ffmpeg解析MP4封装的avc1编码问题「建议收藏」

ffmpeg解析MP4封装的avc1编码问题「建议收藏」0、问题  遇到的问题:使用ffmpeg直接读取avc1编码的mp4视频,将读取到的帧写下来(H264码流),播放失败。  原因:ffmpeg解码获取的AVPacket只包含视频压缩数据,并没有包含相关的解码信息(比如:h264的sps,pps头信息),这些解码信息包括编码的profile,level,图像的宽和高,deblock滤波器等。没有这些编码头信息解码器就不能进行解码。1、mp4…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

0、问题

  遇到的问题:使用ffmpeg直接读取avc1编码的mp4视频,将读取到的帧写下来(H264码流),播放失败。
  原因: ffmpeg解码获取的AVPacket只包含视频压缩数据,并没有包含相关的解码信息(比如:h264的sps,pps头信息),这些解码信息包括编码的profile,level,图像的宽和高,deblock滤波器等。没有这些编码头信息解码器就不能进行解码。

1、mp4封装的avc1编码

  mp4封装的avc1编码(不带起始码的H264编码格式)视频如果直接用av_read_frame接口读取然后播放是不能播放成功的。因为读取出来的数据不带PPS/SPS、起始码这三种信息。
必须添加上后才能播放。

sps,pps之后就是I帧的数据起始码为00 00 00 01或00 00 01
在这里插入图片描述

上图中黑框内就是sps和psp数据,蓝色框为起始码(00 00 00 01)及I帧标志码(06 50)

2、SPS,PPS在ffmpeg

  H.264码流的SPS和pps信息存储在AVCidecContext结构体的extradata中,添加这些信息需要使用ffmpeg中名称为”h264_mp4toannexb”的bitstream filter处理。
查看ffmpeg工具支持的Bitstream Filter类型命令

ffmpeg -bsfs

在这里插入图片描述

3、新旧接口

《1》、旧接口

int ParseH264ExtraDataInMp4(int stream_id, AVPacket* packet) 
{
	uint8_t *dummy = NULL; int dummy_size;
	AVBitStreamFilterContext* bsfc = av_bitstream_filter_init("h264_mp4toannexb");
	if (bsfc == NULL) 
	{
        envir() << "cannot open the h264_mp4toannexb\n";
        return -1;
	}

 	av_bitstream_filter_filter(bsfc, format_ctx_->streams[stream_id]->codec,
          NULL, &dummy, &dummy_size, NULL, 0, 0);

    av_bitstream_filter_close(bsfc);
}

旧接口使用时需要特别注意,否则很容易导致内存泄漏。

《2》、新接口

int ParseH264ExtraDataInMp4(int stream_id, AVPacket* packet) 
{
const AVBitStreamFilter * absFilter = NULL;
    AVBSFContext *absCtx = NULL;
    AVCodecParameters *codecpar = NULL;

    absFilter = av_bsf_get_by_name("h264_mp4toannexb");

    //过滤器分配内存   
    av_bsf_alloc(absFilter, &absCtx);

    //添加解码器属性   
    codecpar = format_ctx_->streams[stream_id]->codecpar;
    avcodec_parameters_copy(absCtx->par_in, codecpar);
    absCtx->time_base_in = format_ctx_->streams[stream_id]->time_base;

    //初始化过滤器上下文   
    av_bsf_init(absCtx);

    //AVPacket处理   
    if (av_bsf_send_packet(absCtx, packet) < 0)
    {
        printf("av_bsf_send_packet faile \n");
        av_bsf_free(&absCtx);
        absCtx = NULL;
        return -1;
    }


    if (av_bsf_receive_packet(absCtx, packet) == 0)
    {
        //printf("av_bsf_receive_packet faile \n");
        //av_bsf_free(&absCtx);
        //absCtx = NULL;
        return 0;

    }


    av_bsf_free(&absCtx);
    absCtx = NULL;
}

《3》、使用伪代码

