ffdshow 源代码分析 8: 视频解码器类(TvideoCodecDec)
=====================================================
ffdshow源代码分析系列文章列表:
ffdshow 源代码分析 2: 位图覆盖滤镜(对话框部分Dialog)
ffdshow 源代码分析 3: 位图覆盖滤镜(设置部分Settings)
ffdshow 源代码分析 4: 位图覆盖滤镜(滤镜部分Filter)
ffdshow 源代码分析 6: 对解码器的dll的封装(libavcodec)
ffdshow 源代码分析 7: libavcodec视频解码器类(TvideoCodecLibavcodec)
ffdshow 源代码分析 8: 视频解码器类(TvideoCodecDec)
=====================================================
前面两篇文章介绍了ffdshow中libavcodec的封装类Tlibavcodec,以及libavcodec的解码器类TvideoCodecLibavcodec:
ffdshow 源代码分析 6: 对解码器的dll的封装(libavcodec)
ffdshow 源代码分析 7: 解码器类(TvideoCodecLibavcodec)
其中libavcodec的解码器类TvideoCodecLibavcodec通过调用Tlibavcodec中的方法实现了libavcodec的dll中方法的调用;而它继承了TvideoCodecDec,本文正是要分析它继承的这个类。
TvideoCodecDec是所有视频解码器共有的父类。可以看一下它的继承关系:
可见,除了TvideoCodecLibavcodec继承了TvideoCodecDec之外,还有好几个类继承了TvideoCodecDec,比如说:TvideoCodecLibmpeg2,TvideoCodecXviD4等等…。突然来了兴趣,我们可以看一下其他的解码器类的定义是什么样的。
TvideoCodecLibmpeg2定义如下:
/*
*雷霄骅
*leixiaohua1020@126.com
*中国传媒大学/数字电视技术
*/
#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定义如下:
/*
*雷霄骅
*leixiaohua1020@126.com
*中国传媒大学/数字电视技术
*/
#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:重要性不言而喻,回头介绍
IdecVideoSink *sinkD:重要性不言而喻,回头介绍
void *quants:QP表(为什么要存在这里还没搞清)
TvideoCodecDec类定义了几个函数:
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 源代码分析
ffdshow神奇的功能:视频播放时显示运动矢量和QP FFDShow可以称得上是全能的解码.编码器.最初FFDShow只是mpeg视频解码器,不过现在他能做到的远不止于此.它能够解码的视频格式已经远 ...
- ffdshow 源代码分析 7: libavcodec视频解码器类(TvideoCodecLibavcodec)
===================================================== ffdshow源代码分析系列文章列表: ffdshow 源代码分析 1: 整体结构 ffds ...
- ffdshow 源代码分析 9: 编解码器有关类的总结
===================================================== ffdshow源代码分析系列文章列表: ffdshow 源代码分析 1: 整体结构 ffds ...
- ffdshow 源代码分析 6: 对解码器的dll的封装(libavcodec)
===================================================== ffdshow源代码分析系列文章列表: ffdshow 源代码分析 1: 整体结构 ffds ...
- ffdshow 源代码分析 5: 位图覆盖滤镜(总结)
===================================================== ffdshow源代码分析系列文章列表: ffdshow 源代码分析 1: 整体结构 ffds ...
- ffdshow 源代码分析 4: 位图覆盖滤镜(滤镜部分Filter)
===================================================== ffdshow源代码分析系列文章列表: ffdshow 源代码分析 1: 整体结构 ffds ...
- ffdshow 源代码分析 3: 位图覆盖滤镜(设置部分Settings)
===================================================== ffdshow源代码分析系列文章列表: ffdshow 源代码分析 1: 整体结构 ffds ...
- ffdshow 源代码分析 2: 位图覆盖滤镜(对话框部分Dialog)
===================================================== ffdshow源代码分析系列文章列表: ffdshow 源代码分析 1: 整体结构 ffds ...
- Media Player Classic - HC 源代码分析 4:核心类 (CMainFrame)(3)
===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...
随机推荐
- 《An Industrial-Strength Audio Search Algorithm》译文
随着微信摇一摇逐渐被大众所广泛使用,听歌识曲功能也开始被关注.目前来看,像音乐雷达和微信摇一摇都采用了经典的shazam算法,为了使大家对shazam算法更加了解,我将其经典论文进行了翻译,希望对大家 ...
- OBJ文件格式分析工具: objdump, nm,ar
首先简要阐述关于gcc.glibc和 binutils模块之间的关系 一.关于gcc.glibc和binutils模块之间的关系 1.gcc(gnu collect compiler)是一组编译工具的 ...
- LAB颜色空间各通道的取值范围
简介 LAB颜色空间在计算机视觉中经常被使用,知道L,A,B三个通道的取值范围有一定的意义. OpenCV获取LAB取值范围 下面是一段实验代码,用于获取LAB的取值范围. 基本思路是,排列组合所有R ...
- Python实现数据库一键导出为Excel表格
依赖 Python2711 xlwt MySQLdb 数据库相关 连接 获取字段信息 获取数据 Excel基础 workbook sheet 案例 封装 封装之后 测试结果 总结 数据库数据导出为ex ...
- 可能是CAP理论的最好解释
一篇非常精彩的解释CAP理论的文章,翻译水平有限,不准确之处请参考原文,还请见谅. Chapter 1: "Remembrance Inc" Your new venture : ...
- Redis 学习笔记1:CentOS 6.7下安装Redis
在linux环境搭建Redis环境,首先从官网(http://redis.io/)下载Redis 版本,本人使用的3.21版本. 1. 将redis 解压到 /usr/local目录下. [root ...
- SpriteKit中类似Cocos2D的CCActionSpawn并发方法GroupAction
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在Cocos2D中对于并发Action的处理可以使用C ...
- Ubuntu和Windows设备共享
http://blog.csdn.net/pipisorry/article/details/51725942 蓝牙设备如键盘.鼠标都可以. 装的双系统win7和Ubuntu,如果只使用一个系统,蓝牙 ...
- 11 ContextMenu 上下文菜单按钮
ContextMenu 上下文菜单 在res下的menu里写菜单项 在逻辑代码中 写OnCreateContextMenu() 方法 将菜单项添加到菜单 对菜单项进行监听 onContextItemS ...
- Android的ImageSwitcher和TextSw-android学习之旅(三十四)
ImageSwitcher简介 ImageSwitcher继承了ViewSwitcher,所以在切换时候会有动画,可以把它理解成一个动画版本的ImageView. 他的showNext(),和show ...