基於FFmpeg的視頻軟解
阿新 • • 發佈:2019-01-21
lena iobuffer guess ecc file 移動 上下 ostream text
首先需要創建一個AVFormatContext對象,其包含了很多視頻的基本信息;
AVFormatContext* m_pFmtCtx; m_pFmtCtx = avformat_alloc_context();
打開視頻源,可以通過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);
查找視頻流
// 解析數據流信息 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];
初始化解碼器上下文
// 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);
獲取視頻幀率(可選,rtsp不需要)
m_pDecoderCtx->framerate = av_guess_frame_rate(m_pFmtCtx, m_pVideoStream, NULL);
循環解碼
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的視頻軟解