/*
* $Id$
*
* (C) 2006-2010 see AUTHORS
*
* This file is part of mplayerc.
*
* Mplayerc is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Mplayerc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "stdafx.h"
#include
#include
#include
#include "PODtypes.h"
#include "avcodec.h"
#include
#include "MPCVideoDecFilter.h"
#include "VideoDecOutputPin.h"
#include "CpuId.h"
extern "C"
{
#include "FfmpegContext.h"
#include "libswscale/swscale.h"
extern void init_libvo();
}
#include "../../../DSUtil/DSUtil.h"
#include "../../../DSUtil/MediaTypes.h"
#include "../../parser/mpegsplitter/MpegSplitter.h"
#include
#include "DXVADecoderH264.h"
#include "../../../apps/mplayerc/internal_filter_config.h"
/////
#define MAX_SUPPORTED_MODE 5
#define MPCVD_CAPTION _T("MPC Video decoder")
#define ROUND_FRAMERATE(var,FrameRate) if (labs ((long)(var - FrameRate)) < FrameRate*1/100) var = FrameRate;
typedef struct
{
const int PicEntryNumber;
const UINT PreferedConfigBitstream;
const GUID* Decoder[MAX_SUPPORTED_MODE];
const WORD RestrictedMode[MAX_SUPPORTED_MODE];
} DXVA_PARAMS;
typedef struct
{
const CLSID* clsMinorType;
const enum CodecID nFFCodec;
const int fourcc;
const DXVA_PARAMS* DXVAModes;
int DXVAModeCount()
{
if (!DXVAModes) return 0;
for (int i=0; iDecoder[i] == &GUID_NULL) return i;
}
return MAX_SUPPORTED_MODE;
}
} FFMPEG_CODECS;
typedef enum
{
ffYCbCr_RGB_coeff_ITUR_BT601 = 0,
ffYCbCr_RGB_coeff_ITUR_BT709 = 1,
ffYCbCr_RGB_coeff_SMPTE240M = 2,
} ffYCbCr_RGB_MatrixCoefficientsType;
struct TYCbCr2RGB_coeffs {
double Kr;
double Kg;
double Kb;
double chr_range;
double y_mul;
double vr_mul;
double ug_mul;
double vg_mul;
double ub_mul;
int Ysub;
int RGB_add1;
int RGB_add3;
TYCbCr2RGB_coeffs(ffYCbCr_RGB_MatrixCoefficientsType cspOptionsIturBt,
int cspOptionsWhiteCutoff,
int cspOptionsBlackCutoff,
int cspOptionsChromaCutoff,
double cspOptionsRGB_WhiteLevel,
double cspOptionsRGB_BlackLevel)
{
if (cspOptionsIturBt == ffYCbCr_RGB_coeff_ITUR_BT601) {
Kr = 0.299;
Kg = 0.587;
Kb = 0.114;
} else if (cspOptionsIturBt == ffYCbCr_RGB_coeff_SMPTE240M) {
Kr = 0.2122;
Kg = 0.7013;
Kb = 0.0865;
} else {
Kr = 0.2125;
Kg = 0.7154;
Kb = 0.0721;
}
double in_y_range = cspOptionsWhiteCutoff - cspOptionsBlackCutoff;
chr_range = 128 - cspOptionsChromaCutoff;
double cspOptionsRGBrange = cspOptionsRGB_WhiteLevel - cspOptionsRGB_BlackLevel;
y_mul =cspOptionsRGBrange / in_y_range;
vr_mul=(cspOptionsRGBrange / chr_range) * (1.0 - Kr);
ug_mul=(cspOptionsRGBrange / chr_range) * (1.0 - Kb) * Kb / Kg;
vg_mul=(cspOptionsRGBrange / chr_range) * (1.0 - Kr) * Kr / Kg;
ub_mul=(cspOptionsRGBrange / chr_range) * (1.0 - Kb);
int sub = min((int)cspOptionsRGB_BlackLevel, cspOptionsBlackCutoff);
Ysub = cspOptionsBlackCutoff - sub;
RGB_add1 = (int)cspOptionsRGB_BlackLevel - sub;
RGB_add3 = (RGB_add1 << 8) + (RGB_add1 << 16) + RGB_add1;
}
};
// DXVA modes supported for Mpeg2
DXVA_PARAMS DXVA_Mpeg2 =
{
9, // PicEntryNumber
1, // PreferedConfigBitstream
{ &DXVA2_ModeMPEG2_VLD, &GUID_NULL },
{ DXVA_RESTRICTED_MODE_UNRESTRICTED, 0 } // Restricted mode for DXVA1?
};
// DXVA modes supported for H264
DXVA_PARAMS DXVA_H264 =
{
16, // PicEntryNumber
2, // PreferedConfigBitstream
{ &DXVA2_ModeH264_E, &DXVA2_ModeH264_F, &DXVA_Intel_H264_ClearVideo, &GUID_NULL },
{ DXVA_RESTRICTED_MODE_H264_E, 0}
};
DXVA_PARAMS DXVA_H264_VISTA =
{
22, // PicEntryNumber
2, // PreferedConfigBitstream
{ &DXVA2_ModeH264_E, &DXVA2_ModeH264_F, &DXVA_Intel_H264_ClearVideo, &GUID_NULL },
{ DXVA_RESTRICTED_MODE_H264_E, 0}
};
// DXVA modes supported for VC1
DXVA_PARAMS DXVA_VC1 =
{
14, // PicEntryNumber
1, // PreferedConfigBitstream
{ &DXVA2_ModeVC1_D, &GUID_NULL },
{ DXVA_RESTRICTED_MODE_VC1_D, 0}
};
FFMPEG_CODECS ffCodecs[] =
{
#if INCLUDE_MPC_VIDEO_DECODER
// Flash video
{ &MEDIASUBTYPE_FLV1, CODEC_ID_FLV1, MAKEFOURCC('F','L','V','1'), NULL },
{ &MEDIASUBTYPE_flv1, CODEC_ID_FLV1, MAKEFOURCC('f','l','v','1'), NULL },
{ &MEDIASUBTYPE_FLV4, CODEC_ID_VP6F, MAKEFOURCC('F','L','V','4'), NULL },
{ &MEDIASUBTYPE_flv4, CODEC_ID_VP6F, MAKEFOURCC('f','l','v','4'), NULL },
{ &MEDIASUBTYPE_VP6F, CODEC_ID_VP6F, MAKEFOURCC('V','P','6','F'), NULL },
{ &MEDIASUBTYPE_vp6f, CODEC_ID_VP6F, MAKEFOURCC('v','p','6','f'), NULL },
// VP5
{ &MEDIASUBTYPE_VP50, CODEC_ID_VP5, MAKEFOURCC('V','P','5','0'), NULL },
{ &MEDIASUBTYPE_vp50, CODEC_ID_VP5, MAKEFOURCC('v','p','5','0'), NULL },
// VP6
{ &MEDIASUBTYPE_VP60, CODEC_ID_VP6, MAKEFOURCC('V','P','6','0'), NULL },
{ &MEDIASUBTYPE_vp60, CODEC_ID_VP6, MAKEFOURCC('v','p','6','0'), NULL },
{ &MEDIASUBTYPE_VP61, CODEC_ID_VP6, MAKEFOURCC('V','P','6','1'), NULL },
{ &MEDIASUBTYPE_vp61, CODEC_ID_VP6, MAKEFOURCC('v','p','6','1'), NULL },
{ &MEDIASUBTYPE_VP62, CODEC_ID_VP6, MAKEFOURCC('V','P','6','2'), NULL },
{ &MEDIASUBTYPE_vp62, CODEC_ID_VP6, MAKEFOURCC('v','p','6','2'), NULL },
{ &MEDIASUBTYPE_VP6A, CODEC_ID_VP6A, MAKEFOURCC('V','P','6','A'), NULL },
{ &MEDIASUBTYPE_vp6a, CODEC_ID_VP6A, MAKEFOURCC('v','p','6','a'), NULL },
// Xvid
{ &MEDIASUBTYPE_XVID, CODEC_ID_MPEG4, MAKEFOURCC('X','V','I','D'), NULL },
{ &MEDIASUBTYPE_xvid, CODEC_ID_MPEG4, MAKEFOURCC('x','v','i','d'), NULL },
{ &MEDIASUBTYPE_XVIX, CODEC_ID_MPEG4, MAKEFOURCC('X','V','I','X'), NULL },
{ &MEDIASUBTYPE_xvix, CODEC_ID_MPEG4, MAKEFOURCC('x','v','i','x'), NULL },
// DivX
{ &MEDIASUBTYPE_DX50, CODEC_ID_MPEG4, MAKEFOURCC('D','X','5','0'), NULL },
{ &MEDIASUBTYPE_dx50, CODEC_ID_MPEG4, MAKEFOURCC('d','x','5','0'), NULL },
{ &MEDIASUBTYPE_DIVX, CODEC_ID_MPEG4, MAKEFOURCC('D','I','V','X'), NULL },
{ &MEDIASUBTYPE_divx, CODEC_ID_MPEG4, MAKEFOURCC('d','i','v','x'), NULL },
// WMV1/2/3
{ &MEDIASUBTYPE_WMV1, CODEC_ID_WMV1, MAKEFOURCC('W','M','V','1'), NULL },
{ &MEDIASUBTYPE_wmv1, CODEC_ID_WMV1, MAKEFOURCC('w','m','v','1'), NULL },
{ &MEDIASUBTYPE_WMV2, CODEC_ID_WMV2, MAKEFOURCC('W','M','V','2'), NULL },
{ &MEDIASUBTYPE_wmv2, CODEC_ID_WMV2, MAKEFOURCC('w','m','v','2'), NULL },
{ &MEDIASUBTYPE_WMV3, CODEC_ID_WMV3, MAKEFOURCC('W','M','V','3'), NULL },
{ &MEDIASUBTYPE_wmv3, CODEC_ID_WMV3, MAKEFOURCC('w','m','v','3'), NULL },
// Mpeg 2
{ &MEDIASUBTYPE_MPEG2_VIDEO, CODEC_ID_MPEG2VIDEO, MAKEFOURCC('M','P','G','2'), &DXVA_Mpeg2 },
// MSMPEG-4
{ &MEDIASUBTYPE_DIV3, CODEC_ID_MSMPEG4V3, MAKEFOURCC('D','I','V','3'), NULL },
{ &MEDIASUBTYPE_div3, CODEC_ID_MSMPEG4V3, MAKEFOURCC('d','i','v','3'), NULL },
{ &MEDIASUBTYPE_DVX3, CODEC_ID_MSMPEG4V3, MAKEFOURCC('D','V','X','3'), NULL },
{ &MEDIASUBTYPE_dvx3, CODEC_ID_MSMPEG4V3, MAKEFOURCC('d','v','x','3'), NULL },
{ &MEDIASUBTYPE_MP43, CODEC_ID_MSMPEG4V3, MAKEFOURCC('M','P','4','3'), NULL },
{ &MEDIASUBTYPE_mp43, CODEC_ID_MSMPEG4V3, MAKEFOURCC('m','p','4','3'), NULL },
{ &MEDIASUBTYPE_COL1, CODEC_ID_MSMPEG4V3, MAKEFOURCC('C','O','L','1'), NULL },
{ &MEDIASUBTYPE_col1, CODEC_ID_MSMPEG4V3, MAKEFOURCC('c','o','l','1'), NULL },
{ &MEDIASUBTYPE_DIV4, CODEC_ID_MSMPEG4V3, MAKEFOURCC('D','I','V','4'), NULL },
{ &MEDIASUBTYPE_div4, CODEC_ID_MSMPEG4V3, MAKEFOURCC('d','i','v','4'), NULL },
{ &MEDIASUBTYPE_DIV5, CODEC_ID_MSMPEG4V3, MAKEFOURCC('D','I','V','5'), NULL },
{ &MEDIASUBTYPE_div5, CODEC_ID_MSMPEG4V3, MAKEFOURCC('d','i','v','5'), NULL },
{ &MEDIASUBTYPE_DIV6, CODEC_ID_MSMPEG4V3, MAKEFOURCC('D','I','V','6'), NULL },
{ &MEDIASUBTYPE_div6, CODEC_ID_MSMPEG4V3, MAKEFOURCC('d','i','v','6'), NULL },
{ &MEDIASUBTYPE_AP41, CODEC_ID_MSMPEG4V3, MAKEFOURCC('A','P','4','1'), NULL },
{ &MEDIASUBTYPE_ap41, CODEC_ID_MSMPEG4V3, MAKEFOURCC('a','p','4','1'), NULL },
{ &MEDIASUBTYPE_MPG3, CODEC_ID_MSMPEG4V3, MAKEFOURCC('M','P','G','3'), NULL },
{ &MEDIASUBTYPE_mpg3, CODEC_ID_MSMPEG4V3, MAKEFOURCC('m','p','g','3'), NULL },
{ &MEDIASUBTYPE_DIV2, CODEC_ID_MSMPEG4V2, MAKEFOURCC('D','I','V','2'), NULL },
{ &MEDIASUBTYPE_div2, CODEC_ID_MSMPEG4V2, MAKEFOURCC('d','i','v','2'), NULL },
{ &MEDIASUBTYPE_MP42, CODEC_ID_MSMPEG4V2, MAKEFOURCC('M','P','4','2'), NULL },
{ &MEDIASUBTYPE_mp42, CODEC_ID_MSMPEG4V2, MAKEFOURCC('m','p','4','2'), NULL },
{ &MEDIASUBTYPE_MPG4, CODEC_ID_MSMPEG4V1, MAKEFOURCC('M','P','G','4'), NULL },
{ &MEDIASUBTYPE_mpg4, CODEC_ID_MSMPEG4V1, MAKEFOURCC('m','p','g','4'), NULL },
{ &MEDIASUBTYPE_DIV1, CODEC_ID_MSMPEG4V1, MAKEFOURCC('D','I','V','1'), NULL },
{ &MEDIASUBTYPE_div1, CODEC_ID_MSMPEG4V1, MAKEFOURCC('d','i','v','1'), NULL },
{ &MEDIASUBTYPE_MP41, CODEC_ID_MSMPEG4V1, MAKEFOURCC('M','P','4','1'), NULL },
{ &MEDIASUBTYPE_mp41, CODEC_ID_MSMPEG4V1, MAKEFOURCC('m','p','4','1'), NULL },
// AMV Video
{ &MEDIASUBTYPE_AMVV, CODEC_ID_AMV, MAKEFOURCC('A','M','V','V'), NULL },
#endif /* INCLUDE_MPC_VIDEO_DECODER */
// H264/AVC
{ &MEDIASUBTYPE_H264, CODEC_ID_H264, MAKEFOURCC('H','2','6','4'), &DXVA_H264 },
{ &MEDIASUBTYPE_h264, CODEC_ID_H264, MAKEFOURCC('h','2','6','4'), &DXVA_H264 },
{ &MEDIASUBTYPE_X264, CODEC_ID_H264, MAKEFOURCC('X','2','6','4'), &DXVA_H264 },
{ &MEDIASUBTYPE_x264, CODEC_ID_H264, MAKEFOURCC('x','2','6','4'), &DXVA_H264 },
{ &MEDIASUBTYPE_VSSH, CODEC_ID_H264, MAKEFOURCC('V','S','S','H'), &DXVA_H264 },
{ &MEDIASUBTYPE_vssh, CODEC_ID_H264, MAKEFOURCC('v','s','s','h'), &DXVA_H264 },
{ &MEDIASUBTYPE_DAVC, CODEC_ID_H264, MAKEFOURCC('D','A','V','C'), &DXVA_H264 },
{ &MEDIASUBTYPE_davc, CODEC_ID_H264, MAKEFOURCC('d','a','v','c'), &DXVA_H264 },
{ &MEDIASUBTYPE_PAVC, CODEC_ID_H264, MAKEFOURCC('P','A','V','C'), &DXVA_H264 },
{ &MEDIASUBTYPE_pavc, CODEC_ID_H264, MAKEFOURCC('p','a','v','c'), &DXVA_H264 },
{ &MEDIASUBTYPE_AVC1, CODEC_ID_H264, MAKEFOURCC('A','V','C','1'), &DXVA_H264 },
{ &MEDIASUBTYPE_avc1, CODEC_ID_H264, MAKEFOURCC('a','v','c','1'), &DXVA_H264 },
{ &MEDIASUBTYPE_H264_bis, CODEC_ID_H264, MAKEFOURCC('a','v','c','1'), &DXVA_H264 },
#if INCLUDE_MPC_VIDEO_DECODER
// SVQ3
{ &MEDIASUBTYPE_SVQ3, CODEC_ID_SVQ3, MAKEFOURCC('S','V','Q','3'), NULL },
// SVQ1
{ &MEDIASUBTYPE_SVQ1, CODEC_ID_SVQ1, MAKEFOURCC('S','V','Q','1'), NULL },
// H263
{ &MEDIASUBTYPE_H263, CODEC_ID_H263, MAKEFOURCC('H','2','6','3'), NULL },
{ &MEDIASUBTYPE_h263, CODEC_ID_H263, MAKEFOURCC('h','2','6','3'), NULL },
{ &MEDIASUBTYPE_S263, CODEC_ID_H263, MAKEFOURCC('S','2','6','3'), NULL },
{ &MEDIASUBTYPE_s263, CODEC_ID_H263, MAKEFOURCC('s','2','6','3'), NULL },
// Real video
{ &MEDIASUBTYPE_RV10, CODEC_ID_RV10, MAKEFOURCC('R','V','1','0'), NULL },
{ &MEDIASUBTYPE_RV20, CODEC_ID_RV20, MAKEFOURCC('R','V','2','0'), NULL },
{ &MEDIASUBTYPE_RV30, CODEC_ID_RV30, MAKEFOURCC('R','V','3','0'), NULL },
{ &MEDIASUBTYPE_RV40, CODEC_ID_RV40, MAKEFOURCC('R','V','4','0'), NULL },
// Theora
{ &MEDIASUBTYPE_THEORA, CODEC_ID_THEORA, MAKEFOURCC('T','H','E','O'), NULL },
{ &MEDIASUBTYPE_theora, CODEC_ID_THEORA, MAKEFOURCC('t','h','e','o'), NULL },
#endif /* INCLUDE_MPC_VIDEO_DECODER */
// WVC1
{ &MEDIASUBTYPE_WVC1, CODEC_ID_VC1, MAKEFOURCC('W','V','C','1'), &DXVA_VC1 },
{ &MEDIASUBTYPE_wvc1, CODEC_ID_VC1, MAKEFOURCC('w','v','c','1'), &DXVA_VC1 },
#if INCLUDE_MPC_VIDEO_DECODER
// Other MPEG-4
{ &MEDIASUBTYPE_MP4V, CODEC_ID_MPEG4, MAKEFOURCC('M','P','4','V'), NULL },
{ &MEDIASUBTYPE_mp4v, CODEC_ID_MPEG4, MAKEFOURCC('m','p','4','v'), NULL },
{ &MEDIASUBTYPE_M4S2, CODEC_ID_MPEG4, MAKEFOURCC('M','4','S','2'), NULL },
{ &MEDIASUBTYPE_m4s2, CODEC_ID_MPEG4, MAKEFOURCC('m','4','s','2'), NULL },
{ &MEDIASUBTYPE_MP4S, CODEC_ID_MPEG4, MAKEFOURCC('M','P','4','S'), NULL },
{ &MEDIASUBTYPE_mp4s, CODEC_ID_MPEG4, MAKEFOURCC('m','p','4','s'), NULL },
{ &MEDIASUBTYPE_3IV1, CODEC_ID_MPEG4, MAKEFOURCC('3','I','V','1'), NULL },
{ &MEDIASUBTYPE_3iv1, CODEC_ID_MPEG4, MAKEFOURCC('3','i','v','1'), NULL },
{ &MEDIASUBTYPE_3IV2, CODEC_ID_MPEG4, MAKEFOURCC('3','I','V','2'), NULL },
{ &MEDIASUBTYPE_3iv2, CODEC_ID_MPEG4, MAKEFOURCC('3','i','v','2'), NULL },
{ &MEDIASUBTYPE_3IVX, CODEC_ID_MPEG4, MAKEFOURCC('3','I','V','X'), NULL },
{ &MEDIASUBTYPE_3ivx, CODEC_ID_MPEG4, MAKEFOURCC('3','i','v','x'), NULL },
{ &MEDIASUBTYPE_BLZ0, CODEC_ID_MPEG4, MAKEFOURCC('B','L','Z','0'), NULL },
{ &MEDIASUBTYPE_blz0, CODEC_ID_MPEG4, MAKEFOURCC('b','l','z','0'), NULL },
{ &MEDIASUBTYPE_DM4V, CODEC_ID_MPEG4, MAKEFOURCC('D','M','4','V'), NULL },
{ &MEDIASUBTYPE_dm4v, CODEC_ID_MPEG4, MAKEFOURCC('d','m','4','v'), NULL },
{ &MEDIASUBTYPE_FFDS, CODEC_ID_MPEG4, MAKEFOURCC('F','F','D','S'), NULL },
{ &MEDIASUBTYPE_ffds, CODEC_ID_MPEG4, MAKEFOURCC('f','f','d','s'), NULL },
{ &MEDIASUBTYPE_FVFW, CODEC_ID_MPEG4, MAKEFOURCC('F','V','F','W'), NULL },
{ &MEDIASUBTYPE_fvfw, CODEC_ID_MPEG4, MAKEFOURCC('f','v','f','w'), NULL },
{ &MEDIASUBTYPE_DXGM, CODEC_ID_MPEG4, MAKEFOURCC('D','X','G','M'), NULL },
{ &MEDIASUBTYPE_dxgm, CODEC_ID_MPEG4, MAKEFOURCC('d','x','g','m'), NULL },
{ &MEDIASUBTYPE_FMP4, CODEC_ID_MPEG4, MAKEFOURCC('F','M','P','4'), NULL },
{ &MEDIASUBTYPE_fmp4, CODEC_ID_MPEG4, MAKEFOURCC('f','m','p','4'), NULL },
{ &MEDIASUBTYPE_HDX4, CODEC_ID_MPEG4, MAKEFOURCC('H','D','X','4'), NULL },
{ &MEDIASUBTYPE_hdx4, CODEC_ID_MPEG4, MAKEFOURCC('h','d','x','4'), NULL },
{ &MEDIASUBTYPE_LMP4, CODEC_ID_MPEG4, MAKEFOURCC('L','M','P','4'), NULL },
{ &MEDIASUBTYPE_lmp4, CODEC_ID_MPEG4, MAKEFOURCC('l','m','p','4'), NULL },
{ &MEDIASUBTYPE_NDIG, CODEC_ID_MPEG4, MAKEFOURCC('N','D','I','G'), NULL },
{ &MEDIASUBTYPE_ndig, CODEC_ID_MPEG4, MAKEFOURCC('n','d','i','g'), NULL },
{ &MEDIASUBTYPE_RMP4, CODEC_ID_MPEG4, MAKEFOURCC('R','M','P','4'), NULL },
{ &MEDIASUBTYPE_rmp4, CODEC_ID_MPEG4, MAKEFOURCC('r','m','p','4'), NULL },
{ &MEDIASUBTYPE_SMP4, CODEC_ID_MPEG4, MAKEFOURCC('S','M','P','4'), NULL },
{ &MEDIASUBTYPE_smp4, CODEC_ID_MPEG4, MAKEFOURCC('s','m','p','4'), NULL },
{ &MEDIASUBTYPE_SEDG, CODEC_ID_MPEG4, MAKEFOURCC('S','E','D','G'), NULL },
{ &MEDIASUBTYPE_sedg, CODEC_ID_MPEG4, MAKEFOURCC('s','e','d','g'), NULL },
{ &MEDIASUBTYPE_UMP4, CODEC_ID_MPEG4, MAKEFOURCC('U','M','P','4'), NULL },
{ &MEDIASUBTYPE_ump4, CODEC_ID_MPEG4, MAKEFOURCC('u','m','p','4'), NULL },
{ &MEDIASUBTYPE_WV1F, CODEC_ID_MPEG4, MAKEFOURCC('W','V','1','F'), NULL },
{ &MEDIASUBTYPE_wv1f, CODEC_ID_MPEG4, MAKEFOURCC('w','v','1','f'), NULL },
#endif /* INCLUDE_MPC_VIDEO_DECODER */
};
/* Important: the order should be exactly the same as in ffCodecs[] */
const AMOVIESETUP_MEDIATYPE CMPCVideoDecFilter::sudPinTypesIn[] =
{
#if INCLUDE_MPC_VIDEO_DECODER
// Flash video
{ &MEDIATYPE_Video, &MEDIASUBTYPE_FLV1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_flv1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_FLV4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_flv4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_VP6F },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_vp6f },
// VP5
{ &MEDIATYPE_Video, &MEDIASUBTYPE_VP50 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_vp50 },
// VP6
{ &MEDIATYPE_Video, &MEDIASUBTYPE_VP60 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_vp60 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_VP61 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_vp61 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_VP62 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_vp62 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_VP6A },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_vp6a },
// Xvid
{ &MEDIATYPE_Video, &MEDIASUBTYPE_XVID },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_xvid },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_XVIX },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_xvix },
// DivX
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DX50 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_dx50 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DIVX },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_divx },
// WMV1/2/3
{ &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_wmv1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_WMV2 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_wmv2 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_WMV3 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_wmv3 },
// Mpeg 2
{ &MEDIATYPE_Video, &MEDIASUBTYPE_MPEG2_VIDEO },
// MSMPEG-4
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DIV3 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_div3 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DVX3 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_dvx3 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_MP43 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_mp43 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_COL1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_col1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DIV4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_div4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DIV5 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_div5 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DIV6 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_div6 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_AP41 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_ap41 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_MPG3 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_mpg3 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DIV2 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_div2 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_MP42 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_mp42 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_MPG4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_mpg4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DIV1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_div1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_MP41 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_mp41 },
// AMV Video
{ &MEDIATYPE_Video, &MEDIASUBTYPE_AMVV },
#endif /* INCLUDE_MPC_VIDEO_DECODER */
// H264/AVC
{ &MEDIATYPE_Video, &MEDIASUBTYPE_H264 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_h264 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_X264 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_x264 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_VSSH },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_vssh },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DAVC },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_davc },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_PAVC },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_pavc },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_AVC1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_avc1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_H264_bis },
#if INCLUDE_MPC_VIDEO_DECODER
// SVQ3
{ &MEDIATYPE_Video, &MEDIASUBTYPE_SVQ3 },
// SVQ1
{ &MEDIATYPE_Video, &MEDIASUBTYPE_SVQ1 },
// H263
{ &MEDIATYPE_Video, &MEDIASUBTYPE_H263 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_h263 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_S263 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_s263 },
// Real video
{ &MEDIATYPE_Video, &MEDIASUBTYPE_RV10 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_RV20 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_RV30 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_RV40 },
// Theora
{ &MEDIATYPE_Video, &MEDIASUBTYPE_THEORA },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_theora },
#endif /* INCLUDE_MPC_VIDEO_DECODER */
// VC1
{ &MEDIATYPE_Video, &MEDIASUBTYPE_WVC1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_wvc1 },
#if INCLUDE_MPC_VIDEO_DECODER
// IMPORTANT : some of the last MediaTypes present in next group may be not available in
// the standalone filter (workaround to prevent GraphEdit crash).
// Other MPEG-4
{ &MEDIATYPE_Video, &MEDIASUBTYPE_MP4V },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_mp4v },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_M4S2 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_m4s2 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_MP4S },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_mp4s },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_3IV1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_3iv1 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_3IV2 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_3iv2 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_3IVX },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_3ivx },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_BLZ0 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_blz0 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DM4V },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_dm4v },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_FFDS },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_ffds },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_FVFW },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_fvfw },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_DXGM },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_dxgm },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_FMP4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_fmp4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_HDX4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_hdx4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_LMP4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_lmp4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_NDIG },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_ndig },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_RMP4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_rmp4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_SMP4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_smp4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_SEDG },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_sedg },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_UMP4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_ump4 },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_WV1F },
{ &MEDIATYPE_Video, &MEDIASUBTYPE_wv1f }
#endif /* INCLUDE_MPC_VIDEO_DECODER */
};
const int CMPCVideoDecFilter::sudPinTypesInCount = countof(CMPCVideoDecFilter::sudPinTypesIn);
UINT CMPCVideoDecFilter::FFmpegFilters = 0xFFFFFFFF;
UINT CMPCVideoDecFilter::DXVAFilters = 0xFFFFFFFF;
bool CMPCVideoDecFilter::m_ref_frame_count_check_skip = false;
const AMOVIESETUP_MEDIATYPE CMPCVideoDecFilter::sudPinTypesOut[] =
{
{&MEDIATYPE_Video, &MEDIASUBTYPE_NV12},
{&MEDIATYPE_Video, &MEDIASUBTYPE_NV24}
};
const int CMPCVideoDecFilter::sudPinTypesOutCount = countof(CMPCVideoDecFilter::sudPinTypesOut);
BOOL CALLBACK EnumFindProcessWnd (HWND hwnd, LPARAM lParam)
{
DWORD procid = 0;
TCHAR WindowClass [40];
GetWindowThreadProcessId (hwnd, &procid);
GetClassName (hwnd, WindowClass, countof(WindowClass));
if (procid == GetCurrentProcessId() && _tcscmp (WindowClass, _T("MediaPlayerClassicW")) == 0)
{
HWND* pWnd = (HWND*) lParam;
*pWnd = hwnd;
return FALSE;
}
return TRUE;
}
CMPCVideoDecFilter::CMPCVideoDecFilter(LPUNKNOWN lpunk, HRESULT* phr)
: CBaseVideoFilter(NAME("MPC - Video decoder"), lpunk, phr, __uuidof(this))
{
HWND hWnd = NULL;
for (int i=0; iGetProcessorNumber();
m_nDiscardMode = AVDISCARD_DEFAULT;
m_nErrorRecognition = FF_ER_CAREFUL;
m_nIDCTAlgo = FF_IDCT_AUTO;
m_bDXVACompatible = true;
m_pFFBuffer = NULL;
m_nFFBufferSize = 0;
ResetBuffer();
m_nWidth = 0;
m_nHeight = 0;
m_pSwsContext = NULL;
m_bUseDXVA = true;
m_bUseFFmpeg = true;
m_nDXVAMode = MODE_SOFTWARE;
m_pDXVADecoder = NULL;
m_pVideoOutputFormat = NULL;
m_nVideoOutputCount = 0;
m_hDevice = INVALID_HANDLE_VALUE;
m_nARMode = 1;
m_nDXVACheckCompatibility = 0;
m_nPosB = 1;
m_sar.SetSize(1,1);
CRegKey key;
if(ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Gabest\\Filters\\MPC Video Decoder"), KEY_READ))
{
DWORD dw;
if(ERROR_SUCCESS == key.QueryDWORDValue(_T("ThreadNumber"), dw)) m_nThreadNumber = dw;
if(ERROR_SUCCESS == key.QueryDWORDValue(_T("DiscardMode"), dw)) m_nDiscardMode = dw;
if(ERROR_SUCCESS == key.QueryDWORDValue(_T("ErrorRecognition"), dw)) m_nErrorRecognition = dw;
if(ERROR_SUCCESS == key.QueryDWORDValue(_T("IDCTAlgo"), dw)) m_nIDCTAlgo = dw;
if(ERROR_SUCCESS == key.QueryDWORDValue(_T("ActiveCodecs"), dw)) m_nActiveCodecs = dw;
if(ERROR_SUCCESS == key.QueryDWORDValue(_T("ARMode"), dw)) m_nARMode = dw;
if(ERROR_SUCCESS == key.QueryDWORDValue(_T("DXVACheckCompatibility"), dw)) m_nDXVACheckCompatibility = dw;
}
if(m_nDXVACheckCompatibility>3) m_nDXVACheckCompatibility = 0;
ff_avcodec_default_get_buffer = avcodec_default_get_buffer;
ff_avcodec_default_release_buffer = avcodec_default_release_buffer;
ff_avcodec_default_reget_buffer = avcodec_default_reget_buffer;
avcodec_init();
avcodec_register_all();
av_log_set_callback(LogLibAVCodec);
#if INCLUDE_MPC_VIDEO_DECODER
init_libvo();
#endif
EnumWindows(EnumFindProcessWnd, (LPARAM)&hWnd);
DetectVideoCard(hWnd);
#ifdef _DEBUG
// Check codec definition table
int nCodecs = countof(ffCodecs);
int nPinTypes = countof(sudPinTypesIn);
ASSERT (nCodecs == nPinTypes);
for (int i=0; iGetAdapterCount(); adp < num_adp; ++adp)
{
HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp);
if(hAdpMon == hMonitor) return adp;
}
return D3DADAPTER_DEFAULT;
}
void CMPCVideoDecFilter::DetectVideoCard(HWND hWnd)
{
IDirect3D9* pD3D9;
m_nPCIVendor = 0;
m_nPCIDevice = 0;
m_VideoDriverVersion.HighPart = 0;
m_VideoDriverVersion.LowPart = 0;
if (pD3D9 = Direct3DCreate9(D3D_SDK_VERSION))
{
D3DADAPTER_IDENTIFIER9 adapterIdentifier;
if (pD3D9->GetAdapterIdentifier(GetAdapter(pD3D9, hWnd), 0, &adapterIdentifier) == S_OK)
{
m_nPCIVendor = adapterIdentifier.VendorId;
m_nPCIDevice = adapterIdentifier.DeviceId;
m_VideoDriverVersion = adapterIdentifier.DriverVersion;
m_strDeviceDescription = adapterIdentifier.Description;
m_strDeviceDescription.AppendFormat (_T(" (%d)"), m_nPCIVendor);
}
pD3D9->Release();
}
}
CMPCVideoDecFilter::~CMPCVideoDecFilter()
{
Cleanup();
SAFE_DELETE(m_pCpuId);
}
inline int LNKO(int a, int b)
{
if(a == 0 || b == 0)
return(1);
while(a != b)
{
if(a < b) b -= a;
else if(a > b) a -= b;
}
return(a);
}
bool CMPCVideoDecFilter::IsVideoInterlaced()
{
// NOT A BUG : always tell DirectShow it's interlaced (progressive flags set in
// SetTypeSpecificFlags function)
return true;
};
void CMPCVideoDecFilter::UpdateFrameTime (REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop)
{
if (rtStart == _I64_MIN)
{
// If reference time has not been set by splitter, extrapolate start time
// from last known start time already delivered
rtStart = m_rtLastStart + m_rtAvrTimePerFrame*m_nCountEstimated;
m_nCountEstimated++;
}
else
{
// Known start time, set as new reference
m_rtLastStart = rtStart;
m_nCountEstimated = 1;
}
rtStop = rtStart + m_rtAvrTimePerFrame;
}
void CMPCVideoDecFilter::GetOutputSize(int& w, int& h, int& arx, int& ary, int &RealWidth, int &RealHeight)
{
#if 1
RealWidth = m_nWidth;
RealHeight = m_nHeight;
w = PictWidthRounded();
h = PictHeightRounded();
#else
if (m_nDXVAMode == MODE_SOFTWARE)
{
w = m_nWidth;
h = m_nHeight;
}
else
{
// DXVA surface are multiple of 16 pixels!
w = PictWidthRounded();
h = PictHeightRounded();
}
#endif
}
int CMPCVideoDecFilter::PictWidth()
{
return m_nWidth;
}
int CMPCVideoDecFilter::PictHeight()
{
return m_nHeight;
}
int CMPCVideoDecFilter::PictWidthRounded()
{
// Picture height should be rounded to 16 for DXVA
return ((m_nWidth + 15) / 16) * 16;
}
int CMPCVideoDecFilter::PictHeightRounded()
{
// Picture height should be rounded to 16 for DXVA
return ((m_nHeight + 15) / 16) * 16;
}
int CMPCVideoDecFilter::FindCodec(const CMediaType* mtIn)
{
for (int i=0; isubtype == *ffCodecs[i].clsMinorType)
{
#ifndef REGISTER_FILTER
switch (ffCodecs[i].nFFCodec)
{
case CODEC_ID_H264 :
#if INTERNAL_DECODER_H264_DXVA
m_bUseDXVA = (DXVAFilters & 1) != 0;
#else
m_bUseDXVA = false;
#endif
#if INTERNAL_DECODER_H264
m_bUseFFmpeg = (FFmpegFilters & 1) != 0;
#else
m_bUseFFmpeg = false;
#endif
break;
case CODEC_ID_VC1 :
#if INTERNAL_DECODER_VC1_DXVA
m_bUseDXVA = (DXVAFilters & 2) != 0;
#else
m_bUseDXVA = false;
#endif
#if INTERNAL_DECODER_VC1
m_bUseFFmpeg = (FFmpegFilters & 2) != 0;
#else
m_bUseFFmpeg = false;
#endif
break;
case CODEC_ID_MPEG2VIDEO :
#if INTERNAL_DECODER_MPEG2_DXVA
m_bUseDXVA = true;
#endif
m_bUseFFmpeg = false; // No Mpeg2 software support with ffmpeg!
break;
default :
m_bUseDXVA = false;
}
return ((m_bUseDXVA || m_bUseFFmpeg) ? i : -1);
#else
bool bCodecActivated = false;
switch (ffCodecs[i].nFFCodec)
{
case CODEC_ID_FLV1 :
case CODEC_ID_VP6F :
bCodecActivated = (m_nActiveCodecs & MPCVD_FLASH) != 0;
break;
case CODEC_ID_MPEG4 :
if ((*ffCodecs[i].clsMinorType == MEDIASUBTYPE_XVID) ||
(*ffCodecs[i].clsMinorType == MEDIASUBTYPE_xvid) ||
(*ffCodecs[i].clsMinorType == MEDIASUBTYPE_XVIX) ||
(*ffCodecs[i].clsMinorType == MEDIASUBTYPE_xvix) )
{
bCodecActivated = (m_nActiveCodecs & MPCVD_XVID) != 0;
}
else if ((*ffCodecs[i].clsMinorType == MEDIASUBTYPE_DX50) ||
(*ffCodecs[i].clsMinorType == MEDIASUBTYPE_dx50) ||
(*ffCodecs[i].clsMinorType == MEDIASUBTYPE_DIVX) ||
(*ffCodecs[i].clsMinorType == MEDIASUBTYPE_divx) )
{
bCodecActivated = (m_nActiveCodecs & MPCVD_DIVX) != 0;
}
break;
case CODEC_ID_WMV1 :
case CODEC_ID_WMV2 :
case CODEC_ID_WMV3 :
bCodecActivated = (m_nActiveCodecs & MPCVD_WMV) != 0;
break;
case CODEC_ID_MSMPEG4V3 :
case CODEC_ID_MSMPEG4V2 :
case CODEC_ID_MSMPEG4V1 :
bCodecActivated = (m_nActiveCodecs & MPCVD_MSMPEG4) != 0;
break;
case CODEC_ID_H264 :
m_bUseDXVA = (m_nActiveCodecs & MPCVD_H264_DXVA) != 0;
m_bUseFFmpeg = (m_nActiveCodecs & MPCVD_H264) != 0;
bCodecActivated = m_bUseDXVA || m_bUseFFmpeg;
break;
case CODEC_ID_SVQ3 :
case CODEC_ID_SVQ1 :
bCodecActivated = (m_nActiveCodecs & MPCVD_SVQ3) != 0;
break;
case CODEC_ID_H263 :
bCodecActivated = (m_nActiveCodecs & MPCVD_H263) != 0;
break;
case CODEC_ID_THEORA :
bCodecActivated = (m_nActiveCodecs & MPCVD_THEORA) != 0;
break;
case CODEC_ID_VC1 :
m_bUseDXVA = (m_nActiveCodecs & MPCVD_VC1_DXVA) != 0;
m_bUseFFmpeg = (m_nActiveCodecs & MPCVD_VC1) != 0;
bCodecActivated = m_bUseDXVA || m_bUseFFmpeg;
break;
case CODEC_ID_AMV :
bCodecActivated = (m_nActiveCodecs & MPCVD_AMVV) != 0;
break;
case CODEC_ID_VP5 :
case CODEC_ID_VP6 :
case CODEC_ID_VP6A :
bCodecActivated = (m_nActiveCodecs & MPCVD_VP6) != 0;
break;
}
return (bCodecActivated ? i : -1);
#endif
}
return -1;
}
void CMPCVideoDecFilter::Cleanup()
{
SAFE_DELETE (m_pDXVADecoder);
// Release FFMpeg
if (m_pAVCtx)
{
if (m_pAVCtx->intra_matrix) free(m_pAVCtx->intra_matrix);
if (m_pAVCtx->inter_matrix) free(m_pAVCtx->inter_matrix);
if (m_pAVCtx->extradata) free((unsigned char*)m_pAVCtx->extradata);
if (m_pFFBuffer) free(m_pFFBuffer);
if (m_pAVCtx->slice_offset) av_free(m_pAVCtx->slice_offset);
if (m_pAVCtx->codec) avcodec_close(m_pAVCtx);
// Free thread resource if necessary
FFSetThreadNumber (m_pAVCtx, 0);
av_free(m_pAVCtx);
}
if (m_pFrame) av_free(m_pFrame);
#if INCLUDE_MPC_VIDEO_DECODER
if (m_pSwsContext)
{
sws_freeContext(m_pSwsContext);
m_pSwsContext = NULL;
}
#endif /* INCLUDE_MPC_VIDEO_DECODER */
m_pAVCodec = NULL;
m_pAVCtx = NULL;
m_pFrame = NULL;
m_pFFBuffer = NULL;
m_nFFBufferSize = 0;
m_nFFBufferPos = 0;
m_nFFPicEnd = INT_MIN;
m_nCodecNb = -1;
SAFE_DELETE_ARRAY (m_pVideoOutputFormat);
// Release DXVA ressources
if (m_hDevice != INVALID_HANDLE_VALUE)
{
m_pDeviceManager->CloseDeviceHandle(m_hDevice);
m_hDevice = INVALID_HANDLE_VALUE;
}
m_pDeviceManager = NULL;
m_pDecoderService = NULL;
m_pDecoderRenderTarget = NULL;
}
void CMPCVideoDecFilter::CalcAvgTimePerFrame()
{
CMediaType &mt = m_pInput->CurrentMediaType();
if (mt.formattype==FORMAT_VideoInfo)
m_rtAvrTimePerFrame = ((VIDEOINFOHEADER*)mt.pbFormat)->AvgTimePerFrame;
else if (mt.formattype==FORMAT_VideoInfo2)
m_rtAvrTimePerFrame = ((VIDEOINFOHEADER2*)mt.pbFormat)->AvgTimePerFrame;
else if (mt.formattype==FORMAT_MPEGVideo)
m_rtAvrTimePerFrame = ((MPEG1VIDEOINFO*)mt.pbFormat)->hdr.AvgTimePerFrame;
else if (mt.formattype==FORMAT_MPEG2Video)
m_rtAvrTimePerFrame = ((MPEG2VIDEOINFO*)mt.pbFormat)->hdr.AvgTimePerFrame;
else
{
ASSERT (FALSE);
m_rtAvrTimePerFrame = 1;
}
m_rtAvrTimePerFrame = max (1, m_rtAvrTimePerFrame);
}
void CMPCVideoDecFilter::LogLibAVCodec(void* par,int level,const char *fmt,va_list valist)
{
#ifdef _DEBUG
char Msg [500];
vsnprintf_s (Msg, sizeof(Msg), _TRUNCATE, fmt, valist);
TRACE("AVLIB : %s", Msg);
#endif
}
void CMPCVideoDecFilter::OnGetBuffer(AVFrame *pic)
{
// Callback from FFMpeg to store Ref Time in frame (needed to have correct rtStart after avcodec_decode_video calls)
// pic->rtStart = m_rtStart;
}
STDMETHODIMP CMPCVideoDecFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
return
QI(IMPCVideoDecFilter)
QI(ISpecifyPropertyPages)
QI(ISpecifyPropertyPages2)
__super::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT CMPCVideoDecFilter::CheckInputType(const CMediaType* mtIn)
{
for (int i=0; imajortype == *sudPinTypesIn[i].clsMajorType) &&
(mtIn->subtype == *sudPinTypesIn[i].clsMinorType))
return S_OK;
}
return VFW_E_TYPE_NOT_ACCEPTED;
}
bool CMPCVideoDecFilter::IsMultiThreadSupported(int nCodec)
{
return (nCodec==CODEC_ID_H264);
}
HRESULT CMPCVideoDecFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt)
{
int nNewCodec;
if (direction == PINDIR_INPUT)
{
nNewCodec = FindCodec(pmt);
if (nNewCodec == -1) return VFW_E_TYPE_NOT_ACCEPTED;
if (nNewCodec != m_nCodecNb)
{
m_nCodecNb = nNewCodec;
m_bReorderBFrame = true;
m_pAVCodec = avcodec_find_decoder(ffCodecs[nNewCodec].nFFCodec);
CheckPointer (m_pAVCodec, VFW_E_UNSUPPORTED_VIDEO);
m_pAVCtx = avcodec_alloc_context();
CheckPointer (m_pAVCtx, E_POINTER);
if ((m_nThreadNumber > 1) && IsMultiThreadSupported (ffCodecs[m_nCodecNb].nFFCodec))
FFSetThreadNumber(m_pAVCtx, m_nThreadNumber);
m_pFrame = avcodec_alloc_frame();
CheckPointer (m_pFrame, E_POINTER);
if(pmt->formattype == FORMAT_VideoInfo)
{
VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat;
m_pAVCtx->width = vih->bmiHeader.biWidth;
m_pAVCtx->height = abs(vih->bmiHeader.biHeight);
m_pAVCtx->codec_tag = vih->bmiHeader.biCompression;
}
else if(pmt->formattype == FORMAT_VideoInfo2)
{
VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)pmt->pbFormat;
m_pAVCtx->width = vih2->bmiHeader.biWidth;
m_pAVCtx->height = abs(vih2->bmiHeader.biHeight);
m_pAVCtx->codec_tag = vih2->bmiHeader.biCompression;
}
else if(pmt->formattype == FORMAT_MPEGVideo)
{
MPEG1VIDEOINFO* mpgv = (MPEG1VIDEOINFO*)pmt->pbFormat;
m_pAVCtx->width = mpgv->hdr.bmiHeader.biWidth;
m_pAVCtx->height = abs(mpgv->hdr.bmiHeader.biHeight);
m_pAVCtx->codec_tag = mpgv->hdr.bmiHeader.biCompression;
}
else if(pmt->formattype == FORMAT_MPEG2Video)
{
MPEG2VIDEOINFO* mpg2v = (MPEG2VIDEOINFO*)pmt->pbFormat;
m_pAVCtx->width = mpg2v->hdr.bmiHeader.biWidth;
m_pAVCtx->height = abs(mpg2v->hdr.bmiHeader.biHeight);
m_pAVCtx->codec_tag = mpg2v->hdr.bmiHeader.biCompression;
if (mpg2v->hdr.bmiHeader.biCompression == NULL)
{
m_pAVCtx->codec_tag = pmt->subtype.Data1;
}
else if ( (m_pAVCtx->codec_tag == MAKEFOURCC('a','v','c','1')) || (m_pAVCtx->codec_tag == MAKEFOURCC('A','V','C','1')))
{
m_pAVCtx->nal_length_size = mpg2v->dwFlags;
m_bReorderBFrame = false;
}
}
m_nWidth = m_pAVCtx->width;
m_nHeight = m_pAVCtx->height;
m_pAVCtx->intra_matrix = (uint16_t*)calloc(sizeof(uint16_t),64);
m_pAVCtx->inter_matrix = (uint16_t*)calloc(sizeof(uint16_t),64);
m_pAVCtx->codec_tag = ffCodecs[nNewCodec].fourcc;
m_pAVCtx->workaround_bugs = m_nWorkaroundBug;
m_pAVCtx->error_concealment = m_nErrorConcealment;
m_pAVCtx->error_recognition = m_nErrorRecognition;
m_pAVCtx->idct_algo = m_nIDCTAlgo;
m_pAVCtx->skip_loop_filter = (AVDiscard)m_nDiscardMode;
m_pAVCtx->dsp_mask = FF_MM_FORCE | m_pCpuId->GetFeatures();
m_pAVCtx->postgain = 1.0f;
m_pAVCtx->debug_mv = 0;
#ifdef _DEBUG
//m_pAVCtx->debug = FF_DEBUG_PICT_INFO | FF_DEBUG_STARTCODE | FF_DEBUG_PTS;
#endif
m_pAVCtx->opaque = this;
m_pAVCtx->get_buffer = get_buffer;
AllocExtradata (m_pAVCtx, pmt);
ConnectTo (m_pAVCtx);
CalcAvgTimePerFrame();
if (avcodec_open(m_pAVCtx, m_pAVCodec)<0)
return VFW_E_INVALIDMEDIATYPE;
switch (ffCodecs[m_nCodecNb].nFFCodec)
{
case CODEC_ID_H264 :
int nCompat;
nCompat = FFH264CheckCompatibility (PictWidthRounded(), PictHeightRounded(), m_pAVCtx, (BYTE*)m_pAVCtx->extradata, m_pAVCtx->extradata_size, m_nPCIVendor, m_VideoDriverVersion);
if(nCompat>0)
{
switch(m_nDXVACheckCompatibility)
{
case 0 :
m_bDXVACompatible = false;
break;
case 1 :
if(nCompat == 2) m_bDXVACompatible = false;
break;
case 2 :
if(nCompat == 1) m_bDXVACompatible = false;
break;
}
}
break;
case CODEC_ID_MPEG2VIDEO :
// DSP is disable for DXVA decoding (to keep default idct_permutation)
m_pAVCtx->dsp_mask ^= FF_MM_FORCE;
break;
}
// Force single thread for DXVA !
if (IsDXVASupported())
FFSetThreadNumber(m_pAVCtx, 1);
BuildDXVAOutputFormat();
}
}
return __super::SetMediaType(direction, pmt);
}
VIDEO_OUTPUT_FORMATS DXVAFormats[] =
{
{&MEDIASUBTYPE_NV12, 1, 12, 'avxd'}, // DXVA2
{&MEDIASUBTYPE_NV12, 1, 12, 'AVXD'},
{&MEDIASUBTYPE_NV12, 1, 12, 'AVxD'},
{&MEDIASUBTYPE_NV12, 1, 12, 'AvXD'}
};
VIDEO_OUTPUT_FORMATS SoftwareFormats[] =
{
{&MEDIASUBTYPE_YV12, 3, 12, '21VY'},
{&MEDIASUBTYPE_YUY2, 1, 16, '2YUY'}, // Software
{&MEDIASUBTYPE_I420, 3, 12, '024I'},
{&MEDIASUBTYPE_IYUV, 3, 12, 'VUYI'}
};
bool CMPCVideoDecFilter::IsDXVASupported()
{
if (m_nCodecNb != -1) {
// Does the codec suppport DXVA ?
if (ffCodecs[m_nCodecNb].DXVAModes != NULL) {
// Enabled by user ?
if (m_bUseDXVA) {
// is the file compatible ?
if (m_bDXVACompatible) {
return true;
}
}
}
}
return false;
}
void CMPCVideoDecFilter::BuildDXVAOutputFormat()
{
int nPos = 0;
SAFE_DELETE_ARRAY (m_pVideoOutputFormat);
m_nVideoOutputCount = (IsDXVASupported() ? ffCodecs[m_nCodecNb].DXVAModeCount() + countof (DXVAFormats) : 0) +
(m_bUseFFmpeg ? countof(SoftwareFormats) : 0);
m_pVideoOutputFormat = DNew VIDEO_OUTPUT_FORMATS[m_nVideoOutputCount];
if (IsDXVASupported())
{
// Dynamic DXVA media types for DXVA1
for (nPos=0; nPosDecoder[nPos];
m_pVideoOutputFormat[nPos].biCompression = 'avxd';
m_pVideoOutputFormat[nPos].biBitCount = 12;
m_pVideoOutputFormat[nPos].biPlanes = 1;
}
// Static list for DXVA2
memcpy (&m_pVideoOutputFormat[nPos], DXVAFormats, sizeof(DXVAFormats));
nPos += countof (DXVAFormats);
}
// Software rendering
if (m_bUseFFmpeg)
memcpy (&m_pVideoOutputFormat[nPos], SoftwareFormats, sizeof(SoftwareFormats));
}
int CMPCVideoDecFilter::GetPicEntryNumber()
{
if (IsDXVASupported())
return ffCodecs[m_nCodecNb].DXVAModes->PicEntryNumber;
else
return 0;
}
void CMPCVideoDecFilter::GetOutputFormats (int& nNumber, VIDEO_OUTPUT_FORMATS** ppFormats)
{
nNumber = m_nVideoOutputCount;
*ppFormats = m_pVideoOutputFormat;
}
void CMPCVideoDecFilter::AllocExtradata(AVCodecContext* pAVCtx, const CMediaType* pmt)
{
const BYTE* data = NULL;
unsigned int size = 0;
if (pmt->formattype==FORMAT_VideoInfo)
{
size = pmt->cbFormat-sizeof(VIDEOINFOHEADER);
data = size?pmt->pbFormat+sizeof(VIDEOINFOHEADER):NULL;
}
else if (pmt->formattype==FORMAT_VideoInfo2)
{
size = pmt->cbFormat-sizeof(VIDEOINFOHEADER2);
data = size?pmt->pbFormat+sizeof(VIDEOINFOHEADER2):NULL;
}
else if (pmt->formattype==FORMAT_MPEGVideo)
{
MPEG1VIDEOINFO* mpeg1info = (MPEG1VIDEOINFO*)pmt->pbFormat;
if (mpeg1info->cbSequenceHeader)
{
size = mpeg1info->cbSequenceHeader;
data = mpeg1info->bSequenceHeader;
}
}
else if (pmt->formattype==FORMAT_MPEG2Video)
{
MPEG2VIDEOINFO* mpeg2info = (MPEG2VIDEOINFO*)pmt->pbFormat;
if (mpeg2info->cbSequenceHeader)
{
size = mpeg2info->cbSequenceHeader;
data = (const uint8_t*)mpeg2info->dwSequenceHeader;
}
}
else if (pmt->formattype==FORMAT_VorbisFormat2)
{
const VORBISFORMAT2 *vf2=(const VORBISFORMAT2*)pmt->pbFormat;
size=pmt->cbFormat-sizeof(VORBISFORMAT2);
data=size?pmt->pbFormat+sizeof(VORBISFORMAT2):NULL;
}
if (size)
{
pAVCtx->extradata_size = size;
pAVCtx->extradata = (const unsigned char*)calloc(1,size+FF_INPUT_BUFFER_PADDING_SIZE);
memcpy((void*)pAVCtx->extradata, data, size);
}
}
HRESULT CMPCVideoDecFilter::CompleteConnect(PIN_DIRECTION direction, IPin* pReceivePin)
{
LOG(_T("CMPCVideoDecFilter::CompleteConnect"));
if (direction==PINDIR_INPUT && m_pOutput->IsConnected())
{
ReconnectOutput (m_nWidth, m_nHeight);
}
else if (direction==PINDIR_OUTPUT)
{
if (IsDXVASupported())
{
if (m_nDXVAMode == MODE_DXVA1)
m_pDXVADecoder->ConfigureDXVA1();
else if (SUCCEEDED (ConfigureDXVA2 (pReceivePin)) && SUCCEEDED (SetEVRForDXVA2 (pReceivePin)) )
m_nDXVAMode = MODE_DXVA2;
}
if (m_nDXVAMode == MODE_SOFTWARE && !FFSoftwareCheckCompatibility(m_pAVCtx))
return VFW_E_INVALIDMEDIATYPE;
CLSID ClsidSourceFilter = GetCLSID(m_pInput->GetConnected());
if((ClsidSourceFilter == __uuidof(CMpegSourceFilter)) || (ClsidSourceFilter == __uuidof(CMpegSplitterFilter)))
m_bReorderBFrame = false;
}
// Cannot use YUY2 if horizontal or vertical resolution is not even
if ( ((m_pOutput->CurrentMediaType().subtype == MEDIASUBTYPE_NV12) && (m_nDXVAMode == MODE_SOFTWARE)) ||
((m_pOutput->CurrentMediaType().subtype == MEDIASUBTYPE_YUY2) && (m_pAVCtx->width&1 || m_pAVCtx->height&1)) )
return VFW_E_INVALIDMEDIATYPE;
return __super::CompleteConnect (direction, pReceivePin);
}
HRESULT CMPCVideoDecFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
{
if (UseDXVA2())
{
HRESULT hr;
ALLOCATOR_PROPERTIES Actual;
if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
pProperties->cBuffers = GetPicEntryNumber();
if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual)))
return hr;
return pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
? E_FAIL
: NOERROR;
}
else
return __super::DecideBufferSize (pAllocator, pProperties);
}
HRESULT CMPCVideoDecFilter::NewSegment(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double dRate)
{
CAutoLock cAutoLock(&m_csReceive);
m_nPosB = 1;
memset (&m_BFrames, 0, sizeof(m_BFrames));
m_rtLastStart = 0;
m_nCountEstimated = 0;
ResetBuffer();
if (m_pAVCtx)
avcodec_flush_buffers (m_pAVCtx);
if (m_pDXVADecoder)
m_pDXVADecoder->Flush();
return __super::NewSegment (rtStart, rtStop, dRate);
}
HRESULT CMPCVideoDecFilter::BreakConnect(PIN_DIRECTION dir)
{
if (dir == PINDIR_INPUT)
{
Cleanup();
}
return __super::BreakConnect (dir);
}
void CMPCVideoDecFilter::SetTypeSpecificFlags(IMediaSample* pMS)
{
if(CComQIPtr pMS2 = pMS)
{
AM_SAMPLE2_PROPERTIES props;
if(SUCCEEDED(pMS2->GetProperties(sizeof(props), (BYTE*)&props)))
{
props.dwTypeSpecificFlags &= ~0x7f;
if(!m_pFrame->interlaced_frame)
props.dwTypeSpecificFlags |= AM_VIDEO_FLAG_WEAVE;
else
{
if(m_pFrame->top_field_first)
props.dwTypeSpecificFlags |= AM_VIDEO_FLAG_FIELD1FIRST;
}
switch (m_pFrame->pict_type)
{
case FF_I_TYPE :
case FF_SI_TYPE :
props.dwTypeSpecificFlags |= AM_VIDEO_FLAG_I_SAMPLE;
break;
case FF_P_TYPE :
case FF_SP_TYPE :
props.dwTypeSpecificFlags |= AM_VIDEO_FLAG_P_SAMPLE;
break;
default :
props.dwTypeSpecificFlags |= AM_VIDEO_FLAG_B_SAMPLE;
break;
}
pMS2->SetProperties(sizeof(props), (BYTE*)&props);
}
}
}
#if INCLUDE_MPC_VIDEO_DECODER
int CMPCVideoDecFilter::GetCspFromMediaType(GUID& subtype)
{
if (subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV || subtype == MEDIASUBTYPE_YV12)
return FF_CSP_420P|FF_CSP_FLAGS_YUV_ADJ;
else if (subtype == MEDIASUBTYPE_YUY2)
return FF_CSP_YUY2;
// else if (subtype == MEDIASUBTYPE_ARGB32 || subtype == MEDIASUBTYPE_RGB32 || subtype == MEDIASUBTYPE_RGB24 || subtype == MEDIASUBTYPE_RGB565)
ASSERT (FALSE);
return FF_CSP_NULL;
}
void CMPCVideoDecFilter::InitSwscale()
{
if (m_pSwsContext == NULL)
{
TYCbCr2RGB_coeffs coeffs(ffYCbCr_RGB_coeff_ITUR_BT601,0, 235, 16, 255.0, 0.0);
int32_t swscaleTable[7];
SwsParams params;
memset(¶ms,0,sizeof(params));
if (m_pAVCtx->dsp_mask & CCpuId::MPC_MM_MMX) params.cpu |= SWS_CPU_CAPS_MMX|SWS_CPU_CAPS_MMX2;
if (m_pAVCtx->dsp_mask & CCpuId::MPC_MM_3DNOW) params.cpu |= SWS_CPU_CAPS_3DNOW;
params.methodLuma.method=params.methodChroma.method=SWS_POINT;
swscaleTable[0] = int32_t(coeffs.vr_mul * 65536 + 0.5);
swscaleTable[1] = int32_t(coeffs.ub_mul * 65536 + 0.5);
swscaleTable[2] = int32_t(coeffs.ug_mul * 65536 + 0.5);
swscaleTable[3] = int32_t(coeffs.vg_mul * 65536 + 0.5);
swscaleTable[4] = int32_t(coeffs.y_mul * 65536 + 0.5);
swscaleTable[5] = int32_t(coeffs.Ysub * 65536);
swscaleTable[6] = coeffs.RGB_add1;
BITMAPINFOHEADER bihOut;
ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
m_nOutCsp = GetCspFromMediaType(m_pOutput->CurrentMediaType().subtype);
m_pSwsContext = sws_getContext(m_pAVCtx->width,
m_pAVCtx->height,
csp_ffdshow2mplayer(csp_lavc2ffdshow(m_pAVCtx->pix_fmt)),
m_pAVCtx->width,
m_pAVCtx->height,
csp_ffdshow2mplayer(m_nOutCsp),
¶ms,
NULL,
NULL,
swscaleTable);
m_pOutSize.cx = bihOut.biWidth;
m_pOutSize.cy = abs(bihOut.biHeight);
}
}
template inline T odd2even(T x)
{
return x&1 ?
x + 1 :
x;
}
#endif /* INCLUDE_MPC_VIDEO_DECODER */
HRESULT CMPCVideoDecFilter::SoftwareDecode(IMediaSample* pIn, BYTE* pDataIn, int nSize, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop)
{
HRESULT hr;
int got_picture;
int used_bytes;
while (nSize > 0)
{
if (nSize+FF_INPUT_BUFFER_PADDING_SIZE > m_nFFBufferSize)
{
m_nFFBufferSize = nSize+FF_INPUT_BUFFER_PADDING_SIZE;
m_pFFBuffer = (BYTE*)realloc(m_pFFBuffer, m_nFFBufferSize);
}
// Required number of additionally allocated bytes at the end of the input bitstream for decoding.
// This is mainly needed because some optimized bitstream readers read
// 32 or 64 bit at once and could read over the end.
// Note: If the first 23 bits of the additional bytes are not 0, then damaged
// MPEG bitstreams could cause overread and segfault.
memcpy(m_pFFBuffer, pDataIn, nSize);
memset(m_pFFBuffer+nSize,0,FF_INPUT_BUFFER_PADDING_SIZE);
used_bytes = avcodec_decode_video (m_pAVCtx, m_pFrame, &got_picture, m_pFFBuffer, nSize);
if (!got_picture || !m_pFrame->data[0]) return S_OK;
if(pIn->IsPreroll() == S_OK || rtStart < 0) return S_OK;
CComPtr pOut;
BYTE* pDataOut = NULL;
UpdateAspectRatio();
if(FAILED(hr = GetDeliveryBuffer(m_pAVCtx->width, m_pAVCtx->height, &pOut)) || FAILED(hr = pOut->GetPointer(&pDataOut)))
return hr;
rtStart = m_pFrame->reordered_opaque;
rtStop = m_pFrame->reordered_opaque + m_rtAvrTimePerFrame;
ReorderBFrames(rtStart, rtStop);
pOut->SetTime(&rtStart, &rtStop);
pOut->SetMediaTime(NULL, NULL);
#if INCLUDE_MPC_VIDEO_DECODER
if (m_pSwsContext == NULL) InitSwscale();
// TODO : quick and dirty patch to fix convertion to YUY2 with swscale
if (m_nOutCsp == FF_CSP_YUY2)
CopyBuffer(pDataOut, m_pFrame->data, m_pAVCtx->width, m_pAVCtx->height, m_pFrame->linesize[0], MEDIASUBTYPE_I420, false);
else if (m_pSwsContext != NULL)
{
uint8_t* dst[4];
stride_t srcStride[4];
stride_t dstStride[4];
const TcspInfo *outcspInfo=csp_getInfo(m_nOutCsp);
for (int i=0;i<4;i++)
{
srcStride[i]=(stride_t)m_pFrame->linesize[i];
dstStride[i]=m_pOutSize.cx>>outcspInfo->shiftX[i];
if (i==0)
dst[i]=pDataOut;
else
dst[i]=dst[i-1]+dstStride[i-1]*(m_pOutSize.cy>>outcspInfo->shiftY[i-1]);
}
int nTempCsp = m_nOutCsp;
if(outcspInfo->id==FF_CSP_420P)
csp_yuv_adj_to_plane(nTempCsp,outcspInfo,odd2even(m_pOutSize.cy),(unsigned char**)dst,dstStride);
else
csp_yuv_adj_to_plane(nTempCsp,outcspInfo,m_pAVCtx->height,(unsigned char**)dst,dstStride);
sws_scale_ordered (m_pSwsContext, m_pFrame->data, srcStride, 0, m_pAVCtx->height, dst, dstStride);
}
#endif /* INCLUDE_MPC_VIDEO_DECODER */
#if defined(_DEBUG) && 0
static REFERENCE_TIME rtLast = 0;
TRACE ("Deliver : %10I64d - %10I64d (%10I64d) {%10I64d}\n", rtStart, rtStop,
rtStop - rtStart, rtStart - rtLast);
rtLast = rtStart;
#endif
SetTypeSpecificFlags (pOut);
hr = m_pOutput->Deliver(pOut);
nSize -= used_bytes;
pDataIn += used_bytes;
}
return hr;
}
/*
void CMPCVideoDecFilter::FindStartCodeVC1 (BYTE** pDataIn, int& nSize)
{
DWORD dw = 0;
long lStart = -1;
*pDataIn = NULL;
nSize = 0;
for (int i=0; i= 4)
{
if (m_nFFPicEnd == INT_MIN)
{
if ( (dw & 0xffffff00) == 0x00000100 &&
(dw & 0x000000FF) == nStartCode )
{
m_nFFPicEnd = i+nIndex-3;
}
}
else
{
if ( (dw & 0xffffff00) == 0x00000100 &&
( (dw & 0x000000FF) == nStartCode || (dw & 0x000000FF) == 0xB3 ))
{
m_nFFPicEnd = i+nIndex-3;
return true;
}
}
}
}
return false;
}
void CMPCVideoDecFilter::ResetBuffer()
{
m_nFFBufferPos = 0;
m_nFFPicEnd = INT_MIN;
for (int i=0; i= nPos)
{
m_FFBufferTime[nDestPos].nBuffPos = m_FFBufferTime[i].nBuffPos - nPos;
m_FFBufferTime[nDestPos].rtStart = m_FFBufferTime[i].rtStart;
m_FFBufferTime[nDestPos].rtStop = m_FFBufferTime[i].rtStop;
nDestPos++;
}
i++;
}
// Free unused slots
for (i=nDestPos; i m_nFFBufferSize)
{
m_nFFBufferSize = m_nFFBufferPos+nSize+FF_INPUT_BUFFER_PADDING_SIZE;
m_pFFBuffer = (BYTE*)realloc(m_pFFBuffer, m_nFFBufferSize);
}
memcpy(m_pFFBuffer+m_nFFBufferPos, pDataIn, nSize);
m_nFFBufferPos += nSize;
return true;
}
void CMPCVideoDecFilter::ShrinkBuffer()
{
int nRemaining = m_nFFBufferPos-m_nFFPicEnd;
ASSERT (m_nFFPicEnd != INT_MIN);
PopBufferTime (m_nFFPicEnd);
memcpy (m_pFFBuffer, m_pFFBuffer+m_nFFPicEnd, nRemaining);
m_nFFBufferPos = nRemaining;
m_nFFPicEnd = (m_pFFBuffer[3] == 0x00) ? 0 : INT_MIN;
}
HRESULT CMPCVideoDecFilter::Transform(IMediaSample* pIn)
{
CAutoLock cAutoLock(&m_csReceive);
HRESULT hr;
BYTE* pDataIn;
int nSize;
REFERENCE_TIME rtStart = _I64_MIN;
REFERENCE_TIME rtStop = _I64_MIN;
if(FAILED(hr = pIn->GetPointer(&pDataIn)))
return hr;
nSize = pIn->GetActualDataLength();
pIn->GetTime(&rtStart, &rtStop);
// FIXE THIS PART TO EVO_SUPPORT (insure m_rtAvrTimePerFrame is not estimated if not needed!!)
//if (rtStart != _I64_MIN)
//{
// // Estimate rtStart/rtStop if not set by parser (EVO support)
// if (m_nCountEstimated > 0)
// {
// m_rtAvrTimePerFrame = (rtStart - m_rtLastStart) / m_nCountEstimated;
// ROUND_FRAMERATE (m_rtAvrTimePerFrame, 417083); // 23.97 fps
// ROUND_FRAMERATE (m_rtAvrTimePerFrame, 333667); // 29.97 fps
// ROUND_FRAMERATE (m_rtAvrTimePerFrame, 400000); // 25.00 fps
// }
// m_rtLastStart = rtStart;
// m_nCountEstimated = 0;
//}
//else
//{
// m_nCountEstimated++;
// rtStart = rtStop = m_rtLastStart + m_nCountEstimated*m_rtAvrTimePerFrame;
//}
if (rtStop <= rtStart && rtStop != _I64_MIN)
rtStop = rtStart + m_rtAvrTimePerFrame;
m_pAVCtx->reordered_opaque = rtStart;
m_pAVCtx->reordered_opaque2 = rtStop;
if (m_pAVCtx->has_b_frames)
{
m_BFrames[m_nPosB].rtStart = rtStart;
m_BFrames[m_nPosB].rtStop = rtStop;
m_nPosB = 1-m_nPosB;
}
// m_rtStart = rtStart;
// DumpBuffer (pDataIn, nSize);
// TRACE ("Receive : %10I64d - %10I64d (%10I64d) Size=%d\n", rtStart, rtStop, rtStop - rtStart, nSize);
//char strMsg[300];
//FILE* hFile = fopen ("d:\\receive.txt", "at");
//sprintf (strMsg, "Receive : %10I64d - %10I64d Size=%d\n", (rtStart + m_rtAvrTimePerFrame/2) / m_rtAvrTimePerFrame, rtStart, nSize);
//fwrite (strMsg, strlen(strMsg), 1, hFile);
//fclose (hFile);
//char strMsg[300];
//FILE* hFile = fopen ("receive.bin", "ab");
//fwrite (pDataIn, nSize, 1, hFile);
//fclose (hFile);
switch (m_nDXVAMode)
{
case MODE_SOFTWARE :
hr = SoftwareDecode (pIn, pDataIn, nSize, rtStart, rtStop);
break;
case MODE_DXVA1 :
case MODE_DXVA2 :
CheckPointer (m_pDXVADecoder, E_UNEXPECTED);
UpdateAspectRatio();
// Change aspect ratio for DXVA1
if ((m_nDXVAMode == MODE_DXVA1) &&
ReconnectOutput(PictWidthRounded(), PictHeightRounded(), true, PictWidth(), PictHeight()) == S_OK)
{
m_pDXVADecoder->ConfigureDXVA1();
}
if (m_pAVCtx->codec_id == CODEC_ID_MPEG2VIDEO)
{
AppendBuffer (pDataIn, nSize, rtStart, rtStop);
hr = S_OK;
while (FindPicture (max (m_nFFBufferPos-nSize-4, 0), 0x00))
{
if (m_FFBufferTime[0].nBuffPos != INT_MIN && m_FFBufferTime[0].nBuffPos < m_nFFPicEnd)
{
rtStart = m_FFBufferTime[0].rtStart;
rtStop = m_FFBufferTime[0].rtStop;
}
else
rtStart = rtStop = _I64_MIN;
hr = m_pDXVADecoder->DecodeFrame (m_pFFBuffer, m_nFFPicEnd, rtStart, rtStop);
ShrinkBuffer();
}
}
else
{
hr = m_pDXVADecoder->DecodeFrame (pDataIn, nSize, rtStart, rtStop);
}
break;
default :
ASSERT (FALSE);
hr = E_UNEXPECTED;
}
return hr;
}
void CMPCVideoDecFilter::UpdateAspectRatio()
{
if(((m_nARMode) && (m_pAVCtx)) && ((m_pAVCtx->sample_aspect_ratio.num>0) && (m_pAVCtx->sample_aspect_ratio.den>0)))
{
CSize SAR(m_pAVCtx->sample_aspect_ratio.num, m_pAVCtx->sample_aspect_ratio.den);
if(m_sar != SAR)
{
m_sar = SAR;
CSize aspect(m_nWidth * SAR.cx, m_nHeight * SAR.cy);
int lnko = LNKO(aspect.cx, aspect.cy);
if(lnko > 1) aspect.cx /= lnko, aspect.cy /= lnko;
SetAspect(aspect);
}
}
}
void CMPCVideoDecFilter::ReorderBFrames(REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop)
{
// Re-order B-frames if needed
if (m_pAVCtx->has_b_frames && m_bReorderBFrame)
{
rtStart = m_BFrames [m_nPosB].rtStart;
rtStop = m_BFrames [m_nPosB].rtStop;
}
}
void CMPCVideoDecFilter::FillInVideoDescription(DXVA2_VideoDesc *pDesc)
{
memset (pDesc, 0, sizeof(DXVA2_VideoDesc));
pDesc->SampleWidth = PictWidthRounded();
pDesc->SampleHeight = PictHeightRounded();
pDesc->Format = D3DFMT_A8R8G8B8;
pDesc->UABProtectionLevel = 1;
}
BOOL CMPCVideoDecFilter::IsSupportedDecoderMode(const GUID& mode)
{
if (IsDXVASupported())
{
for (int i=0; iDecoder[i] == GUID_NULL)
break;
else if (*ffCodecs[m_nCodecNb].DXVAModes->Decoder[i] == mode)
return true;
}
}
return false;
}
BOOL CMPCVideoDecFilter::IsSupportedDecoderConfig(const D3DFORMAT nD3DFormat, const DXVA2_ConfigPictureDecode& config, bool& bIsPrefered)
{
bool bRet = false;
bRet = (nD3DFormat == MAKEFOURCC('N', 'V', '1', '2'));
bIsPrefered = (config.ConfigBitstreamRaw == ffCodecs[m_nCodecNb].DXVAModes->PreferedConfigBitstream);
LOG (_T("IsSupportedDecoderConfig 0x%08x %d"), nD3DFormat, bRet);
return bRet;
}
HRESULT CMPCVideoDecFilter::FindDXVA2DecoderConfiguration(IDirectXVideoDecoderService *pDecoderService,
const GUID& guidDecoder,
DXVA2_ConfigPictureDecode *pSelectedConfig,
BOOL *pbFoundDXVA2Configuration)
{
HRESULT hr = S_OK;
UINT cFormats = 0;
UINT cConfigurations = 0;
bool bIsPrefered = false;
D3DFORMAT *pFormats = NULL; // size = cFormats
DXVA2_ConfigPictureDecode *pConfig = NULL; // size = cConfigurations
// Find the valid render target formats for this decoder GUID.
hr = pDecoderService->GetDecoderRenderTargets(guidDecoder, &cFormats, &pFormats);
LOG (_T("GetDecoderRenderTargets => %d"), cFormats);
if (SUCCEEDED(hr))
{
// Look for a format that matches our output format.
for (UINT iFormat = 0; iFormat < cFormats; iFormat++)
{
LOG (_T("Try to negociate => 0x%08x"), pFormats[iFormat]);
// Fill in the video description. Set the width, height, format, and frame rate.
FillInVideoDescription(&m_VideoDesc); // Private helper function.
m_VideoDesc.Format = pFormats[iFormat];
// Get the available configurations.
hr = pDecoderService->GetDecoderConfigurations(guidDecoder, &m_VideoDesc, NULL, &cConfigurations, &pConfig);
if (FAILED(hr))
{
continue;
}
// Find a supported configuration.
for (UINT iConfig = 0; iConfig < cConfigurations; iConfig++)
{
if (IsSupportedDecoderConfig(pFormats[iFormat], pConfig[iConfig], bIsPrefered))
{
// This configuration is good.
if (bIsPrefered || !*pbFoundDXVA2Configuration)
{
*pbFoundDXVA2Configuration = TRUE;
*pSelectedConfig = pConfig[iConfig];
}
if (bIsPrefered) break;
}
}
CoTaskMemFree(pConfig);
} // End of formats loop.
}
CoTaskMemFree(pFormats);
// Note: It is possible to return S_OK without finding a configuration.
return hr;
}
HRESULT CMPCVideoDecFilter::ConfigureDXVA2(IPin *pPin)
{
HRESULT hr = S_OK;
UINT cDecoderGuids = 0;
BOOL bFoundDXVA2Configuration = FALSE;
GUID guidDecoder = GUID_NULL;
DXVA2_ConfigPictureDecode config;
ZeroMemory(&config, sizeof(config));
CComPtr pGetService;
CComPtr pDeviceManager;
CComPtr pDecoderService;
GUID* pDecoderGuids = NULL;
HANDLE hDevice = INVALID_HANDLE_VALUE;
// Query the pin for IMFGetService.
hr = pPin->QueryInterface(__uuidof(IMFGetService), (void**)&pGetService);
// Get the Direct3D device manager.
if (SUCCEEDED(hr))
{
hr = pGetService->GetService(
MR_VIDEO_ACCELERATION_SERVICE,
__uuidof(IDirect3DDeviceManager9),
(void**)&pDeviceManager);
}
// Open a new device handle.
if (SUCCEEDED(hr))
{
hr = pDeviceManager->OpenDeviceHandle(&hDevice);
}
// Get the video decoder service.
if (SUCCEEDED(hr))
{
hr = pDeviceManager->GetVideoService(
hDevice,
__uuidof(IDirectXVideoDecoderService),
(void**)&pDecoderService);
}
// Get the decoder GUIDs.
if (SUCCEEDED(hr))
{
hr = pDecoderService->GetDecoderDeviceGuids(&cDecoderGuids, &pDecoderGuids);
}
if (SUCCEEDED(hr))
{
// Look for the decoder GUIDs we want.
for (UINT iGuid = 0; iGuid < cDecoderGuids; iGuid++)
{
// Do we support this mode?
if (!IsSupportedDecoderMode(pDecoderGuids[iGuid]))
{
continue;
}
// Find a configuration that we support.
hr = FindDXVA2DecoderConfiguration(pDecoderService, pDecoderGuids[iGuid], &config, &bFoundDXVA2Configuration);
if (FAILED(hr))
{
break;
}
if (bFoundDXVA2Configuration)
{
// Found a good configuration. Save the GUID.
guidDecoder = pDecoderGuids[iGuid];
}
}
}
if (pDecoderGuids) CoTaskMemFree(pDecoderGuids);
if (!bFoundDXVA2Configuration)
{
hr = E_FAIL; // Unable to find a configuration.
}
if (SUCCEEDED(hr))
{
// Store the things we will need later.
m_pDeviceManager = pDeviceManager;
m_pDecoderService = pDecoderService;
m_DXVA2Config = config;
m_DXVADecoderGUID = guidDecoder;
m_hDevice = hDevice;
}
if (FAILED(hr))
{
if (hDevice != INVALID_HANDLE_VALUE)
{
pDeviceManager->CloseDeviceHandle(hDevice);
}
}
return hr;
}
HRESULT CMPCVideoDecFilter::SetEVRForDXVA2(IPin *pPin)
{
HRESULT hr = S_OK;
CComPtr pGetService;
CComPtr pVideoConfig;
CComPtr pVdc;
// Query the pin for IMFGetService.
hr = pPin->QueryInterface(__uuidof(IMFGetService), (void**)&pGetService);
// Get the IDirectXVideoMemoryConfiguration interface.
if (SUCCEEDED(hr))
{
hr = pGetService->GetService(
MR_VIDEO_ACCELERATION_SERVICE,
__uuidof(IDirectXVideoMemoryConfiguration),
(void**)&pVideoConfig);
if (SUCCEEDED (pGetService->GetService(MR_VIDEO_RENDER_SERVICE, __uuidof(IMFVideoDisplayControl), (void**)&pVdc)))
{
HWND hWnd;
if (SUCCEEDED (pVdc->GetVideoWindow(&hWnd)))
{
DetectVideoCard(hWnd);
}
}
}
// Notify the EVR.
if (SUCCEEDED(hr))
{
DXVA2_SurfaceType surfaceType;
for (DWORD iTypeIndex = 0; ; iTypeIndex++)
{
hr = pVideoConfig->GetAvailableSurfaceTypeByIndex(iTypeIndex, &surfaceType);
if (FAILED(hr))
break;
if (surfaceType == DXVA2_SurfaceType_DecoderRenderTarget)
{
hr = pVideoConfig->SetSurfaceType(DXVA2_SurfaceType_DecoderRenderTarget);
break;
}
}
}
return hr;
}
HRESULT CMPCVideoDecFilter::CreateDXVA2Decoder(UINT nNumRenderTargets, IDirect3DSurface9** pDecoderRenderTargets)
{
HRESULT hr;
CComPtr pDirectXVideoDec;
m_pDecoderRenderTarget = NULL;
if (m_pDXVADecoder) m_pDXVADecoder->SetDirectXVideoDec (NULL);
hr = m_pDecoderService->CreateVideoDecoder (m_DXVADecoderGUID, &m_VideoDesc, &m_DXVA2Config,
pDecoderRenderTargets, nNumRenderTargets, &pDirectXVideoDec);
if (SUCCEEDED (hr))
{
if (!m_pDXVADecoder)
{
m_pDXVADecoder = CDXVADecoder::CreateDecoder (this, pDirectXVideoDec, &m_DXVADecoderGUID, GetPicEntryNumber(), &m_DXVA2Config);
if (m_pDXVADecoder) m_pDXVADecoder->SetExtraData ((BYTE*)m_pAVCtx->extradata, m_pAVCtx->extradata_size);
}
m_pDXVADecoder->SetDirectXVideoDec (pDirectXVideoDec);
}
return hr;
}
HRESULT CMPCVideoDecFilter::FindDXVA1DecoderConfiguration(IAMVideoAccelerator* pAMVideoAccelerator, const GUID* guidDecoder, DDPIXELFORMAT* pPixelFormat)
{
HRESULT hr = E_FAIL;
DWORD dwFormats = 0;
DDPIXELFORMAT* pPixelFormats = NULL;
pAMVideoAccelerator->GetUncompFormatsSupported (guidDecoder, &dwFormats, NULL);
if (dwFormats > 0)
{
// Find the valid render target formats for this decoder GUID.
pPixelFormats = DNew DDPIXELFORMAT[dwFormats];
hr = pAMVideoAccelerator->GetUncompFormatsSupported (guidDecoder, &dwFormats, pPixelFormats);
if (SUCCEEDED(hr))
{
// Look for a format that matches our output format.
for (DWORD iFormat = 0; iFormat < dwFormats; iFormat++)
{
if (pPixelFormats[iFormat].dwFourCC == MAKEFOURCC ('N', 'V', '1', '2'))
{
memcpy (pPixelFormat, &pPixelFormats[iFormat], sizeof(DDPIXELFORMAT));
SAFE_DELETE_ARRAY(pPixelFormats)
return S_OK;
}
}
SAFE_DELETE_ARRAY(pPixelFormats);
hr = E_FAIL;
}
}
return hr;
}
HRESULT CMPCVideoDecFilter::CheckDXVA1Decoder(const GUID *pGuid)
{
if (m_nCodecNb != -1)
{
for (int i=0; iDecoder[i] == *pGuid)
return S_OK;
}
return E_INVALIDARG;
}
void CMPCVideoDecFilter::SetDXVA1Params(const GUID* pGuid, DDPIXELFORMAT* pPixelFormat)
{
m_DXVADecoderGUID = *pGuid;
memcpy (&m_PixelFormat, pPixelFormat, sizeof (DDPIXELFORMAT));
}
WORD CMPCVideoDecFilter::GetDXVA1RestrictedMode()
{
if (m_nCodecNb != -1)
{
for (int i=0; iDecoder[i] == m_DXVADecoderGUID)
return ffCodecs[m_nCodecNb].DXVAModes->RestrictedMode [i];
}
return DXVA_RESTRICTED_MODE_UNRESTRICTED;
}
HRESULT CMPCVideoDecFilter::CreateDXVA1Decoder(IAMVideoAccelerator* pAMVideoAccelerator, const GUID* pDecoderGuid, DWORD dwSurfaceCount)
{
if (m_pDXVADecoder && m_DXVADecoderGUID == *pDecoderGuid)
return S_OK;
SAFE_DELETE (m_pDXVADecoder);
if (!m_bUseDXVA) return E_FAIL;
m_nDXVAMode = MODE_DXVA1;
m_DXVADecoderGUID = *pDecoderGuid;
m_pDXVADecoder = CDXVADecoder::CreateDecoder (this, pAMVideoAccelerator, &m_DXVADecoderGUID, dwSurfaceCount);
if (m_pDXVADecoder) m_pDXVADecoder->SetExtraData ((BYTE*)m_pAVCtx->extradata, m_pAVCtx->extradata_size);
return S_OK;
}
// ISpecifyPropertyPages2
STDMETHODIMP CMPCVideoDecFilter::GetPages(CAUUID* pPages)
{
CheckPointer(pPages, E_POINTER);
#ifdef REGISTER_FILTER
pPages->cElems = 2;
#else
pPages->cElems = 1;
#endif
pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID) * pPages->cElems);
pPages->pElems[0] = __uuidof(CMPCVideoDecSettingsWnd);
if (pPages->cElems>1) pPages->pElems[1] = __uuidof(CMPCVideoDecCodecWnd);
return S_OK;
}
STDMETHODIMP CMPCVideoDecFilter::CreatePage(const GUID& guid, IPropertyPage** ppPage)
{
CheckPointer(ppPage, E_POINTER);
if(*ppPage != NULL) return E_INVALIDARG;
HRESULT hr;
if(guid == __uuidof(CMPCVideoDecSettingsWnd))
{
(*ppPage = DNew CInternalPropertyPageTempl(NULL, &hr))->AddRef();
}
else if(guid == __uuidof(CMPCVideoDecCodecWnd))
{
(*ppPage = DNew CInternalPropertyPageTempl(NULL, &hr))->AddRef();
}
return *ppPage ? S_OK : E_FAIL;
}
// IFfmpegDecFilter
STDMETHODIMP CMPCVideoDecFilter::Apply()
{
CRegKey key;
if(ERROR_SUCCESS == key.Create(HKEY_CURRENT_USER, _T("Software\\Gabest\\Filters\\MPC Video Decoder")))
{
key.SetDWORDValue(_T("ThreadNumber"), m_nThreadNumber);
key.SetDWORDValue(_T("DiscardMode"), m_nDiscardMode);
key.SetDWORDValue(_T("ErrorRecognition"), m_nErrorRecognition);
key.SetDWORDValue(_T("IDCTAlgo"), m_nIDCTAlgo);
key.SetDWORDValue(_T("ActiveCodecs"), m_nActiveCodecs);
key.SetDWORDValue(_T("ARMode"), m_nARMode);
key.SetDWORDValue(_T("DXVACheckCompatibility"), m_nDXVACheckCompatibility);
}
return S_OK;
}
STDMETHODIMP CMPCVideoDecFilter::SetThreadNumber(int nValue)
{
CAutoLock cAutoLock(&m_csProps);
m_nThreadNumber = nValue;
return S_OK;
}
STDMETHODIMP_(int) CMPCVideoDecFilter::GetThreadNumber()
{
CAutoLock cAutoLock(&m_csProps);
return m_nThreadNumber;
}
STDMETHODIMP CMPCVideoDecFilter::SetDiscardMode(int nValue)
{
CAutoLock cAutoLock(&m_csProps);
m_nDiscardMode = nValue;
return S_OK;
}
STDMETHODIMP_(int) CMPCVideoDecFilter::GetDiscardMode()
{
CAutoLock cAutoLock(&m_csProps);
return m_nDiscardMode;
}
STDMETHODIMP CMPCVideoDecFilter::SetErrorRecognition(int nValue)
{
CAutoLock cAutoLock(&m_csProps);
m_nErrorRecognition = nValue;
return S_OK;
}
STDMETHODIMP_(int) CMPCVideoDecFilter::GetErrorRecognition()
{
CAutoLock cAutoLock(&m_csProps);
return m_nErrorRecognition;
}
STDMETHODIMP CMPCVideoDecFilter::SetIDCTAlgo(int nValue)
{
CAutoLock cAutoLock(&m_csProps);
m_nIDCTAlgo = nValue;
return S_OK;
}
STDMETHODIMP_(int) CMPCVideoDecFilter::GetIDCTAlgo()
{
CAutoLock cAutoLock(&m_csProps);
return m_nIDCTAlgo;
}
STDMETHODIMP_(GUID*) CMPCVideoDecFilter::GetDXVADecoderGuid()
{
if (m_pGraph == NULL)
return NULL;
else
return &m_DXVADecoderGUID;
}
STDMETHODIMP CMPCVideoDecFilter::SetActiveCodecs(MPC_VIDEO_CODEC nValue)
{
CAutoLock cAutoLock(&m_csProps);
m_nActiveCodecs = (int)nValue;
return S_OK;
}
STDMETHODIMP_(MPC_VIDEO_CODEC) CMPCVideoDecFilter::GetActiveCodecs()
{
CAutoLock cAutoLock(&m_csProps);
return (MPC_VIDEO_CODEC)m_nActiveCodecs;
}
STDMETHODIMP_(LPCTSTR) CMPCVideoDecFilter::GetVideoCardDescription()
{
CAutoLock cAutoLock(&m_csProps);
return m_strDeviceDescription;
}
STDMETHODIMP CMPCVideoDecFilter::SetARMode(int nValue)
{
CAutoLock cAutoLock(&m_csProps);
m_nARMode = nValue;
return S_OK;
}
STDMETHODIMP_(int) CMPCVideoDecFilter::GetARMode()
{
CAutoLock cAutoLock(&m_csProps);
return m_nARMode;
}
STDMETHODIMP CMPCVideoDecFilter::SetDXVACheckCompatibility(int nValue)
{
CAutoLock cAutoLock(&m_csProps);
m_nDXVACheckCompatibility = nValue;
return S_OK;
}
STDMETHODIMP_(int) CMPCVideoDecFilter::GetDXVACheckCompatibility()
{
CAutoLock cAutoLock(&m_csProps);
return m_nDXVACheckCompatibility;
}