ffdshow 源代码分析 8: 视频解码器类(TvideoCodecDec)

本文深入解析了ffdshow中的视频解码器类TvideoCodecDec及其子类的实现细节,包括关键成员变量和函数的作用,特别是初始化解码器的initDec()函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

=====================================================

ffdshow源代码分析系列文章列表:

ffdshow 源代码分析 1: 整体结构

ffdshow 源代码分析 2: 位图覆盖滤镜(对话框部分Dialog)

ffdshow 源代码分析 3: 位图覆盖滤镜(设置部分Settings)

ffdshow 源代码分析 4: 位图覆盖滤镜(滤镜部分Filter)

ffdshow 源代码分析 5: 位图覆盖滤镜(总结)

ffdshow 源代码分析 6: 对解码器的dll的封装(libavcodec)

ffdshow 源代码分析 7: libavcodec视频解码器类(TvideoCodecLibavcodec)

ffdshow 源代码分析 8: 视频解码器类(TvideoCodecDec)

ffdshow 源代码分析 9: 编解码器有关类的总结

=====================================================

前面两篇文章介绍了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消耗CPU功率比原来的DivX编码方式少,甚至最高的后处理。同时后处理似乎给优良的品质效果,并允许超过原有的DivX编解码器的配置。它甚至可以全自动减少后处理,如果你的CPU是挤破头。噪音过滤器增加了一个rasterising效果图片 - 可能在某些情况下非常有用。 alpha版本还包括MPEG - 1和MPEG - 2文件(如VCD和SVCD影片),其中作品相当该死的实验播放。唯一的问题是,MPEG - 2播放可以直接从CD SVCD的剪辑,但需要使用VCDGear首先要提取的视频到硬盘。 FFDSHOW MPEG - 4视频解码器的特点: - 各种压缩方法: MPEG - 4兼容(XVID,DIVX,DIVX 6的DivX 4,DivX的5 7 8,DIVX)使用libavcodec的或XviD DIVX 3兼容,MSMPEG4v2,MSMPEG4v1 WMV2 WMV1 / 7 / 8 H263,H263 ,H264 HuffYUV YV12色彩 MJPEG MPEG - 1 MPEG - 2,使用MJPEGtools项目mpeg2enc代码 MP3,AC3,DTS,E - AC3,AAC格式 SVQ3 Vorbis格式 Theora格式(不经常使用,格式是没有稳定尚未) 所有的Windows Media Video 9的支持编码器输出​​到ASF / WMV文件或AVI - 所有常用的编码模式:恒定比特率,固定量化,定质量,二阶段编码(取决于压缩机的功能) - libavcodec的和XviD的运动估计方法的详细选择 - 最小和最大I帧间隔 - 最小和最大的量化选择,量化型和格子libavcodec的量化选择 - 自适应量化(亦称屏蔽)使用libavcodec和XviD,消除单一系数 - 可选择的压缩开始和结束学分 - 两个曲线的第二个阶段二阶段编码压缩算法 - XVID开发 - 第二遍模拟:虽然不是很精确,还有助于调整先进的曲线压缩参数 - 能够使用libavcodec的内部传递代码 - 图像预处理与FFDSHOW的图像过滤器(必须安装最新的FFDSHOW版本) - 图在编码过程中:如果你的编码方案未提供 - B帧支持:从一到8个连续的B帧 - 支持MPEG - 4 quarterpel和GMC - 可选择的隔行编码 - 减压 FFDSHOW的转换3943,3900 FFDSHOW转换: - 腾出空间用于添加更多的色彩FFDSHOW - 更新Libav - 更新pthreads的(CVS 20110710) - 修正了另一个DXVA的回归 - 更新Swscale - 64位的pthread库 - ffdshow的音频解码器的QT PCM变种(如三三两两)创建新格式“选项。他们以前如果未压缩的音频选项的一部分。 - 修正了一些色彩空间转换问题 - 更新了俄语翻译 - 在XP上安装的MANIFEST文件 - ICL12工程:清理和移动common_icl12.props所有共同属性 - VS2010的项目:清理 - 更新线程工具提示 - VS2010的项目: *清理额外的库 *修复makeAVIS文件,libfaad2 ff_wmv9项目 *重命名libmpeg2_ff一致性的项目文件 - 更新构建脚本 - 修正H.264 4:4:4 - 哈克,以防止与H.264 4:4:4的崩溃。色彩尚不支持。 - 更新黑名单 重要注意事项: - 一些杀毒软件一样的AVG“检测”在FFDSHOW木马之上。这是一个假阳性,有FFDSHOW建立无木马!
h.264视频解码源代码.rar 详细说明:h.264标准代码,用于视频编码!可以实现各种视频的编码和解码,可以在这个代码的基础上进行各种开发,比如算法的优化,转码技术,实现各种分辨了的转码-h.264 standard code, uses in the video frequency code! May realize each kind of video frequency code and the decoding, may carry on each kind of development in this code foundation, for instance the algorithm optimization, transfers the code technology, realizes each kind has distinguished extension code 文件列表: jm73 ....\JM ....\..\bin ....\..\...\decoder.cfg ....\..\...\encoder.cfg ....\..\...\lencod.exe ....\..\...\lencod.map ....\..\...\lencod.pdb ....\..\CHANGES.TXT ....\..\Changes_detail.txt ....\..\copyright.txt ....\..\disclaimer.txt ....\..\doc ....\..\...\coding_style.doc ....\..\...\doxygen.txt ....\..\...\h26l.css ....\..\...\ldecod.dox ....\..\...\lencod.dox ....\..\encoder.cfg ....\..\foreman_part_qcif.yuv ....\..\ldecod ....\..\......\inc ....\..\......\...\annexb.h ....\..\......\...\biaridecod.h ....\..\......\...\block.h ....\..\......\...\cabac.h ....\..\......\...\context_ini.h ....\..\......\...\contributors.h ....\..\......\...\ctx_tables.h ....\..\......\...\defines.h ....\..\......\...\elements.h ....\..\......\...\erc_api.h ....\..\......\...\erc_do.h ....\..\......\...\erc_globals.h ....\..\......\...\errorconcealment.h ....\..\......\...\fmo.h ....\..\......\...\global.h ....\..\......\...\header.h ....\..\......\...\image.h ....\..\......\...\leaky_bucket.h ....\..\......\...\macroblock.h ....\..\......\...\mbuffer.h ....\..\......\...\mb_access.h ....\..\......\...\memalloc.h ....\..\......\...\nalu.h ....\..\......\...\nalucommon.h ....\..\......\...\output.h ....\..\......\...\parset.h ....\..\......\...\parsetcommon.h ....\..\......\...\rtp.h ....\..\......\...\sei.h ....\..\......\...\vlc.h ....\..\......\Makefile ....\..\......\src ....\..\......\...\annexb.c ....\..\......\...\biaridecod.c ....\..\......\...\block.c ....\..\......\...\cabac.c ....\..\......\...\context_ini.c ....\..\......\...\erc_api.c ....\..\......\...\erc_do_i.c ....\..\......\...\erc_do_p.c ....\..\......\...\errorconcealment.c ....\..\......\...\filehandle.c ....\..\......\...\fmo.c ....\..\......\...\header.c ....\..\......\...\image.c ....\..\......\...\ldecod.c ....\..\......\...\leaky_bucket.c ....\..\......\...\loopFilter.c ....\..\......\...\macroblock.c ....\..\......\...\mbuffer.c ....\..\......\...\mb_access.c ....\..\......\...\memalloc.c ....\..\......\...\nal.c ....\..\......\...\nalu.c ....\..\......\...\nalucommon.c ....\..\......\...\nal_part.c ....\..\......\...\output.c ....\..\......\...\parset.c ....\..\......\...\parsetcommon.c ....\..\......\...\rtp.c ....\..\......\...\sei.c ....\..\......\...\vlc.c ....\..\ldecod.dsp ....\..\ldecod.dsw ... ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值