代码改变世界

FFMpeg笔记(二) 使用FFmpeg对视频进行编解码的一般流程

2017-03-05 18:18  jiayayao  阅读(3347)  评论(0编辑  收藏  举报

 1. 编码:

1.对编码资源的初始化

   AVCodec*                m_pVideoEncoder;// 特定编码器的参数信息
    AVCodecContext*         m_pVideoEncoderContext;// 设置的编码参数信息
    AVFrame*                m_YUV_Frame;// RGB转换为YUV数据帧以减少传输数据量,减少网络带宽占用
    AVFrame*                m_RGB_Frame;// 获取到的数据帧
    SwsContext*             m_pSwsc;// 保存由YUV转换为RGB的转换参数的结构体
    // 根据给定的编码器ID找到注册过的编码器
    m_pVideoEncoder = avcodec_find_encoder(AV_CODEC_ID_H264);  
    if (!m_pVideoEncoder) 
    {
        assert(0); 
        return false;
    }  
    // 申请一个AVCodecContext结构体,注意使用avcodec_free_context()函数释放
    m_pVideoEncoderContext = avcodec_alloc_context3(m_pVideoEncoder);  
    if(!m_pVideoEncoderContext)
    {
        assert(0);
        return false;
    }

    // 对m_pVideoEncoderContext设置一些参数
    m_pVideoEncoderContext->width = frameWidth;
    m_pVideoEncoderContext->height = frameHeight;
  // ......
  
// 初始化AVCodecContext int err = avcodec_open2(m_pVideoEncoderContext, m_pVideoEncoder,NULL); if ( err < 0) { assert(0); char errorStr[256]; av_strerror(err,errorStr,256); return false; } // 申请AVFrame m_YUV_Frame = av_frame_alloc();   // 获取保留图像拉伸参数的结构体 m_pSwsc = sws_getContext(frameWidth,frameHeight,g_Format,frameWidth,frameHeight,AV_PIX_FMT_YUV420P,SWS_ALGORITHM,NULL,NULL,NULL); if (!m_pSwsc) { assert(0); return false; }
m_RGB_Frame
= av_frame_alloc();

2.编码

        // 将原始数据(RGB格式的)填充到一个RGB的AVFrame中
        avpicture_fill((AVPicture*)m_RGB_Frame, (uint8_t*)rawVideo, g_Format, m_nLastFrameWidth, m_nLastFrameHeight);
        // 将RGB格式的AVFrame转换为YUV格式,以降低传输数据的总量
        sws_scale(m_pSwsc,m_RGB_Frame->data,m_RGB_Frame->linesize,0,m_pVideoEncoderContext->height,m_YUV_Frame->data,m_YUV_Frame->linesize);

        AVPacket packet;
        av_init_packet(&packet);
     int bOutPacketNonEmpty = 0;
        int nRet = avcodec_encode_video2(m_pVideoEncoderContext, &packet, m_YUV_Frame, &bOutPacketNonEmpty); 
     if(nRet < 0)
     {
return false; }
     // 将AVPacket传输
     // ......

2. 解码:

1.对解码资源的初始化

    AVCodec*            m_pVideoDecoder;  
    AVCodecContext*     m_pVideoDecoderContext;
    
    AVPacket            m_recvPacket;
    AVFrame*            m_pYUVFrame;

    SwsContext*         m_pSwsc;// 保存由YUV转换为RGB的转换参数的结构体
    AVFrame*            m_pRGBFrame;// 用于显示
    // 根据数据包的编码格式,找到对应的解码器
   m_pVideoDecoder = avcodec_find_decoder((AVCodecID)codecid); if (!m_pVideoDecoder) { fprintf(stderr, "Codec not found\n"); return false; } m_pVideoDecoderContext = avcodec_alloc_context3(m_pVideoDecoder); int ret = avcodec_open2( m_pVideoDecoderContext, m_pVideoDecoder, NULL); if(ret < 0) { return false; }

2.解码

    av_init_packet(&m_recvPacket);
    m_recvPacket.size = videoPacket.length;
    m_recvPacket.data = videoPacket.pData;

    int got_frame = 0;
    while (m_recvPacket.size)
    {
        int len = avcodec_decode_video2(m_pVideoDecoderContext, m_pYUVFrame, &got_frame, &m_recvPacket);
        if (len < 0) 
        {
return false;
        }
        if (m_recvPacket.data) 
        {
            m_recvPacket.size -= len;
            m_recvPacket.data += len;
        }
    }
    
    if(got_frame == 0)
    {
        return false;
    }
  // 将
m_pYUVFrame转换为RGBFrame用于显示
  // ......