如何在libavcodec中将音频帧从输入.mp4传递到输出.mp4?

如何在libavcodec中将音频帧从输入.mp4传递到输出.mp4?,c,audio,ffmpeg,encoding,libavcodec,C,Audio,Ffmpeg,Encoding,Libavcodec,我有一个项目可以正确地打开.mp4,提取视频帧,修改它们,并将修改后的帧转储到输出.mp4。除了音频的编写,一切都正常(大部分情况下——我有一个随机弹出的视频计时错误,但我会杀死它)。我根本不想修改音频通道-我只想将输入.mp4中的音频不经更改地传递到输出.mp4 这里有太多的代码来提供一个工作示例,这主要是因为其中有很多OpenGL和GLSL,但最重要的是我在哪里推进了一个框架。此方法在循环中调用,如果帧是视频帧,则循环将图像数据发送到渲染硬件,对其执行一系列GL魔术,然后写出一帧视频。如果帧

我有一个项目可以正确地打开.mp4,提取视频帧,修改它们,并将修改后的帧转储到输出.mp4。除了音频的编写,一切都正常(大部分情况下——我有一个随机弹出的视频计时错误,但我会杀死它)。我根本不想修改音频通道-我只想将输入.mp4中的音频不经更改地传递到输出.mp4

这里有太多的代码来提供一个工作示例,这主要是因为其中有很多OpenGL和GLSL,但最重要的是我在哪里推进了一个框架。此方法在循环中调用,如果帧是视频帧,则循环将图像数据发送到渲染硬件,对其执行一系列GL魔术,然后写出一帧视频。如果帧是音频帧,则循环不执行任何操作,但是
advanced\u frame()
方法应该只将该帧转储到输出mp4。我不知道libavcodec提供了什么可以做到这一点

注意,在这里,我将音频数据包解码为帧,但这不是必需的。我更愿意处理数据包,而不是为了解码而浪费CPU时间。(我试过另一种方法,但这是我在尝试解码数据,然后重新编码以创建输出流时得到的结果。)我只需要一种方法将数据包从输入传递到输出

bool MediaContainerMgr::advance_frame() {
    int ret; // Crappy naming, but I'm using ffmpeg's name for it.
    while (true) {
        ret = av_read_frame(m_format_context, m_packet);
        if (ret < 0) {
            // Do we actually need to unref the packet if it failed?
            av_packet_unref(m_packet);
            if (ret == AVERROR_EOF) {
                finalize_output();
                return false;
            }
            continue;
            //return false;
        }
        else {
            int response = decode_packet();
            if (response != 0) {
                continue;
            }
            // If this was an audio packet, the image renderer doesn't care about it - just push
            // the audio data to the output .mp4:
            if (m_packet->stream_index == m_audio_stream_index) {
                printf("m_packet->stream_index: %d\n", m_packet->stream_index);
                printf("  m_packet->pts: %lld\n", m_packet->pts);
                printf("  mpacket->size: %d\n", m_packet->size);
                // m_recording is true if we're writing a .mp4, as opposed to just letting OpenGL
                // display the frames onscreen.
                if (m_recording) {
                    int err = 0;
                    // I've tried everything I can find to try to push the audio frame to the
                    // output .mp4. This doesn't work, but neither do a half-dozen other libavcodec
                    // methods:
                    err = avcodec_send_frame(m_output_audio_codec_context, m_last_audio_frame);

                    if (err) {
                        printf("  encoding error: %d\n", err);
                    }
                }
            }
            av_packet_unref(m_packet);
            if (m_packet->stream_index == m_video_stream_index) {
                return true;
            }
        }
    }
}
如有必要,我可以为所有上下文提供设置,但为了简洁起见,我们可以使用
av\u dump\u格式(m\u output\u format\u context,0,filename,1)
显示:

Output #0, mp4, to 'D:\yodeling_monkey_nuggets.mp4':
  Metadata:
    encoder         : Lavf58.64.100
    Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv420p, 1920x1080, q=-1--1, 20305 kb/s, 29.97 fps, 30k tbn
    Stream #0:1: Audio: aac (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 125 kb/s
若要将音频AVPacket“按原样”放入输出,而无需执行解码-编码步骤,则应使用该函数来处理此类数据包,而不是使用。请注意,这些函数使用不同的上下文:
AVFormatContext
AVCodecContext

avcodec\u send\u frame
向编码器提供原始视频或音频帧


av\u write\u frame
将数据包直接传递给muxer

是否可以使用或重新创建副本过滤器?这看起来不是一个完整的例子。它看起来像是复制了上下文(实际上,这是一个很好的发现-谢谢),但仍然缺少最后的细节-如何将输入数据包发送到输出上下文。奇怪的是,我已经找到了很多与此相近的例子,但它们都非常古老,不能与当前的库一起使用。我会尝试一下,但我不能说必须更改上下文类型令人激动。为什么不同?为什么缺少兼容的接口?是否可以从
AVCodecContext
获取
AVFormatContext
,或者我必须经历一个完全不同的创建和绑定到输出容器的循环?AVCodecContext和AVFormatContext在不同的媒体工作层上使用不同的东西。使用文件/流时使用AVFormatContext,使用编码器/编码器时使用AVCodeContext。我认为,当您将媒体流写入输出时,您的代码中已经有了AVFormatContext。搜索它并用它来写音频包,
Output #0, mp4, to 'D:\yodeling_monkey_nuggets.mp4':
  Metadata:
    encoder         : Lavf58.64.100
    Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv420p, 1920x1080, q=-1--1, 20305 kb/s, 29.97 fps, 30k tbn
    Stream #0:1: Audio: aac (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 125 kb/s