`

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

 
阅读更多

 

注:写了一系列的有关ffdshow对解码器的封装的代码,列表如下:
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源代码

    ffdshow的源代码是学习视频解码和处理技术的宝贵资源,对于开发者来说,深入研究它的实现细节有助于提升在多媒体领域的专业技能。 首先,让我们来看看ffdshow的核心功能: 1. **视频解码**:ffdshow能够解码多种...

    FFmpeg基础库编程开发

    ffdshow 源代码分析 8: 视频解码器类(TvideoCodecDec) 344 ffdshow 源代码分析 9: 编解码器有关类的总结 352 9.2 LAV filters 357 LAV Filter 源代码分析 1: 总体结构 357 LAV Filter 源代码分析 2: LAV ...

    ffmpeg基础开发资料自总结

    ffdshow 源代码分析 8: 视频解码器类(TvideoCodecDec) 328 ffdshow 源代码分析 9: 编解码器有关类的总结 335 9.2 LAV filters 340 LAV Filter 源代码分析 1: 总体结构 340 LAV Filter 源代码分析 2: LAV ...

    ffdshow的源代码(2012)

    10. **持续学习与进阶**:通过对ffdshow源代码的学习,开发者可以进一步研究更复杂的多媒体处理技术,如硬件加速、3D视频解码、实时编码等。 总的来说,ffdshow的源代码是一个宝贵的教育资源,无论对于初学者还是...

    FFDSHOW 源代码

    FFDSHOW是一款著名的开源视频解码过滤器,广泛应用于多媒体播放软件中,如VLC、Media Player Classic等。它的源代码提供了对多种视频和音频格式的解码支持,包括但不限于MPEG-4 ASP(DivX,XviD)、H.264、VP9、AV1...

    ffdshow源代码

    ffdshow是一款著名的开源视频解码过滤器,广泛应用于Windows平台上的多媒体播放软件中。它能够解码多种视频编码格式,包括但不限于MPEG-4 ASP(如DivX和XviD)、H.264、MPEG-1、MPEG-2、VP8以及Theora等。ffdshow的...

    ffdshow音视频解码器

    ffdshow是一款著名的开源音视频解码器,广泛应用于多媒体播放领域。它支持众多音视频编码格式,使得用户能够在不安装多种解码器的情况下,顺利播放各种格式的媒体文件。ffdshow以其高效、灵活和可定制性著称,是许多...

    ffdshow的源代码

    FFDShow是一个开源的视频解码过滤器,主要用于在Windows平台上播放各种编码格式的视频文件。它是基于FFmpeg项目的一部分,而FFmpeg则是一个全面的多媒体处理框架,涵盖了音视频编码、解码、转码、流媒体等多个领域。...

    ffdshow-视频解码

    ffdshow是一款著名的开源视频解码过滤器,专为Windows操作系统设计。它被广泛应用于多媒体播放领域,因其强大的解码能力和广泛的格式支持而受到用户青睐。ffdshow能够在DirectShow框架下工作,与各种媒体播放器(如...

    ffdshow 解码器

    ffdshow 解码器 ffdshow 解码器 ffdshow 解码器

    ffdshow20130525x64解码器

    ffdshow20130525x64解码器是一款专为64位操作系统设计的视频解码工具,其主要功能是帮助用户解析和播放各种格式的视频文件。在数字媒体领域,解码器扮演着至关重要的角色,因为不同格式的视频文件需要对应的解码器...

    FFDShow全能解码器 2012.1213 官方版.rar

    最初FFDShow只是mpeg视频解码器,不过现在他能做到的远不止于此.它能够解码的视频格式已经远远超出了mepg4的范围,包括indeo video,WMV,mpeg2等等.同时,它也提供了丰富的加工处理选项,可以锐化画面,调节画面的亮度等等...

    ffdshow解码器2012.3.22官方中文版.rar

    这是一个全能的音频视频解码器,支持N多的媒体格式,丰富的选项设置可以自由调节画面的音频参数,安装后能够让你的电脑播放最新的视频文件。可自定义选择安装以下组件:ffdshow DirectShow 滤镜DXVA video ...

    Windows 7 音视频解码器 Windows 7 Codec Pack 4.2.7 免费版.zip

    Windows 7 音视频解码器 Windows 7 Codec Pack 下载Windows 7 音视频解码器 Windows 7 Codec Pack 中文版 封装编解码器组件: ●LAV视频解码器0.74.1 Build 60 x86。 ●LAV视频解码器0.74.1 Build 60 x64。 ●Cole的...

    Windows 8 视频解码器 Windows 8 Codec Pack 2.1.7 免费版.zip

    Windows 8 视频解码器 Windows 8 Codec PackWindows 8 视频解码器 Windows 8 Codec Pack 中文版 包含最基本的媒体编解码器的软件包,可以在默认播放器中播放各种流行的格式 Windows 8 编解码器包包括音频和视频编...

    ffdshow sdk

    - 学习FFDShow的源代码,了解如何高效地处理视频解码和编码。 - 创建自定义的解码器和编码器,以适应特定的需求或优化性能。 - 将FFDShow的功能集成到多媒体播放器、视频编辑软件或其他多媒体应用中。 - 开发新的...

    ffdshow代码

    总的来说,ffdshow代码是一个涵盖视频解码、画质优化和用户自定义功能的综合性工具。通过学习它的源码,开发者可以提升在视频处理领域的专业技能,同时也可以为自己的项目引入类似的功能。无论是对个人学习还是商业...

    kLite解码器安装包

    【kLite解码器安装包】是一个专为Qt5版本设计的音视频解码工具,旨在帮助用户在使用Qt5开发音视频应用时能够顺利播放各种格式的媒体文件。这个安装包包含了完整的解码组件,使得Qt5应用程序无需依赖额外的第三方库就...

    ffdshow.EXE

    ffdshow是一款著名的开源视频解码过滤器,主要应用于Windows操作系统,用于处理各种视频流。它以其高度可定制性和性能优化而受到开发者和媒体播放爱好者的欢迎。ffdshow能够解码多种编码格式,包括但不限于MPEG-4 ...

    ffdshow_source_2011_12_28 ffdshow源码(2011-12-28)

    1. **ffdshow**: 这是一个基于DirectShow技术的视频解码器,能够处理多种视频编码格式,如H.264, Xvid, DivX等。它通过提供广泛的编解码选项和视频增强功能,使得用户可以在播放时调整视频质量,例如添加文字、图像...

Global site tag (gtag.js) - Google Analytics