例から、このコードの基本的なアイデアを得ました。ただし、muxing.c demuxing.c と decode_encoding.c はすべて異なるアプローチを使用しているため、何が欠けているのかわかりません。
オーディオ ファイルを別のファイルに変換するプロセスは、大まかに次のようになります。
しかし、demuxing.c で次のコメントを見つけました。 /* 最初のプレーンの生のオーディオ データ サンプルを書き込みます。これは
* パックされたフォーマット (例えば AV_SAMPLE_FMT_S16) では問題なく動作します。ただし、
ほとんどのオーディオ デコーダは * 平面オーディオを出力します。これは、
各チャンネルのオーディオ サンプルの * 個別のプレーンを使用します (例: AV_SAMPLE_FMT_S16P)。
* 言い換えると、このコードは
、これらの場合に * 最初のオーディオ チャネルのみを書き込みます。
* フレームを圧縮データに変換するには、libswresample または libavfilter を使用する必要があり
ます。*/
これに関する私の質問は次のとおりです。
デコーダー関数の 1 つ fe avcodec_decode_audio4 を呼び出して取得されたフレームが適切な値を保持してエンコーダーに直接配置されることを期待できますか、それともコメントに記載されているリサンプリング手順は必須ですか?
私は正しいアプローチを取っていますか?ffmpeg は非常に非対称です。つまり、関数 open_file_for_input がある場合、関数 open_file_for_output がない可能性があります。また、多くの関数 (avcodec_decode_audio[1-4]) にはさまざまなバージョンがあり、さまざまな命名スキームがあるため、一般的なアプローチが正しいかどうか、または実際にはさまざまなバージョンのバンプで使用された技術の醜い混合物であるかどうかを判断するのは非常に困難です。 ffmpeg。
ffmpeg は、「平面サンプリング」や「パック形式」などの多くの特定の用語を使用しており、これらの用語の定義を見つけるのに苦労しています。オーディオに関する深い知識がなくても、動作するコードを書くことは可能ですか?
これまでの私のコードは avcodec_encode_audio2 でクラッシュし、その理由はわかりません。
int Java_com_fscz_ffmpeg_Audio_convert(JNIEnv * env, jobject this, jstring jformat, jstring jcodec, jstring jsource, jstring jdest) {
jboolean isCopy;
jclass configClass = (*env)->FindClass(env, "com.fscz.ffmpeg.Config");
jfieldID fid = (*env)->GetStaticFieldID(env, configClass, "ffmpeg_logging", "I");
logging = (*env)->GetStaticIntField(env, configClass, fid);
/// open input
const char* sourceFile = (*env)->GetStringUTFChars(env, jsource, &isCopy);
AVFormatContext* pInputCtx;
AVStream* pInputStream;
open_input(sourceFile, &pInputCtx, &pInputStream);
// open output
const char* destFile = (*env)->GetStringUTFChars(env, jdest, &isCopy);
const char* cformat = (*env)->GetStringUTFChars(env, jformat, &isCopy);
const char* ccodec = (*env)->GetStringUTFChars(env, jcodec, &isCopy);
AVFormatContext* pOutputCtx;
AVOutputFormat* pOutputFmt;
AVStream* pOutputStream;
open_output(cformat, ccodec, destFile, &pOutputCtx, &pOutputFmt, &pOutputStream);
/// decode/encode
error = avformat_write_header(pOutputCtx, NULL);
DIE_IF_LESS_ZERO(error, "error writing output stream header to file: %s, error: %s", destFile, e2s(error));
AVFrame* frame = avcodec_alloc_frame();
DIE_IF_UNDEFINED(frame, "Could not allocate audio frame");
frame->pts = 0;
LOGI("allocate packet");
AVPacket pktIn;
AVPacket pktOut;
LOGI("done");
int got_frame, got_packet, len, frame_count = 0;
int64_t processed_time = 0, duration = pInputStream->duration;
while (av_read_frame(pInputCtx, &pktIn) >= 0) {
do {
len = avcodec_decode_audio4(pInputStream->codec, frame, &got_frame, &pktIn);
DIE_IF_LESS_ZERO(len, "Error decoding frame: %s", e2s(len));
if (len < 0) break;
len = FFMIN(len, pktIn.size);
size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample(frame->format);
LOGI("audio_frame n:%d nb_samples:%d pts:%s\n", frame_count++, frame->nb_samples, av_ts2timestr(frame->pts, &(pInputStream->codec->time_base)));
if (got_frame) {
do {
av_init_packet(&pktOut);
pktOut.data = NULL;
pktOut.size = 0;
LOGI("encode frame");
DIE_IF_UNDEFINED(pOutputStream->codec, "no output codec");
DIE_IF_UNDEFINED(frame->nb_samples, "no nb samples");
DIE_IF_UNDEFINED(pOutputStream->codec->internal, "no internal");
LOGI("tests done");
len = avcodec_encode_audio2(pOutputStream->codec, &pktOut, frame, &got_packet);
LOGI("encode done");
DIE_IF_LESS_ZERO(len, "Error (re)encoding frame: %s", e2s(len));
} while (!got_packet);
// write packet;
LOGI("write packet");
/* Write the compressed frame to the media file. */
error = av_interleaved_write_frame(pOutputCtx, &pktOut);
DIE_IF_LESS_ZERO(error, "Error while writing audio frame: %s", e2s(error));
av_free_packet(&pktOut);
}
pktIn.data += len;
pktIn.size -= len;
} while (pktIn.size > 0);
av_free_packet(&pktIn);
}
LOGI("write trailer");
av_write_trailer(pOutputCtx);
LOGI("end");
/// close resources
avcodec_free_frame(&frame);
avcodec_close(pInputStream->codec);
av_free(pInputStream->codec);
avcodec_close(pOutputStream->codec);
av_free(pOutputStream->codec);
avformat_close_input(&pInputCtx);
avformat_free_context(pOutputCtx);
return 0;
}