最近有些客户在使用美菲特视频采集卡中遇到一个Windows Media SDK或者Wndows SDK 7A的WMV解码问题:
在Win7 64bit下,interlacing 的wmv 片子decode出来的YUYV视频只有色度,没有亮度。
奇怪的问题!
在项目修改之后,又写了以下解码样例代码来验证,确认问题的存在。
最后的解决办法是:
1,确定修改逻辑只作用在64bit,32bit处理逻辑保持不变
2,分析侦测影片是否为interlaced
3,对于64bit interlaced的片子,设置为VYUY导出,其他则保持为YUYV导出
4,将VYUY转换成YUYV
是微软挖了个大坑,还是调用方法有误?
聊以记之,以观后效。
// Date: 2014-9-16
// Target: Sample code to decode first frame as UYVY of WMV
#include "stdafx.h"
#include <wmsdk.h>
#include <atlbase.h>
#pragma comment(lib,"wmvcore.lib")
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = S_OK;
DWORD dwStreams = 0;
DWORD dwOutputNum;
GUID pguidStreamType;
ULONG cbType = 0;
WORD wStreamNumber = 0 ;
CComPtr<IWMSyncReader> m_pReader;
bool bInterlacedAllowedIsSet = FALSE;
WMVIDEOINFOHEADER head;
WORD wVideoStreamNum = 0;
_TCHAR* ptszFile = TEXT("c:\\test.wmv");
if (argc>1)
ptszFile = argv[1];
CoInitialize(NULL);
if ( !m_pReader )
{
hr = WMCreateSyncReader( NULL, 0, (IWMSyncReader**)&m_pReader.p );
}
if ( FAILED( hr ) )
{
CoUninitialize();
return( hr );
}
hr = m_pReader->Open( ptszFile );
if ( FAILED( hr ) )
{
CoUninitialize();
return( hr );
}
//
// Get the profile interface
//
CComPtr<IWMProfile> pProfile;
hr = m_pReader->QueryInterface( IID_IWMProfile, ( VOID ** )&pProfile.p);
if ( FAILED( hr ) )
{
CoUninitialize();
return( hr );
}
hr = pProfile->GetStreamCount( &dwStreams );
for ( DWORD ix = dwStreams; ix ; --ix )
{
DWORD i=ix-1;
CComPtr<IWMStreamConfig> pStream;
hr = pProfile->GetStream( i, &pStream );
if ( FAILED( hr ) )
{
continue;
}
wStreamNumber = 0;
//
// Get the stream number of the current stream
//
hr = pStream->GetStreamNumber( &wStreamNumber );
if ( FAILED( hr ) )
{
continue;
}
hr = pStream->GetStreamType( &pguidStreamType );
if ( FAILED( hr ) )
{
continue;
}
hr = m_pReader->GetOutputNumberForStream( wStreamNumber, &dwOutputNum);
if ( FAILED( hr ) )
{
continue ;
}
DWORD dwNrFormats=0;
if (SUCCEEDED(hr=m_pReader->GetOutputFormatCount(dwOutputNum,&dwNrFormats)))
{
//For each supported format, call IWMReader::GetOutputFormat to retrieve the IWMOutputMediaProps interface on the output media properties object.
CComPtr<IWMOutputMediaProps> pOutputMediaProps;
for (unsigned int f=0; f<dwNrFormats; f++)
{
//Call IWMMediaProps::GetMediaType to retrieve the media type.
m_pReader->GetOutputFormat(dwOutputNum,f,&pOutputMediaProps.p);
if (FAILED( pOutputMediaProps->GetMediaType( NULL, &cbType ) ))
continue;
WM_MEDIA_TYPE* pMediaType = ( WM_MEDIA_TYPE* ) _alloca(cbType);
if (pMediaType==NULL)
continue;
if (FAILED( pOutputMediaProps->GetMediaType( pMediaType, &cbType )))
continue;
//If the retrieved media type is the desired multichannel type, then set it by calling IWMReader::SetOutputProps.
if ( pMediaType->formattype == WMFORMAT_WaveFormatEx)
{
if (pMediaType->cbFormat >= sizeof(WAVEFORMATEX) ) // type actually is WAVEFORMATEXTENSIBLE for 6 channels
{
WAVEFORMATEX* pWaveEx = (WAVEFORMATEX*)pMediaType->pbFormat;
}
}
if ( pMediaType->formattype == WMFORMAT_VideoInfo)
{
if (pMediaType->cbFormat >= sizeof(WMVIDEOINFOHEADER) ) // type actually is WAVEFORMATEXTENSIBLE for 6 channels
{
WMVIDEOINFOHEADER* pWmvVideoInfo = (WMVIDEOINFOHEADER*)pMediaType->pbFormat;
DWORD biC = pWmvVideoInfo->bmiHeader.biCompression;
if (pWmvVideoInfo->bmiHeader.biCompression == MAKEFOURCC('U','Y','V','Y')) {
m_pReader->SetOutputProps(dwOutputNum,pOutputMediaProps);
memcpy(&head, pWmvVideoInfo, sizeof(WMVIDEOINFOHEADER));
wVideoStreamNum = wStreamNumber;
}
}
}
}
}
// get media info
CComPtr<IWMOutputMediaProps> pProps;
hr = m_pReader->GetOutputProps( dwOutputNum, &pProps );
if( FAILED( hr ) )
{
continue;
}
// Find out the space needed for pMediaType
hr = pProps->GetMediaType( NULL, &cbType );
if( FAILED( hr ) )
{
continue;
}
WM_MEDIA_TYPE* pMediaType = ( WM_MEDIA_TYPE* ) _alloca(cbType);
if( NULL == pMediaType )
{
hr = HRESULT_FROM_WIN32( GetLastError() ) ;
continue;
}
//
// Get the value for MediaType
//
hr = pProps->GetMediaType( pMediaType, &cbType );
if( FAILED( hr ) )
{
continue;
}
if( WMMEDIATYPE_Audio == pguidStreamType )
{
//
}
else if( WMMEDIATYPE_Video == pguidStreamType )
{
BYTE allowInterlaced[4]; *(DWORD*)allowInterlaced=1;
if( SUCCEEDED(hr=m_pReader->SetOutputSetting( dwOutputNum, g_wszAllowInterlacedOutput, WMT_TYPE_BOOL, allowInterlaced,sizeof(allowInterlaced) )) )
bInterlacedAllowedIsSet = TRUE;
}
}
CComPtr<INSSBuffer> pSample;
INSSBuffer** ppSample = &pSample.p;
WMT_STREAM_SELECTION wmtSS = WMT_ON;
QWORD cnsSampleTime = 0, cnsPrevSampleTime = 0;
QWORD cnsSampleDuration = 0;
DWORD dwFlags = 0;
WORD wStreamNum = 0;
DWORD dwVideoSamplesCnt = 0;
hr = m_pReader->GetNextSample( wVideoStreamNum, ppSample,
&cnsSampleTime,
ppSample?(&cnsSampleDuration):NULL,
ppSample?(&dwFlags):NULL,
&dwOutputNum,
&wStreamNum );
BOOL m_bInterlaced = FALSE;
if (*ppSample!=NULL) {
if (bInterlacedAllowedIsSet) {
CComQIPtr<INSSBuffer3> pMS3(pSample);
if( pMS3 )
{
BYTE bufContentType[16];
memset(bufContentType,0xff,sizeof(bufContentType));
DWORD dwSize = WM_SampleExtension_ContentType_Size;
hr = pMS3->GetProperty( WM_SampleExtensionGUID_ContentType, bufContentType, &dwSize ); // bug in WMFSDK9.5: ContentType is only set if buffer was allocated by Reader itself!
if (SUCCEEDED( hr ))
m_bInterlaced = ( ((*bufContentType)&WM_CT_INTERLACED) != 0 );
}
}
BYTE* pbBuffer = NULL;
DWORD dwLength=0;
hr = (*ppSample)->GetBufferAndLength( &pbBuffer, &dwLength);
if ( FAILED( hr ) )
{
pbBuffer = NULL; dwLength = 0;
}
(*ppSample)->Release();
(*ppSample) = NULL;
}
if( !!m_pReader )
{
hr = m_pReader->Close();
}
m_pReader.Release();
CoUninitialize();
return 0;
}