有那么一阵子,我们为了要取得一个视频文件的bitrate(比特率)等信息伤透了脑筋,因为我们对多媒体编程是全然的门外汉,不过幸运地,后来我们接触了DirectShow/DirectSound和WMF等好玩的东西。
关于MPG/MPEG视频文件的bitrate等,那将是另一篇文章,我们在这个小文里只讨论WMV文件的东东。:)
Tips:要针对某一种多媒体文件格式进行处理,一般我们都需要用到特定的Encoder(编码器)和Decoder(解码器)以及其它工具、文档等,这些东东如果被该格式的厂商收集起来提供给开发人员使用,那么显然就变成一个SDK咯,像微软为WMA/WMV/ASF等格式提供的WMF SDK。貌似Real为RM/RMVB等自家格式也提供了SDK吧,不过俺还没有兴趣去研究它们。另外,DirectShow缺省地为MPG/MPEG/WAV等古老的多媒体的格式提供了支持,所以一般情况下不需要去找关于它们的SDK。
嗯,要取得WMV文件的bitrate,只靠DirectShow是不够的,我们需要WMF(Windows Media Format)的支持。如果你还不清楚WMF是什么东东,那么下面一些文章兴许会对你有帮助。
http://www.microsoft.com/windows/windowsmedia/forpros/format/default.mspx
http://msdn2.microsoft.com/zh-cn/windowsmedia/default(en-us).aspx
http://msdn2.microsoft.com/en-us/library/aa387410.aspx
另外,你可以从下面的地址获得最新的WMF11 SDK。
http://download.microsoft.com/download/a/c/3/ac367925-39e7-4451-a175-a224f94fbdce/wmformat11sdk.exe
OK,如果你已经安装完WMF11 SDK,那么我们就可以进入主题了。按照缺省安装,我们会得到很多很多的文件(哦,不多才怪)。我们首先要关心的是以下一些目录和文件。
1、include和lib,使用VC++开发WMF相关程序的依赖资源。
C:/WMSDK/WMFSDK11/include
C:/WMSDK/WMFSDK11/lib
2、Bin和Samples,MS提供的很多例子,很实用。
C:/WMSDK/WMFSDK11/Bin
C:/WMSDK/WMFSDK11/samples
3、帮助文档咯,其实如果安装了MSDN的话,MSDN里面也有的。
C:/WMSDK/WMFSDK11/wmformat.chm
那么为了达到我们本文的目的(取bitrate而已啦)要使用的文件呢?
请打开下面这个工程吧。
C:/WMSDK/WMFSDK11/samples/wmprop/
然后重点关注wmprop.cpp里面的代码,它是我们的核心。
下面我给出一个我加注的版本,嗯,就是加了点注释帮助大家阅读而已。
// number of streams, each stream number, and bitrate
// /
HRESULT CWMProp::GetPropertiesFromProfile()
{
HRESULT hr = S_OK;
if ( NULL == m_pProfile )
{
return ( E_FAIL );
}
// 该变量用于保存媒体流的数量
DWORD dwStreamCount = 0 ;
// 取得媒体流的数量
hr = m_pProfile -> GetStreamCount( & dwStreamCount );
if ( FAILED( hr ) )
{
_tprintf( _T( " Could not get stream count: (hr=0x%08x) " ), hr );
return ( hr );
}
_tprintf( _T( " This Windows Media file has %d stream(s) " ), dwStreamCount );
_tprintf( _T( " " ) );
// 遍历WMF文件里面包含的每一个流
for ( DWORD dwIndex = 0 ; dwIndex < dwStreamCount; dwIndex ++ )
{
// 核心API,IWMStreamConfig
// The IWMStreamConfig interface is the primary interface of
// a stream configuration object. It provides methods to
// configure basic properties for streams to be used in a profile.
IWMStreamConfig * pConfig = NULL;
// 取回一个流
hr = m_pProfile -> GetStream( dwIndex, & pConfig );
if ( FAILED( hr ) )
{
_tprintf( _T( " Could not get the stream: (hr=0x%08x) " ), hr );
return ( hr );
}
GUID guid = GUID_NULL;
// 取回流的类型。一个WMV文件一般包含三个流:
// 视频流 => WMMEDIATYPE_Video
// 音频流 => WMMEDIATYPE_Audio
// 脚本流 => WMMEDIATYPE_Script
hr = pConfig -> GetStreamType( & guid );
if ( FAILED( hr ) )
{
_tprintf( _T( " Could not get the stream type: (hr=0x%08x) " ), hr );
return ( hr );
}
else
{
if ( WMMEDIATYPE_Video == guid )
{
WORD wStreamNum = 0 ;
// 流编号
hr = pConfig -> GetStreamNumber( & wStreamNum );
if ( FAILED( hr ) )
{
_tprintf( _T( " Could not get stream number: (hr=0x%08x) " ), hr );
return ( hr );
}
// 比特率
DWORD dwBitrate = 0 ;
// 取回比特率 GetBitrate(这里取得的是视频流的比特率)
hr = pConfig -> GetBitrate( & dwBitrate );
if ( FAILED( hr ) )
{
_tprintf( _T( " Could not get bit rate: (hr=0x%08x) " ), hr );
return ( hr );
}
_tprintf( _T( " Video Stream properties: " ) );
_tprintf( _T( " Stream number: %d " ), wStreamNum );
_tprintf( _T( " Bitrate: %d bps " ), dwBitrate );
// 取得流的丰富信息
hr = PrintCodecName( pConfig );
_tprintf( _T( " " ) );
}
else if ( WMMEDIATYPE_Audio == guid )
{
WORD wStreamNum = 0 ;
hr = pConfig -> GetStreamNumber( & wStreamNum );
if ( FAILED( hr ) )
{
_tprintf( _T( " Could not get stream number: (hr=0x%08x) " ), hr );
return ( hr );
}
DWORD dwBitrate = 0 ;
// 取回比特率 GetBitrate(这里取得的是音频流的比特率)
// 注意我们通常提到的某媒体文件的比特率是指音频流比特率和视频流比特率的合计,
// 是不是还包含脚本流,这个鄙人目前还不清楚,并不是所有WMV文件都包含脚本流
hr = pConfig -> GetBitrate( & dwBitrate );
if ( FAILED( hr ) )
{
_tprintf( _T( " Could not get bit rate: (hr=0x%08x) " ), hr );
return ( hr );
}
_tprintf( _T( " Audio Stream properties: " ) );
_tprintf( _T( " Stream number: %d " ), wStreamNum );
_tprintf( _T( " Bitrate: %d bps " ), dwBitrate );
hr = PrintCodecName( pConfig );
_tprintf( _T( " " ) );
}
else if ( WMMEDIATYPE_Script == guid )
{
WORD wStreamNum = 0 ;
hr = pConfig -> GetStreamNumber( & wStreamNum );
if ( FAILED( hr ) )
{
_tprintf( _T( " Could not get stream number: (hr=0x%08x) " ), hr );
return ( hr );
}
DWORD dwBitrate = 0 ;
hr = pConfig -> GetBitrate( & dwBitrate );
if ( FAILED( hr ) )
{
_tprintf( _T( " Could not get bit rate: (hr=0x%08x) " ), hr );
return ( hr );
}
_tprintf( _T( " Script Stream properties: " ) );
_tprintf( _T( " Stream number: %d " ), wStreamNum );
_tprintf( _T( " Bitrate: %d bps " ), dwBitrate );
_tprintf( _T( " " ) );
}
}
pConfig -> Release();
}
return ( S_OK );
}
// Use IWMStreamConfig interface to access codec names
// /
HRESULT CWMProp::PrintCodecName( IWMStreamConfig * pConfig )
{
if ( NULL == pConfig )
{
return ( E_FAIL);
}
HRESULT hr = S_OK;
// 核心API IWMMediaProps
// The IWMMediaProps interface sets and retrieves the WM_MEDIA_TYPE structure
// for an input, stream, or output.
IWMMediaProps * pMediaProps = NULL;
do
{
hr = pConfig -> QueryInterface( IID_IWMMediaProps, ( void ** ) & pMediaProps );
if ( FAILED( hr ) )
{
_tprintf( _T( " QI for IWMMediaProps failed: (hr=0x%08x) " ), hr );
break ;
}
DWORD cbType = 0 ;
hr = pMediaProps -> GetMediaType( NULL, & cbType );
if ( FAILED( hr ) )
{
_tprintf( _T( " Get Mediatype failed: (hr=0x%08x) " ), hr );
break ;
}
BYTE * pData = new BYTE[ cbType ];
if ( NULL == pData )
{
hr = E_OUTOFMEMORY;
_tprintf( _T( " Out of memory: (hr=0x%08x) " ), hr );
break ;
}
ZeroMemory( pData, cbType );
hr = pMediaProps -> GetMediaType( ( WM_MEDIA_TYPE * ) pData, & cbType );
if ( FAILED( hr ) )
{
_tprintf( _T( " Get Mediatype failed: (hr=0x%08x) " ), hr );
break ;
}
//
// Audio Codec Names
//
if ( WMMEDIASUBTYPE_WMAudioV9 == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Windows Media Audio V9 " ) );
delete []pData;
pData = NULL;
break ;
}
else if ( WMMEDIASUBTYPE_WMAudio_Lossless == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Windows Media Audio V9 (Lossless Mode) " ) );
delete []pData;
pData = NULL;
break ;
}
else if ( WMMEDIASUBTYPE_WMAudioV7 == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Windows Media Audio V7/V8 " ) );
delete []pData;
pData = NULL;
break ;
}
else if ( WMMEDIASUBTYPE_WMSP1 == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Windows Media Speech Codec V9 " ) );
delete []pData;
pData = NULL;
break ;
}
else if ( WMMEDIASUBTYPE_WMAudioV2 == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Windows Media Audio V2 " ) );
delete []pData;
pData = NULL;
break ;
}
else if ( WMMEDIASUBTYPE_ACELPnet == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: ACELP.net " ) );
delete []pData;
pData = NULL;
break ;
}
//
// Video Codec Names
//
else if ( WMMEDIASUBTYPE_WMV1 == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Windows Media Video V7 " ) );
delete []pData;
pData = NULL;
break ;
}
if ( WMMEDIASUBTYPE_MSS1 == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Windows Media Screen V7 " ) );
delete []pData;
pData = NULL;
break ;
}
if ( WMMEDIASUBTYPE_MSS2 == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Windows Media Screen V9 " ) );
delete []pData;
pData = NULL;
break ;
}
else if ( WMMEDIASUBTYPE_WMV2 == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Windows Media Video V8 " ) );
delete []pData;
pData = NULL;
break ;
}
else if ( WMMEDIASUBTYPE_WMV3 == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Windows Media Video V9 " ) );
delete []pData;
pData = NULL;
break ;
}
else if ( WMMEDIASUBTYPE_MP43 == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: Microsoft MPEG-4 Video Codec V3 " ) );
delete []pData;
pData = NULL;
break ;
}
else if ( WMMEDIASUBTYPE_MP4S == ( ( WM_MEDIA_TYPE * ) pData ) -> subtype )
{
_tprintf( _T( " Codec Name: ISO MPEG-4 Video V1 " ) );
delete []pData;
pData = NULL;
break ;
}
} while ( FALSE );
SAFE_RELEASE( pMediaProps );
return ( hr );
}
※关联文章推荐:
1、来自 陆其明's Blog
《Windows Media Format SDK系统概述》
http://blog.youkuaiyun.com/happydeer/archive/2004/11/29/198262.aspx