码迷,mamicode.com
首页 > 其他好文 > 详细

基于FFmpeg的视频软解

时间:2019-01-21 16:00:30      阅读:284      评论:0      收藏:0      [点我收藏+]

标签:input   avd   设置   form   查找   sub   void   情况   第一个   

  1. 首先需要创建一个AVFormatContext对象,其包含了很多视频的基本信息;

    AVFormatContext* m_pFmtCtx;
    m_pFmtCtx = avformat_alloc_context();
  2. 打开视频源,可以通过rtsp协议,也可以直接打开本地视频文件,或者读取内存中的数据。

    通过rtsp协议:

    // 主码流
    const char * rtsp = "rtsp://admin:密码@视频源IP地址:554/h264/ch1/main/av_stream";
    // 子码流
    //const char * rtsp = "rtsp://admin:密码@视频源IP地址:554/h264/ch1/sub/av_stream";
    
    AVDictionary* options = NULL;
    av_dict_set(&options, "stimeout", "20000", 0);       // 连接超时
    av_dict_set(&options, "rtsp_transport", "tcp", 0);   // 设置tcp连接,默认为udp,在网络环境不好的情况下可能会丢包
    
    // 打开视频源
    avformat_open_input(&m_pFmtCtx, rtsp, NULL, &options);

    打开本地文件:

    const char * fileName = "C://localfile.mp4";
    
    // 打开视频源
    avformat_open_input(&m_pFmtCtx, fileName, NULL, NULL);

    读取内存中的数据:

    unsigned char * pIOBuffer = (unsigned char *)av_malloc(32768);   // 其它大小也是可行的
    
    // 第一个参数是为AVIOContext申请的内存地址
    // 第二个参数是每次读取数据的大小,如无要求一般设为4kb
    // 第三个参数是buffer是否可写
    // 第四个参数是refilling(填写)buffer数据回调函数
    // 第五个参数是将buffer写入磁盘的回调函数
    // 第六个参数是移动读写指针的位置回调函数
    AVIOContext * pAVIO = avio_alloc_context(pIOBuffer, 32768, 0, NULL, ReadData, NULL, NULL);
    
    m_pFmtCtx->pb = pAVIO;
    // 打开视频源
    avformat_open_input(&m_pFmtCtx, "", NULL, NULL);
  3. 查找视频流

    // 解析数据流信息
    avformat_find_stream_info(m_pFmtCtx, NULL);
    // 查找视频流
    // AVCodec * m_pDecoder; // 解码器
    int m_videoIndex = av_find_best_stream(m_pFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &m_pDecoder, 0);
    
    // AVStream * m_pVideoStream; // 视频流
    m_pVideoStream = m_pFmtCtx->streams[m_videoIndex];
  4. 初始化解码器上下文

    // AVCodecContext * m_pDecoderCtx;
    m_pDecoderCtx = avcodec_alloc_context3(m_pDecoder);
    // 初始化
    avcodec_parameters_to_context(m_pDecoderCtx, m_pVideoStream->codecpar);
    // 打开解码器
    avcodec_open2(m_pDecoderCtx, m_pDecoder, NULL);
  5. 获取视频帧率(可选,rtsp不需要)

    m_pDecoderCtx->framerate = av_guess_frame_rate(m_pFmtCtx, m_pVideoStream, NULL);
  6. 循环解码

    AVPacket packet = { 0 };
    while (av_read_frame(m_pFmtCtx, &packet) >= 0)
    {
     if (m_videoIndex == packet.stream_index)
        {
            Decode(m_pDecoderCtx, &packet);  
            av_packet_unref(&packet);
        }
    }
    
    packet.data = NULL;
    packet.size = 0;
    
    // 清空buffer里的残留
    Decode(m_pDecoderCtx, &packet);
    av_packet_unref(&packet);
    
    void Decode(AVCodecContext * pDecodeCtx, AVPacket * pPacket)
    {
     if (avcodec_send_packet(pDecodeCtx, pPacket) < 0)
     {
         return;
     }
    
     while (TRUE)
     {
         if (avcodec_receive_frame(pDecodeCtx, m_pFrame) != 0)
         {
             break;
         }
         // 解码完成
     }
    }

基于FFmpeg的视频软解

标签:input   avd   设置   form   查找   sub   void   情况   第一个   

原文地址:https://www.cnblogs.com/huluwa508/p/10298210.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!