android - 使用 ffmpeg api 转换音频文件。 avcodec_encode_audio2 崩溃

标签 android audio android-ndk ffmpeg

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

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

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

我对此的问题是:

  • 我可以期待通过调用其中一个解码器函数 f.e. 检索到的帧吗?
    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;
    }
    

    最佳答案

    与此同时,我已经弄清楚了这一点并编写了一个 Android Library Project 来做到这一点
    (用于音频文件)。 https://github.com/fscz/FFmpeg-Android

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

    关于android - 使用 ffmpeg api 转换音频文件。 avcodec_encode_audio2 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18420383/

    相关文章:

    android - 在Android.mk中使用Make的 'wildcard'函数

    AndroidPlot : setting the labels on the X-axis

    android - 无法在 Xamarin Studio 中加载 Main.axml

    audio - 如何用Lua打开wav文件

    java - 是否可以实现安全应用程序来阻止 Android 上漫游时的互联网?

    android - 将msvc代码移植到Android/ios

    android - 从第一个编辑文本到第二个编辑文本,输入掩码不起作用

    android - 如何在 Android 中获取当前日期和时间?

    iphone - AVAudioPlayer使用audioPlayerDecodeErrorDidOccur和NSOSStatusErrorDomain -50中断播放

    html - htm音频无法在手机上播放