int main()
{
    //ffmpeg的open接口打开MP4封装的avc1码流视频 , AVFormatContext *format_ctx_
    //读取一帧av_read_frame,读取到AVPacket packet中

    if(视频帧)    //只处理视频帧,音频不处理  
    {
      int stream_id = packet->stream_index;
      AVCodecContext *codec = NULL;
      codec = format_ctx_->streams[stream_id]->codec;

        if (codec->codec_id == AV_CODEC_ID_H264) 
        {
            //pps and sps
            //const char start_code[4] = { 0, 0, 0, 1 };
            //memcpy(packet->data, start_code, 4);

            if ((codec->extradata[0] != 0) && 
                (ParseH264ExtraDataInMp4(stream_id, packet) == 0)) 
            {

                has_extra_data = True;

            }

#if 0
            {

                FILE* wfd = fopen("out.h264", "ab+");
                if (wfd)
                {

                    if (has_extra_data)
                    {

                        fwrite(codec->extradata, 1, codec->extradata_size, wfd);
                    }

                    fwrite(packet->data, 1, packet->size, wfd);
                    fflush(wfd);
                    fclose(wfd);
                    wfd = NULL;
                }
            }

#endif
        } 
    }
}

4、参考

《1》、https://www.jianshu.com/p/e5e021ccc980
《2》、https://blogs.gentoo.org/lu_zero/2016/03/21/bitstream-filtering/
《3》、http://www.xuhj.top/2018/06/26/ffmpeg-convert-to-ts-stream/
《4》、https://cloud.tencent.com/developer/article/1333501
《5》、sps/pps数据结构
《6》、avc1余h264区别

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

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181038.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • GridBagConstraints_gridlayout布局怎么用

    GridBagConstraints_gridlayout布局怎么用2019独角兽企业重金招聘Python工程师标准>>>…

  • 首个可用于深度学习的ToF相关数据集!基于置信度的立体相机以及ToF相机深度图融合框架…

    首个可用于深度学习的ToF相关数据集!基于置信度的立体相机以及ToF相机深度图融合框架…点击上方“计算机视觉工坊”,选择“星标”干货第一时间送达作者|cocoon编辑|3D视觉开发者社区目录✦contents1.概述2.方法以及网络结构2.1使用网络学习置信度2.1.1训练细节2.2双目以及ToF视差的fusion3.合成数据4.实验结果4.1测试集场景4.2置信度估计结果4.3视差估计定性以及定量结果5.参考文献附录:数据…

  • C/S与B/S架构的产品进行系统测试的区别

    C/S与B/S架构的产品进行系统测试的区别

  • visifire 控件

    visifire 控件引言Silverlight对于图形图像处理方面,从1.0时代起就给予了很强大的支持,所以我们可以在Silverlight中实现非常棒的各种统计图表,然而现在有了一些开源的项目,使得这项工作更加的简单。本文我将介绍一个开源的项目visifire,使用它可以在Silverlight2中实现超酷的图表。简单图表首先我们需要下载Visifire项目Silverlight开发包,在建立完项…

  • 【教程】Tomcat 的catalina.out 日志按照自定义日期格式进行切割

    本文简单介绍在使用cronolog对tomcat的日志进行自定义日期格式的切割,方便日志的整理和遇到问题日志的排查!安装cronolog安装cronolog的方法网上有很多,这里也简单的介绍一下。1.下载安装包 cronolog-1.6.2.tar.gz2.安装cronolog tar -zxvf cronolog-1.6.2.tar.gz …

  • 解决Ubuntu18.04版本高分辨率下导致字体过小问题

    解决Ubuntu18.04版本高分辨率下导致字体过小问题我所使用的是小米笔记本,显示屏是3.2K的分辨率。由于分辨率太高了,然后在ubuntu18.04的版本下显示的字体很小,小到都看不清了那种。于是查找了调整18.04版本字体大小的方法如下:安装gnome-tweaks工具sudoapt-getinstallgnome-tweaks安装完之后,直接在终端输入gnome-tweaks即可运行该工具。然后调整缩放比例,因为我的电脑分辨率是3.2K,所以我调整的缩放比例是2倍刚刚好,如下图:调整完之后,直接关闭该工具。再次回到ubunt

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号