FFmpeg学习1:视频解码
在視頻解碼前,先了解以下幾個基本的概念:
- 編解碼器(CODEC):能夠進行視頻和音頻壓縮(CO)與解壓縮(DEC),是視頻編解碼的核心部分。
- 容器/多媒體文件(Container/File):沒有了解視頻的編解碼之前,總是錯誤的認為平常下載的電影的文件的后綴(avi,mkv,rmvb等)就是視頻的編碼方式。事實上,剛才提到的幾種文件的后綴
并不是視頻的編碼方式,只是其封裝的方式。一個視頻文件通常有視頻數據、音頻數據以及字幕等,封裝的格式決定這些數據在文件中是如何的存放的,封裝在一起音頻、視頻等數據組成的多媒體文件,也可以叫做容器(其中包含了視音頻數據)。所以,只看多媒體文件的后綴名是難以知道視音頻的編碼方式的。 - 流數據 Stream,例如視頻流(Video Stream),音頻流(Audio Stream)。流中的數據元素被稱為幀Frame。
FFmpeg視頻解碼過程
通常來說,FFmpeg的視頻解碼過程有以下幾個步驟:
解碼過程的具體說明
1. 注冊
av_register_all該函數注冊支持的所有的文件格式(容器)及其對應的CODEC,只需要調用一次,故一般放在main函數中。也可以注冊某個特定的容器格式,但通常來說不需要這么做。
2. 打開文件
avformat_open_input該函數讀取文件的頭信息,并將其信息保存到AVFormatContext結構體中。其調用如下
AVFormatContext* pFormatCtx = nullptr; avformat_open_input(&pFormatCtx, filenName, nullptr, nullptr)第一個參數是AVFormatContext結構體的指針,第二個參數為文件路徑;第三個參數用來設定輸入文件的格式,如果設為null,將自動檢測文件格式;第四個參數用來填充AVFormatContext一些字段以及Demuxer的private選項。
AVFormatContext包含有較多的碼流信息參數,通常由avformat_open_input創建并填充關鍵字段。
3. 獲取必要的CODEC參數
avformat_open_input通過解析多媒體文件或流的頭信息及其他的輔助數據,能夠獲取到足夠多的關于文件、流和CODEC的信息,并將這些信息填充到AVFormatContext結構體中。但任何一種多媒體格式(容器)提供的信息都是有限的,而且不同的多媒體制作軟件對頭信息的設置也不盡相同,在制作多媒體文件的時候難免會引入一些錯誤。也就是說,僅僅通過avformat_open_input并不能保證能夠獲取所需要的信息,所以一般要使用
avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)avformat_find_stream_info主要用來獲取必要的CODEC參數,設置到ic->streams[i]->codec。
在解碼的過程中,首先要獲取到各個stream所對應的CODEC類型和id,CODEC的類型和id是兩個枚舉值,其定義如下:
通常,如果多媒體文件具有完整而正確的頭信息,通過avformat_open_input即可用獲得這兩個參數。
4. 打開解碼器
經過上面的步驟,已經將文件格式信息讀取到了AVFormatContext中,要打開流數據相應的CODEC需要經過下面幾個步驟
- 找到視頻流 video stream
一個多媒體文件包含有多個原始流,例如 movie.mkv這個多媒體文件可能包含下面的流數據 - 原始流 1 h.264 video
- 原始流 2 aac audio for Chinese
- 原始流 3 aac audio for English
- 原始流 4 Chinese Subtitle
- 原始流 5 English Subtitle
要解碼視頻,首先要在AVFormatContext包含的多個流中找到CODEC類型為AVMEDIA_TYPE_VIDEO,代碼如下:
//查找視頻流 video streamint videoStream = -1;for (int i = 0; i < pFormatCtx->nb_streams; i++){if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){videoStream = i;break;}}if (videoStream == -1)return -1; // 沒有找到視頻流video stream結構體AVFormatContext中的streams字段是一個AVStream指針的數組,包含了文件所有流的描述,上述上述代碼在該數組中查找CODEC類型為
AVMEDIA_TYPE_VIDEO的流的下標。
- 根據codec_id找到相應的CODEC,并打開
結構體AVCodecContext描述了CODEC上下文,包含了眾多CODEC所需要的參數信息。
上述代碼,首先通過codec_id找到相應的CODEC,然后調用avcodec_open2打開相應的CODEC。
5. 讀取數據幀并解碼
已經有了相應的解碼器,下面的工作就是將數據從流中讀出,并解碼為沒有壓縮的原始數據
AVPacket packet; while (av_read_frame(pFormatCtx, &packet) >= 0) {if (packet.stream_index == videoStream){int frameFinished = 0;avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);if (frameFinished){doSomething();}}}上述代碼調用av_read_frame將數據從流中讀取數據到packet中,并調用avcodec_decode_video2對讀取的數據進行解碼。
6. 關閉
需要關閉avformat_open_input打開的輸入流,avcodec_open2打開的CODEC
avcodec_close(pCodecCtxOrg);avformat_close_input(&pFormatCtx);補充
在配置好FFmpeg的開發環境后,在C++中使用FFmpeg的庫函數,會出現解析不出函數的名稱鏈接錯誤,這是由于FFmpeg庫是C語言實現,要在C++調用C函數需要 extern "C"的聲明。
extern "C" {# include <libavcodec\avcodec.h># include <libavformat\avformat.h># include <libswscale\swscale.h> }哎,博客園的Markdown用著好不方便啊,不知道怎么畫流程圖....
代碼 FFmpeg0.cpp
轉載于:https://www.cnblogs.com/wangguchangqing/p/5734998.html
總結
以上是生活随笔為你收集整理的FFmpeg学习1:视频解码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Protobuf] Mac系统下安装配
- 下一篇: Vim 安装 YouCompleteMe