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

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

我有一个项目可以正确打开 .mp4、提取视频帧、修改它们并将修改后的帧转储到输出 .mp4。一切正常(主要是 - 我有一个随机弹出的视频定时错误,但我会杀死它)除了音频的编写。我根本不想修改音频通道 - 我只想将输入 .mp4 中的音频原封不动地传递到输出 .mp4。

这里的代码太多,无法提供一个工作示例,主要是因为那里有很多 OpenGL 和 GLSL,但最重要的部分是我推进帧的地方。这个方法在循环中被调用,如果帧是一个视频帧,循环将图像数据发送到渲染硬件,在它上面做一堆 GL 魔术,然后写出一帧视频。如果该帧是音频帧,则循环不执行任何操作,但 advance_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;
            }
        }
    }
}

advance_frame() 的主力是 decode_packet()。所有这些都非常适用于视频数据:

int MediaContainerMgr::decode_packet() {
    // Supply raw packet data as input to a decoder
    // https://ffmpeg.org/doxygen/trunk/group__lavc__decoding.html#ga58bc4bf1e0ac59e27362597e467efff3
    int             response;
    AVCodecContext* codec_context = nullptr;
    AVFrame*        frame         = nullptr;

    if (m_packet->stream_index == m_video_stream_index) {
        codec_context = m_video_input_codec_context;
        frame = m_last_video_frame;
    }
    if (m_packet->stream_index == m_audio_stream_index) {
        codec_context = m_audio_input_codec_context;
        frame = m_last_audio_frame;
    }

    if (codec_context == nullptr) {
        return -1;
    }

    response = avcodec_send_packet(codec_context,m_packet);
    if (response < 0) {
        char buf[256];
        av_strerror(response,buf,256);
        printf("Error while receiving a frame from the decoder: %s\n",buf);
        return response;
    }

    // Return decoded output data (into a frame) from a decoder
    // https://ffmpeg.org/doxygen/trunk/group__lavc__decoding.html#ga11e6542c4e66d3028668788a1a74217c
    response = avcodec_receive_frame(codec_context,frame);
    if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
        return response;
    } else if (response < 0) {
        char buf[256];
        av_strerror(response,buf);
        return response;
    } else {
        printf(
            "Stream %d,Frame %d (type=%c,size=%d bytes),pts %lld,key_frame %d,[DTS %d]\n",m_packet->stream_index,codec_context->frame_number,av_get_picture_type_char(frame->pict_type),frame->pkt_size,frame->pts,frame->key_frame,frame->coded_picture_number
        );
    }
    return 0;
}

如有必要,我可以提供所有上下文的设置,但为简洁起见,我们可能会忽略 av_dump_format(m_output_format_context,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 “原样”放入输出,您应该对此类数据包使用 av_write_frame 函数而不是 avcodec_send_frame。请注意,这些函数使用不同的上下文:AVFormatContextAVCodecContext

avcodec_send_frame 向编码器提供原始视频或音频帧

av_write_frame 将数据包直接传递给复用器

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?