Skip to content

Commit

Permalink
音声エンコード
Browse files Browse the repository at this point in the history
  • Loading branch information
nekopanda committed Sep 8, 2019
1 parent 7772faf commit eebf180
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 0 deletions.
34 changes: 34 additions & 0 deletions Amatsukaze/AmatsukazeCLI.hpp
Expand Up @@ -43,6 +43,11 @@ static void printHelp(const tchar* bin) {
" -bcm|--bitrate-cm <float> CM判定されたところのビットレート倍率\n"
" --2pass 2passエンコード\n"
" --splitsub メイン以外のフォーマットは結合しない\n"
" -aet|--audio-encoder-type <タイプ> 音声エンコーダ[]"
" 対応エンコーダ: neroAac, qaac, fdkaac\n"
" 指定しなければ音声はエンコードしない\n"
" -aet|--audio-encoder <パス> 音声エンコーダ[]"
" -aeo|--audio-encoder-option <オプション> 音声エンコーダへ渡すオプション[]\n"
" -fmt|--format <フォーマット> 出力フォーマット[mp4]\n"
" 対応フォーマット: mp4,mkv,m2ts,ts\n"
" -m|--muxer <パス> L-SMASHのmuxerまたはmkvmergeまたはtsMuxeRへのパス[muxer.exe]\n"
Expand Down Expand Up @@ -130,6 +135,19 @@ static ENUM_ENCODER encoderFtomString(const tstring& str) {
return (ENUM_ENCODER)-1;
}

static ENUM_AUDIO_ENCODER audioEncoderFtomString(const tstring& str) {
if (str == _T("neroAac")) {
return AUDIO_ENCODER_NEROAAC;
}
else if (str == _T("qaac")) {
return AUDIO_ENCODER_QAAC;
}
else if (str == _T("fdkaac")) {
return AUDIO_ENCODER_FDKAAC;
}
return (ENUM_AUDIO_ENCODER)-1;
}

static DECODER_TYPE decoderFromString(const tstring& str) {
if (str == _T("default")) {
return DECODER_DEFAULT;
Expand Down Expand Up @@ -207,6 +225,22 @@ static std::unique_ptr<ConfigWrapper> parseArgs(AMTContext& ctx, int argc, const
else if (key == _T("-eo") || key == _T("--encoder-option")) {
conf.encoderOptions = getParam(argc, argv, i++);
}
else if (key == _T("-aet") || key == _T("--audio-encoder-type")) {
tstring arg = getParam(argc, argv, i++);
conf.audioEncoder = audioEncoderFtomString(arg);
if (conf.audioEncoder == (ENUM_AUDIO_ENCODER)-1) {
PRINTF("--audio-encoder-typeの指定が間違っています: %" PRITSTR "\n", arg.c_str());
}
}
else if (key == _T("-ae") || key == _T("--audio-encoder")) {
conf.encoderPath = pathNormalize(getParam(argc, argv, i++));
}
else if (key == _T("-aeo") || key == _T("--audio-encoder-option")) {
conf.encoderOptions = getParam(argc, argv, i++);
}
else if (key == _T("-ab") || key == _T("--audio-bitrate")) {
conf.audioBitrateInKbps = std::stoi(getParam(argc, argv, i++));
}
else if (key == _T("-b") || key == _T("--bitrate")) {
const auto arg = getParam(argc, argv, i++);
int ret = sscanfT(arg.c_str(), _T("%lf:%lf:%lf:%lf"),
Expand Down
102 changes: 102 additions & 0 deletions Amatsukaze/AudioEncoder.hpp
@@ -0,0 +1,102 @@
#pragma once

#include <stdint.h>

#include "ProcessThread.hpp"
#include "StreamReform.hpp"

namespace wave {

struct Header
{
int8_t chunkID[4]; //"RIFF" = 0x46464952
uint32_t chunkSize; //28 [+ sizeof(wExtraFormatBytes) + wExtraFormatBytes] + sum(sizeof(chunk.id) + sizeof(chunk.size) + chunk.size)
int8_t format[4]; //"WAVE" = 0x45564157
int8_t subchunk1ID[4]; //"fmt " = 0x20746D66
uint32_t subchunk1Size; //16 [+ sizeof(wExtraFormatBytes) + wExtraFormatBytes]
uint16_t audioFormat;
uint16_t numChannels;
uint32_t sampleRate;
uint32_t byteRate;
uint16_t blockAlign;
uint16_t bitsPerSample;
int8_t subchunk2ID[4];
uint32_t subchunk2Size;
};

void set4(int8_t dst[4], const char* src) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
}

} // namespace wave {

void EncodeAudio(AMTContext& ctx, const tstring& encoder_args,
const tstring& audiopath, const AudioFormat& afmt,
const std::vector<FilterAudioFrame>& audioFrames)
{
using namespace wave;

auto process = std::unique_ptr<StdRedirectedSubProcess>(
new StdRedirectedSubProcess(encoder_args, 5));

int nchannels = 2;
int bytesPerSample = 2;
Header header;
set4(header.chunkID, "RIFF");
header.chunkSize = 0; // サイズ未定
set4(header.format, "WAVE");
set4(header.subchunk1ID, "fmt ");
header.subchunk1Size = 16;
header.audioFormat = 1;
header.numChannels = nchannels;
header.sampleRate = afmt.sampleRate;
header.byteRate = afmt.sampleRate * bytesPerSample * nchannels;
header.blockAlign = bytesPerSample * nchannels;
header.bitsPerSample = bytesPerSample * 8;
set4(header.subchunk2ID, "data");
header.subchunk2Size = 0; // サイズ未定

process->write(MemoryChunk((uint8_t*)&header, sizeof(header)));

int audioSamplesPerFrame = 1024;
// waveLengthはゼロのこともあるので注意
for (int i = 0; i < (int)audioFrames.size(); ++i) {
if (audioFrames[i].waveLength != 0) {
audioSamplesPerFrame = audioFrames[i].waveLength / 4; // 16bitステレオ前提
break;
}
}

File srcFile(audiopath, _T("rb"));
AutoBuffer buffer;
int frameWaveLength = audioSamplesPerFrame * bytesPerSample * nchannels;

for (size_t i = 0; i < audioFrames.size(); ++i) {
MemoryChunk mc = buffer.space(frameWaveLength);
if (audioFrames[i].waveLength != 0) {
// waveがあるなら読む
srcFile.seek(audioFrames[i].waveOffset, SEEK_SET);
srcFile.read(mc);
}
else {
// ない場合はゼロ埋めする
memset(mc.data, 0x00, mc.length);
}
process->write(mc);
}

process->finishWrite();
int ret = process->join();
if (ret != 0) {
ctx.error("↓↓↓↓↓↓音声エンコーダ最後の出力↓↓↓↓↓↓");
for (auto v : process->getLastLines()) {
v.push_back(0); // null terminate
ctx.errorF("%s", v.data());
}
ctx.error("↑↑↑↑↑↑音声エンコーダ最後の出力↑↑↑↑↑↑");
THROWF(RuntimeException, "音声エンコーダ終了コード: 0x%x", ret);
}
}
9 changes: 9 additions & 0 deletions Amatsukaze/CoreUtils.hpp
Expand Up @@ -10,6 +10,7 @@
#include "common.h"

#include <string>
#include <io.h>

#define AMT_MAX_PATH 512

Expand Down Expand Up @@ -265,6 +266,14 @@ class File : NonCopyable
~File() {
fclose(fp_);
}
void setLowPriority() {
FILE_IO_PRIORITY_HINT_INFO priorityHint;
priorityHint.PriorityHint = IoPriorityHintLow;
if (!SetFileInformationByHandle((HANDLE)_get_osfhandle(_fileno(fp_)),
FileIoPriorityHintInfo, &priorityHint, sizeof(priorityHint))) {
THROWF(IOException, "failed to set io priority: %s", GetFullPath(path_));
}
}
void write(MemoryChunk mc) const {
if (mc.length == 0) return;
if (fwrite(mc.data, mc.length, 1, fp_) != 1) {
Expand Down
1 change: 1 addition & 0 deletions Amatsukaze/TranscodeManager.hpp
Expand Up @@ -80,6 +80,7 @@ class AMTSplitter : public TsSplitter {
void open(const tstring& path) {
totalIntVideoSize_ = 0;
file_ = std::unique_ptr<File>(new File(path, _T("wb")));
file_->setLowPriority();
}
void close() {
file_ = nullptr;
Expand Down
63 changes: 63 additions & 0 deletions Amatsukaze/TranscodeSetting.hpp
Expand Up @@ -194,6 +194,49 @@ static tstring makeEncoderArgs(
return sb.str();
}

enum ENUM_AUDIO_ENCODER {
AUDIO_ENCODER_NEROAAC,
AUDIO_ENCODER_QAAC,
AUDIO_ENCODER_FDKAAC,
};

static tstring makeAudioEncoderArgs(
ENUM_AUDIO_ENCODER encoder,
const tstring& options,
int kbps,
const tstring& outpath)
{
StringBuilderT sb;

sb.append(_T("%s "), options);

if (kbps) {
switch (encoder) {
case AUDIO_ENCODER_NEROAAC:
sb.append(_T("-br %d "), kbps * 1000);
break;
case AUDIO_ENCODER_QAAC:
sb.append(_T("-a %d "), kbps * 1000);
break;
case AUDIO_ENCODER_FDKAAC:
sb.append(_T("-b %d "), kbps * 1000);
break;
}
}

switch (encoder) {
case AUDIO_ENCODER_NEROAAC:
sb.append(_T("-if - -of %s"), outpath);
break;
case AUDIO_ENCODER_QAAC:
case AUDIO_ENCODER_FDKAAC:
sb.append(_T("-o %s -"), outpath);
break;
}

return sb.str();
}

static std::vector<std::pair<tstring, bool>> makeMuxerArgs(
ENUM_FORMAT format,
const tstring& binpath,
Expand Down Expand Up @@ -454,6 +497,9 @@ struct Config {
ENUM_ENCODER encoder;
tstring encoderPath;
tstring encoderOptions;
ENUM_AUDIO_ENCODER audioEncoder;
tstring audioEncoderPath;
tstring audioEncoderOptions;
tstring muxerPath;
tstring timelineditorPath;
tstring mp4boxPath;
Expand All @@ -473,6 +519,7 @@ struct Config {
double x265TimeFactor;
int serviceId;
DecoderSetting decoderSetting;
int audioBitrateInKbps;
int numEncodeBufferFrames;
// CM解析用設定
std::vector<tstring> logoPath;
Expand Down Expand Up @@ -563,6 +610,18 @@ class ConfigWrapper : public AMTObject
return conf.encoderOptions;
}

ENUM_AUDIO_ENCODER getAudioEncoder() const {
return conf.audioEncoder;
}

tstring getAudioEncoderPath() const {
return conf.audioEncoderPath;
}

tstring getAudioEncoderOptions() const {
return conf.audioEncoderOptions;
}

ENUM_FORMAT getFormat() const {
return conf.format;
}
Expand Down Expand Up @@ -647,6 +706,10 @@ class ConfigWrapper : public AMTObject
return conf.decoderSetting;
}

int getAudioBitrateInKbps() const {
return conf.audioBitrateInKbps;
}

int getNumEncodeBufferFrames() const {
return conf.numEncodeBufferFrames;
}
Expand Down

0 comments on commit eebf180

Please sign in to comment.