FFMPEG保存H264流到AVI文件中形成录像


研究了使用FFMPEG保存H264流到AVI文件中形成录像的方法,下面是大致流程。

使用的FFMPEG版本   ffmpeg-2.6.9。然后我静态编译后使用的静态库,至于怎么静态编译看我之前的文章。

同时这个H264写入AVI的方法我这也有封装好的类。在文章最后提供。

1.变量定义
    // 输出格式
    AVOutputFormat *m_outFormat;
    // 输出内容对象
    AVFormatContext *m_FormatContext;
    // 视频流对象
    AVStream *m_AVStream;
    // pts
    double video_pts;

2.分配输出内容对象
    注意最后一个参数为文件的文件名(带路径)倒数第二个是文件格式这里这“avi”
    avformat_alloc_output_context2(m_FormatContext, NULL, “avi”,"1.avi");
    
3. 保存输出格式
   m_outFormat = m_FormatContext->oformat;
   
4.添加视频流
  m_AVStream = avformat_new_stream(m_FormatContext, 0);
  如果失败了别忘了释放,否则有内存泄漏
  // 释放分配的文本
  avformat_free_context(m_FormatContext);
  
5.
    填入视频的参数
    AVCodecContext *c = m_AVStream->codec;
    c->codec_id = AV_CODEC_ID_H264;//因为这里使用的是H264流,如果是其他的例如JPEG就修改成相应的参数
    c->codec_type = AVMEDIA_TYPE_VIDEO;
    //填入你视频的宽高
    c->width = 1920;
    c->height = 1080;
    //填入帧率
    c->time_base.den = 20;
    c->time_base.num = 1;
    c = NULL;
    
6.输出信息
  av_dump_format(m_FormatContext, 0, "1.avi", 1);
 
7.打开输出文件
    avio_open(&m_FormatContext->pb, "1.avi", AVIO_FLAG_READ_WRITE);
    
    失败的话别忘了释放文本
    avformat_free_context(this->m_FormatContext);
    
8.  写文件头
    avformat_write_header(m_FormatContext,NULL);
    
9 然后就开始正式的写入数据了
  a>你首先假设获取到了流数据存储到了buf里面吧
  b>计算PTS
   video_pts = (double)m_AVStream->pts.val * m_AVStream->time_base.num / m_AVStream->time_base.den;
  c>写数据
          AVPacket pkt;
        av_init_packet(&pkt);
        然后检索到H264的开始位和关键帧校验(00 00 00 01 65或者00 00 01 65),这个主要是关键帧的开始位前面有一些附加数据需要特殊处理一下。
        如果找到了那么就进行操作d否则进行操作e
    d> 获取开始位之前的数据长度比如你的数据00 00 00 01是从第51个字节开始的那么你获取到的这个长度应该是50将这个值我们设定为X吧,这个部分的数据是额外数据。
       额外数据大小赋值
       m_AVStream->codec->extradata_size = X;
       额外数据分配内存,这个不用每次分配,因为指针存在m_AVStream里面我们下次还能用所以加上if的判断。记住一定要加上FF_INPUT_BUFFER_PADDING_SIZE这个长度。
       FFMPEG里面说是有的解码器会一次读取32个字节或者64字节的数据长度如果不加的话就越界了。那么的话就有可能会崩溃例
           if (m_AVStream->codec->extradata == NULL)
        {
            m_AVStream->codec->extradata = (uint8_t*)malloc(this->m_AVStream->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
        }
        将数据拷贝到内存里面
        memcpy(m_AVStream->codec->extradata, &buf[0], X);
        然后清空后面的数据,因为如果不清空有的解码器会崩溃入力MPEG
        memset(&m_AVStream->codec->extradata[X], 0, FF_INPUT_BUFFER_PADDING_SIZE);
    e>    写入数据    
        pkt.stream_index = m_AVStream->index;
        pkt.data = (uint8_t *)buf;
        pkt.size = len;//这个数数据长度
        av_interleaved_write_frame(m_FormatContext, &pkt);
    f>好了这就是一帧数据写完了,如果收到下一帧数据那么就重新从a开始
    
10到这里就应该是想停止录像了那么需要进行如下操作
  写尾部信息
  av_write_trailer(m_FormatContext);
  释放用过的结构体
      if (m_AVStream->codec->extradata != NULL)
    {
        free(m_AVStream->codec->extradata);
        m_AVStream->codec->extradata = NULL;
        m_AVStream->codec->extradata_size = 0;
    }
     关闭输出文件
    if (!(m_outFormat->flags & AVFMT_NOFILE)) 
    {
        /* close the output file */
        avio_close(m_FormatContext->pb);
        m_FormatContext->pb = NULL;
    } 
     释放文本中的所有内容
    if (NULL != m_FormatContext)
    {
        avformat_free_context(m_FormatContext);
        m_FormatContext = NULL;
    }  
       
11结束。
        
  AVI文件的写类下载:

https://pan.baidu.com/s/1C4p5IqzSKS64L1n9jnm38Q

调用方法

1.OpenNewVideo

2.WriteNewFrame 循环调用

3.CloseNewVideo
  
  

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值