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用於顯示
// ......