ffdshow 原始碼分析 8: 視訊解碼器類(TvideoCodecDec)
=====================================================
ffdshow原始碼分析系列文章列表:
=====================================================
前面兩篇文章介紹了ffdshow中libavcodec的封裝類Tlibavcodec,以及libavcodec的解碼器類TvideoCodecLibavcodec:
其中libavcodec的解碼器類TvideoCodecLibavcodec通過呼叫Tlibavcodec中的方法實現了libavcodec的dll中方法的呼叫;而它繼承了TvideoCodecDec,本文正是要分析它繼承的這個類。
TvideoCodecDec是所有視訊解碼器共有的父類。可以看一下它的繼承關係:
可見,除了TvideoCodecLibavcodec繼承了TvideoCodecDec之外,還有好幾個類繼承了TvideoCodecDec,比如說:TvideoCodecLibmpeg2,TvideoCodecXviD4等等…。突然來了興趣,我們可以看一下其他的解碼器類的定義是什麼樣的。
TvideoCodecLibmpeg2定義如下:
/* *雷霄驊 *[email protected] *中國傳媒大學/數字電視技術 */ #ifndef _TVIDEOCODECLIBMPEG2_H_ #define _TVIDEOCODECLIBMPEG2_H_ #include "TvideoCodec.h" #include "libmpeg2/include/mpeg2.h" class Tdll; struct Textradata; class TccDecoder; //libmpeg2解碼器 class TvideoCodecLibmpeg2 : public TvideoCodecDec { private: Tdll *dll; uint32_t (*mpeg2_set_accel)(uint32_t accel); mpeg2dec_t* (*mpeg2_init)(void); const mpeg2_info_t* (*mpeg2_info)(mpeg2dec_t *mpeg2dec); mpeg2_state_t (*mpeg2_parse)(mpeg2dec_t *mpeg2dec); void (*mpeg2_buffer)(mpeg2dec_t *mpeg2dec, const uint8_t *start, const uint8_t *end); void (*mpeg2_close)(mpeg2dec_t *mpeg2dec); void (*mpeg2_reset)(mpeg2dec_t *mpeg2dec, int full_reset); void (*mpeg2_set_rtStart)(mpeg2dec_t *mpeg2dec, int64_t rtStart); int (*mpeg2_guess_aspect)(const mpeg2_sequence_t * sequence, unsigned int * pixel_width, unsigned int * pixel_height); mpeg2dec_t *mpeg2dec; const mpeg2_info_t *info; bool wait4Iframe; int sequenceFlag; REFERENCE_TIME avgTimePerFrame; TffPict oldpict; Textradata *extradata; TccDecoder *ccDecoder; Tbuffer *buffer; uint32_t oldflags; bool m_fFilm; int SetDeinterlaceMethod(void); void init(void); HRESULT decompressI(const unsigned char *src, size_t srcLen, IMediaSample *pIn); protected: virtual bool beginDecompress(TffPictBase &pict, FOURCC infcc, const CMediaType &mt, int sourceFlags); public: TvideoCodecLibmpeg2(IffdshowBase *Ideci, IdecVideoSink *Isink); virtual ~TvideoCodecLibmpeg2(); static const char_t *dllname; virtual int getType(void) const { return IDFF_MOVIE_LIBMPEG2; } virtual int caps(void) const { return CAPS::VIS_QUANTS; } virtual void end(void); virtual HRESULT decompress(const unsigned char *src, size_t srcLen, IMediaSample *pIn); virtual bool onSeek(REFERENCE_TIME segmentStart); virtual HRESULT BeginFlush(); }; #endif
TvideoCodecXviD4定義如下:
/* *雷霄驊 *[email protected] *中國傳媒大學/數字電視技術 */ #ifndef _TVIDEOCODECXVID4_H_ #define _TVIDEOCODECXVID4_H_ #include "TvideoCodec.h" class Tdll; struct Textradata; //xvid解碼器 class TvideoCodecXviD4 : public TvideoCodecDec { private: void create(void); Tdll *dll; public: TvideoCodecXviD4(IffdshowBase *Ideci, IdecVideoSink *IsinkD); virtual ~TvideoCodecXviD4(); int (*xvid_global)(void *handle, int opt, void *param1, void *param2); int (*xvid_decore)(void *handle, int opt, void *param1, void *param2); int (*xvid_plugin_single)(void *handle, int opt, void *param1, void *param2); int (*xvid_plugin_lumimasking)(void *handle, int opt, void *param1, void *param2); static const char_t *dllname; private: void *enchandle, *dechandle; int psnr; TffPict pict; Tbuffer pictbuf; static int me_hq(int rd3), me_(int me3); Textradata *extradata; REFERENCE_TIME rtStart, rtStop; protected: virtual bool beginDecompress(TffPictBase &pict, FOURCC infcc, const CMediaType &mt, int sourceFlags); virtual HRESULT flushDec(void); public: virtual int getType(void) const { return IDFF_MOVIE_XVID4; } virtual int caps(void) const { return CAPS::VIS_QUANTS; } virtual HRESULT decompress(const unsigned char *src, size_t srcLen, IMediaSample *pIn); }; #endif
從以上這2種解碼器類的定義,我們可以看出一些規律,比如說:
1. 都有Tdll *dll這個變數,用於載入視訊解碼器的dll
2. 都有beginDecompress()函式,用於初始化解碼器
3. 都有decompress()函式,用於解碼
好了,閒話不說,迴歸正題,來看一下這些解碼器共有的父類:TvideoCodecDec
//具體 視訊 解碼器的父類,存一些公共資訊
class TvideoCodecDec : virtual public TvideoCodec, virtual public TcodecDec
{
protected:
bool isdvdproc;
comptrQ<IffdshowDecVideo> deciV;
IdecVideoSink *sinkD;
TvideoCodecDec(IffdshowBase *Ideci, IdecVideoSink *Isink);
Rational guessMPEG2sar(const Trect &r, const Rational &sar2, const Rational &containerSar);
class TtelecineManager
{
private:
TvideoCodecDec* parent;
int segment_count;
int pos_in_group;
struct {
int fieldtype;
int repeat_pict;
REFERENCE_TIME rtStart;
} group[2]; // store information about 2 recent frames.
REFERENCE_TIME group_rtStart;
bool film;
int cfg_softTelecine;
public:
TtelecineManager(TvideoCodecDec* Iparent);
void get_timestamps(TffPict &pict);
void get_fieldtype(TffPict &pict);
void new_frame(int top_field_first, int repeat_pict, const REFERENCE_TIME &rtStart, const REFERENCE_TIME &rtStop);
void onSeek(void);
} telecineManager;
public:
static TvideoCodecDec* initDec(IffdshowBase *deci, IdecVideoSink *Isink, AVCodecID codecId, FOURCC fcc, const CMediaType &mt);
virtual ~TvideoCodecDec();
virtual int caps(void) const {
return CAPS::NONE;
}
virtual bool testMediaType(FOURCC fcc, const CMediaType &mt) {
return true;
}
virtual void forceOutputColorspace(const BITMAPINFOHEADER *hdr, int *ilace, TcspInfos &forcedCsps) {
*ilace = 0; //cspInfos of forced output colorspace, empty when entering function
}
enum {SOURCE_REORDER = 1};
virtual bool beginDecompress(TffPictBase &pict, FOURCC infcc, const CMediaType &mt, int sourceFlags) = 0;
virtual HRESULT decompress(const unsigned char *src, size_t srcLen, IMediaSample *pIn) = 0;
virtual bool onDiscontinuity(void) {
return false;
}
virtual HRESULT onEndOfStream(void) {
return S_OK;
}
unsigned int quantsDx, quantsStride, quantsDy, quantBytes, quantType;
//QP表
void *quants;
uint16_t *intra_matrix, *inter_matrix;
//計算平均QP
float calcMeanQuant(void);
//畫運動向量
virtual bool drawMV(unsigned char *dst, unsigned int dx, stride_t stride, unsigned int dy) const {
return false;
}
virtual const char* get_current_idct(void) {
return NULL;
}
virtual int useDXVA(void) {
return 0;
};
virtual void setOutputPin(IPin * /*pPin*/) {}
};
TvideoCodecDec這個類中,還定義了一個類TtelecineManager。這種在類裡面再定義一個類的方式還是不太多見的。TtelecineManager這個類的作用還沒有研究,先不管它。
可以看出,TvideoCodecDec類的定義並不複雜,最主要的變數有如下幾個,這幾個變數都是子類中會用到的:
comptrQ<IffdshowDecVideo>deciV:重要性不言而喻,回頭介紹TvideoCodecDec類定義了幾個函式:
IdecVideoSink *sinkD:重要性不言而喻,回頭介紹
void *quants:QP表(為什麼要存在這裡還沒搞清)
initDec():初始化解碼器(重要)
calcMeanQuant():計算平均QP(為什麼要在這裡計算還沒搞清)
TvideoCodecDec類還定義了一些純虛擬函式,作為介面,這些函式的實現都在TvideoCodecDec的子類中完成【這幾個函式是最重要的】:
beginDecompress();
decompress();
TvideoCodecDec類中最重要的函式只有一個,就是initDec(),作用主要是初始化解碼器。其他的很多函式大多隻是定義了一個名稱,並沒有實現,因為都是打算在具體各種解碼器類中再進行實現的。
看一下initDec()的程式碼:
TvideoCodecDec* TvideoCodecDec::initDec(IffdshowBase *deci, IdecVideoSink *sink, AVCodecID codecId, FOURCC fcc, const CMediaType &mt)
{
// DXVA mode is a preset setting
switch (codecId) {
case AV_CODEC_ID_H264:
if (deci->getParam2(IDFF_filterMode) & IDFF_FILTERMODE_VIDEODXVA) {
if (deci->getParam2(IDFF_dec_DXVA_H264)) {
codecId = CODEC_ID_H264_DXVA;
} else {
return NULL;
}
}
break;
case AV_CODEC_ID_VC1:
case CODEC_ID_WMV9_LIB:
if (deci->getParam2(IDFF_filterMode) & IDFF_FILTERMODE_VIDEODXVA) {
if (deci->getParam2(IDFF_dec_DXVA_VC1)) {
codecId = CODEC_ID_VC1_DXVA;
} else {
return NULL;
}
}
break;
default:
break;
}
TvideoCodecDec *movie = NULL;
if (is_quicksync_codec(codecId)) {
movie = new TvideoCodecQuickSync(deci, sink, codecId);
} else if (lavc_codec(codecId)) {
movie = new TvideoCodecLibavcodec(deci, sink);
} else if (raw_codec(codecId)) {
movie = new TvideoCodecUncompressed(deci, sink);
} else if (wmv9_codec(codecId)) {
movie = new TvideoCodecWmv9(deci, sink);
} else if (codecId == CODEC_ID_XVID4) {
movie = new TvideoCodecXviD4(deci, sink);
} else if (codecId == CODEC_ID_LIBMPEG2) {
movie = new TvideoCodecLibmpeg2(deci, sink);
} else if (codecId == CODEC_ID_AVISYNTH) {
movie = new TvideoCodecAvisynth(deci, sink);
} else if (codecId == CODEC_ID_H264_DXVA || codecId == CODEC_ID_VC1_DXVA) {
movie = new TvideoCodecLibavcodecDxva(deci, sink, codecId);
} else {
return NULL;
}
if (!movie) {
return NULL;
}
if (movie->ok && movie->testMediaType(fcc, mt)) {
movie->codecId = codecId;
return movie;
} else if (is_quicksync_codec(codecId)) {
// QuickSync decoder init failed, revert to internal decoder.
switch (codecId) {
case CODEC_ID_H264_QUICK_SYNC:
codecId = AV_CODEC_ID_H264;
break;
case CODEC_ID_MPEG2_QUICK_SYNC:
codecId = CODEC_ID_LIBMPEG2;
break;
case CODEC_ID_VC1_QUICK_SYNC:
codecId = CODEC_ID_WMV9_LIB;
break;
default:
ASSERT(FALSE); // this shouldn't happen!
}
delete movie;
// Call this function again with the new codecId.
return initDec(deci, sink, codecId, fcc, mt);
} else {
delete movie;
return NULL;
}
}
這個函式的功能還是比較好理解的,根據CodecID的不同,建立不同的解碼器(從TvideoCodecLibavcodec,TvideoCodecXviD4,TvideoCodecLibmpeg2這些裡面選擇)。
雖然不知道用途是什麼,但是我們可以順便看一下計算平均QP的函式,就是把quants1指向的QP表裡面的資料求了一個平均值:
//計算平均QP
float TvideoCodecDec::calcMeanQuant(void)
{
if (!quants || !quantsDx || !quantsDy) {
return 0;
}
unsigned int sum = 0, num = quantsDx * quantsDy;
unsigned char *quants1 = (unsigned char*)quants;
for (unsigned int y = 0; y < quantsDy; y++)
for (unsigned int x = 0; x < quantsDx; x++) {
sum += quants1[(y * quantsStride + x) * quantBytes];
}
return float(sum) / num;
}
相關推薦
ffdshow 原始碼分析 8: 視訊解碼器類(TvideoCodecDec)
=====================================================ffdshow原始碼分析系列文章列表:=====================================================前面兩篇文章介紹了ffds
ffdshow 原始碼分析 9: 編解碼器有關類的總結
=====================================================ffdshow原始碼分析系列文章列表:=====================================================前幾篇文章已經完成了ffd
XBMC原始碼分析 4:視訊播放器(dvdplayer)-解碼器(以ffmpeg為例)
XBMC分析系列文章: 本文我們分析XBMC中視訊播放器(dvdplayer)中的解碼器部分。由於解碼器種類很多,不可能一一分析,因此以ffmpeg解碼器為例進行分析。 XBMC解碼器部分檔案目錄如下圖所示: 解碼器分為音訊解碼器和視訊解碼器。在這裡我們看一下視訊
XBMC原始碼分析 6:視訊播放器(dvdplayer)-檔案頭(以ffmpeg為例)
XBMC分析系列文章: XBMC原始碼簡析 5:視訊播放器(dvdplayer)-解複用器(以ffmpeg為例)本文我們分析XBMC中視訊播放器(dvdplayer)中的檔案頭部分。檔案頭部分裡包含的是封裝Dll用到的標頭檔案。由於檔案頭種類很多,不可能一一分析,
Tomcat原始碼分析三:Tomcat啟動載入過程(一)的原始碼解析
Tomcat啟動載入過程(一)的原始碼解析 今天,我將分享用原始碼的方式講解Tomcat啟動的載入過程,關於Tomcat的架構請參閱《Tomcat原始碼分析二:先看看Tomcat的整體架構》一文。 先看看應用情況 在《Servlet與Tomcat執行示例》一文中,我詳細的記錄了Tomcat是如何啟動一個Ser
Java原始碼分析——String、StringBuffer、StringBuilder類(二)——AbstractStringBuilder抽象類
在Java中,關於字串類分為兩種,一種是上篇部落格講的String類,即不可變字串類,另外一種則是可變字串類,即AbstractStringBuilder抽象類的子類,StringBuffer與StringBuilder類,其中的兩者的區別
WebRTC原始碼分析四:視訊模組結構
本文在上篇的基礎上介紹WebRTC視訊部分的模組結構,以進一步瞭解其實現框架,只有瞭解了整體框架結構,對區域性演算法修改才能夠胸有成竹。 一、對外介面 對外介面有ViEBase,ViECapture,ViECodec,ViEEncryption,V
Netty原始碼分析第6章(解碼器)---->第3節: 行解碼器
Netty原始碼分析第六章: 解碼器 第三節: 行解碼器 這一小節瞭解下行解碼器LineBasedFrameDecoder, 行解碼器的功能是一個位元組流, 以\r\n或者直接以\n結尾進行解碼, 也就是以換行符為分隔進行解析 同樣, 這個解碼器也繼承了B
Netty原始碼分析第6章(解碼器)---->第2節: 固定長度解碼器
Netty原始碼分析第六章: 解碼器 第二節: 固定長度解碼器 上一小節我們瞭解到, 解碼器需要繼承ByteToMessageDecoder, 並重寫decode方法, 將解析出來的物件放入集合中集合, ByteToMessageDecoder中可以將解析出
Netty原始碼分析第6章(解碼器)---->第1節: ByteToMessageDecoder
Netty原始碼分析第六章: 解碼器 概述: 在我們上一個章節遺留過一個問題, 就是如果Server在讀取客戶端的資料的時候, 如果一次讀取不完整, 就觸發channelRead事件, 那麼Netty是
Netty原始碼分析第6章(解碼器)---->第4節: 分隔符解碼器
Netty原始碼分析第六章: 解碼器 第四節: 分隔符解碼器 基於分隔符解碼器DelimiterBasedFrameDecoder, 是按照指定分隔符進行解碼的解碼器, 通過分隔符, 可以將二進位制流拆分成完整的資料包 同樣
WebRTC原始碼分析三:視訊處理流程
文字介紹視訊的處理流程。圖1中顯示了兩路視訊會話視訊訊號流過程。 圖1 視訊流程示意圖 以一路視訊會話為例,主要分為以下幾個執行緒: 1)視訊源產生執行緒:Camera生產視訊畫面,封裝成視訊幀,以一定幀率投遞到下一個模組。; 2)採集執行緒:由Capturer負責採集視訊幀,並對視訊幀進行一定處理,如
RTMPdump(libRTMP) 原始碼分析 8: 傳送訊息(Message)
=====================================================RTMPdump(libRTMP) 原始碼分析系列文章:=====================================================函式呼叫
ffdshow 原始碼分析 5: 點陣圖覆蓋濾鏡(總結)
=====================================================ffdshow原始碼分析系列文章列表:=====================================================前面寫了三篇文章,介紹了
python 學習彙總25:迭代器iter( tcy)
迭代器 2018/6/12 目錄: iter 1.iter 2.iter-型別判斷 3.iter-解包 itertools工具 1.itertools函式簡表 見本人相關博文 2.itertools函式詳細說明 見本人相關博文 3
【PHP7原始碼分析】如何理解PHP虛擬機器(一)
順風車運營研發團隊 李樂 1.從物理機說起 虛擬機器也是計算機,設計思想和物理機有很多相似之處; 1.1馮諾依曼體系結構 馮·諾依曼是當之無愧的數字計算機之父,當前計算機都採用的是馮諾依曼體系結構;設計思想主要包含以下幾個方面: 指令和資料不加區別混合儲存在同一個儲
mmap核心原始碼分析,基於核心版本3.10(三)
之前寫了(一)(二)其實就梳理到了get_unmapped_area的內容,而且有一點混亂,這裡進行第三篇的講解,講解在do_mmap_pgoff中除了get_unmapped_area的內容,來了解mmap的具體實現。通過(一)(二)(三)來將mmap核心原始碼進行一次梳理
springMVC原始碼分析--異常處理機制HandlerExceptionResolver執行原理(二)
上一篇部落格springMVC原始碼分析--異常處理機制HandlerExceptionResolver簡單示例(一)中我們簡單地實現了一個異常處理例項,接下來我們要介紹一下HandlerExceptionResolver是如何捕獲到Controller中丟擲的異常並展示到前
springMVC原始碼分析--異常處理機制HandlerExceptionResolver簡單示例(一)
springMVC對Controller執行過程中出現的異常提供了統一的處理機制,其實這種處理機制也簡單,只要丟擲的異常在DispatcherServlet中都會進行捕獲,這樣就可以統一的對異常進行處理。 springMVC提供了一個HandlerExcepti
live555原始碼分析之------ H264 RTP封包原理(總結)
在一個RTP 包中封裝多個NALU,對於較小的NALU 可以採用這種打包方案,從而提高傳輸效率。 即可能是由多個 NAL 單元組成一個 RTP 包。 分別有4種組合方式: STAP-A, STAP-B, MTAP16, MTAP24. 那麼這裡的型別值分別是 24, 25, 26 以及 27.