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