1

从示例中我得到了这段代码的基本思想。但是我不确定我缺少什么,因为 muxing.c demuxing.c 和decode_encoding.c 都使用不同的方法。

将音频文件转换为另一个文件的过程大致如下: inputfile -demux-> audiostream -read-> inPackets -decode2frames-> frames -encode2packets-> outPackets -write-> audiostream -mux-> outputfile

但是我在 demuxing.c 中发现了以下注释: /* 写入第一个平面的原始音频数据样本。这适用
于打包格式(例如 AV_SAMPLE_FMT_S16)。然而,
*大多数音频解码器输出平面音频,它为每个通道使用单独的
*平面音频样本(例如 AV_SAMPLE_FMT_S16P)。
* 换句话说,
在这些情况下,此代码将只写入第一个音频通道 *。
* 您应该使用 libswresample 或 libavfilter 将帧
* 转换为打包数据。*/

我对此的问题是:

  1. 我是否可以期望通过调用解码器函数 fe avcodec_decode_audio4 检索到的帧来保存合适的值以将其直接放入编码器中,或者评论中提到的重采样步骤是强制性的吗?

  2. 我是否采取了正确的方法?ffmpeg 非常不对称,即如果有函数 open_file_for_input,则可能没有函数 open_file_for_output。还有许多函数的不同版本(avcodec_decode_audio[1-4])和不同的命名方案,所以很难判断一般方法是否正确,或者实际上是在不同版本颠簸中使用的技术的丑陋混合ffmpeg。

  3. 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;
}
4

1 回答 1

0

同时,我已经弄清楚了这一点并编写了一个 Android 库项目来执行此操作(用于音频文件)。https://github.com/fscz/FFmpeg-Android

有关详细信息,请参阅文件 /jni/audiodecoder.c

于 2014-02-17T14:30:58.903 回答