1. 程式人生 > >ffmpeg3.3新版本AVStream的封裝流引數由codec替換codecpar(解碼)

ffmpeg3.3新版本AVStream的封裝流引數由codec替換codecpar(解碼)

ffmpeg新版本中(封裝流)AVStream的codec引數要被codecpar引數所替代,這樣替代我們要注意什麼,為什麼要替代,我們先來看下ffmpeg的程式碼。 程式碼分析和新引數優勢 typedef struct AVStream { #if FF_API_LAVF_AVCTX /** * @deprecated use the codecpar struct instead */ attribute_deprecated AVCodecContext *codec; #endif 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 /* * Codec parameters associated with this stream. Allocated and freed by
* libavformat in avformat_new_stream() and avformat_free_context() * respectively. * * - demuxing: filled by libavformat on stream creation or in * avformat_find_stream_info() * - muxing: filled by the caller before avformat_write_header() */ AVCodecParameters *codecpar; } 從程式碼中我們可以看出codec引數在58版本及之後就不會支援了,需要由codecpar引數所替代。這樣做的目的我想主要是將編碼和封裝徹底分離,之前封裝和編碼使用的引數都是存放在codec中,這樣的好處是程式碼簡潔,不需要額外給封裝傳遞引數,但壞處是把編碼和封裝的程式碼融合在一塊耦合性較大,有很多需求,我們只需要編碼並不需要做封裝,比如我們做自己的推流協議,直接吧編碼後h264資料通過自定義的協議傳送。
再比如直播推流中我們編碼和封裝推流會在不同的執行緒中處理,如果共用一個上下文肯定還需要處理互斥問題,分開就不會存在這個問題。 既然必須要替換我們如何處理; 比如原來的視訊播放處理方式是這樣(錯誤處理省略): //開啟多媒體檔案,我們假定視訊流索引為0 AVFormatContext *ic = NULL; avformat_open_input(&ic, "test.mp4", 0, 0); //找到視訊解碼器,比如H264   AVCodec *codec = avcodec_find_decoder(ic->streams[0]->codec->codecid);
  //開啟視訊解碼器,開啟音訊解碼器用的也是同一個函式 avcodec_open2(enc, ic->streams[0]->codec, NULL); 看程式碼我們知道avformat_open_input之後音視訊的配置資訊已經被寫在了codec中,解封裝和解碼用同一套引數。但是如果替換為codecpar ,那解碼器是獨立建立的,那是否還要手動填寫一遍解碼引數,理論上是需要的,不過還好ffmpeg提供給我們一個函式做引數複製 int avcodec_parameters_to_context(AVCodecContext *codec, const AVCodecParameters *par); 那我們codec引數替換為codecpar 程式碼就可以這樣寫了(錯誤處理省略) //開啟多媒體檔案,我們假定視訊流索引為0 AVFormatContext *ic = NULL; avformat_open_input(&ic, "test.mp4", 0, 0); //找到視訊解碼器,比如H264   AVCodec *codec = avcodec_find_decoder(ic->streams[0]->codecpar->codec_id); //獨立的解碼上下文 AVCodecContext * vc = avcodec_alloc_context3(codec); avcodec_parameters_to_context(vc, ic->streams[0]->codecpar); avcodec_open2(vc, codec, NULL); 程式碼改變後解碼上下文就是獨立的,後面解碼也不需要與解封裝上下文關聯,包括清理。 解碼器的ID號也變為從codecpar->codec_id成員獲取。