2180 lines
61 KiB
C++
2180 lines
61 KiB
C++
//*****************************************************************************
|
|
//
|
|
// Microsoft Windows Media
|
|
// Copyright (C) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// FileName: GenProfile_lib.cpp
|
|
//
|
|
// Abstract: The implementation for the GenProfile static library.
|
|
//
|
|
//*****************************************************************************
|
|
|
|
#include "stdafx.h"
|
|
#include "GenProfile_lib.h"
|
|
#include <intsafe.h>
|
|
|
|
struct PIXEL_FORMAT
|
|
{
|
|
const GUID* guidFormat;
|
|
DWORD dwFourCC;
|
|
WORD wBitsPerPixel;
|
|
};
|
|
|
|
PIXEL_FORMAT PixelFormats[] =
|
|
{
|
|
{ &WMMEDIASUBTYPE_RGB555, BI_RGB, 16 },
|
|
{ &WMMEDIASUBTYPE_RGB24, BI_RGB, 24 },
|
|
{ &WMMEDIASUBTYPE_RGB32, BI_RGB, 32 },
|
|
{ &WMMEDIASUBTYPE_I420, 0x30323449, 12 },
|
|
{ &WMMEDIASUBTYPE_IYUV, 0x56555949, 12 },
|
|
{ &WMMEDIASUBTYPE_YV12, 0x32315659, 12 },
|
|
{ &WMMEDIASUBTYPE_YUY2, 0x32595559, 16 },
|
|
{ &WMMEDIASUBTYPE_UYVY, 0x59565955, 16 },
|
|
{ &WMMEDIASUBTYPE_YVYU, 0x55595659, 16 }
|
|
};
|
|
|
|
|
|
DWORD WaveFrequency[] =
|
|
{
|
|
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
|
|
};
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CopyMediaType()
|
|
// Desc: Allocates memory for a WM_MEDIA_TYPE and its format data and
|
|
// copies an existing media type into it.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CopyMediaType( WM_MEDIA_TYPE** ppmtDestination,
|
|
WM_MEDIA_TYPE* pmtSource )
|
|
{
|
|
if ( !ppmtDestination )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if ( !pmtSource )
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
ULONG SizeToAlloc;
|
|
|
|
if (FAILED(ULongAdd(sizeof( WM_MEDIA_TYPE ), pmtSource->cbFormat, &SizeToAlloc)))
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
|
|
}
|
|
|
|
//
|
|
// Create enough space for the media type and its format data
|
|
//
|
|
*ppmtDestination = (WM_MEDIA_TYPE*) new BYTE[ SizeToAlloc ];
|
|
if ( !*ppmtDestination)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Copy the media type and the format data
|
|
//
|
|
memcpy( *ppmtDestination, pmtSource, sizeof( WM_MEDIA_TYPE ) );
|
|
(*ppmtDestination)->pbFormat = ( ((BYTE*) *ppmtDestination) + sizeof( WM_MEDIA_TYPE ) ); // Format data is immediately after media type
|
|
memcpy( (*ppmtDestination)->pbFormat, pmtSource->pbFormat, pmtSource->cbFormat );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: EnsureIWMCodecInfo3()
|
|
// Desc: Creates an IWMCodecInfo3 interface if none exists, and ensures
|
|
// an outstanding reference either way. This way the IWMCodecInfo3
|
|
// object is guaranteed to exist and isn't released too many times.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP EnsureIWMCodecInfo3( IWMCodecInfo3** ppCodecInfo3 )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( !ppCodecInfo3 )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
do
|
|
{
|
|
if ( !*ppCodecInfo3 )
|
|
{
|
|
//
|
|
// Create a new IWMCodecInfo3 object
|
|
//
|
|
IWMProfileManager* pProfileManager;
|
|
hr = WMCreateProfileManager( &pProfileManager );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pProfileManager );
|
|
|
|
hr = pProfileManager->QueryInterface( IID_IWMCodecInfo3, (void**) ppCodecInfo3 );
|
|
SAFE_RELEASE( pProfileManager );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Add a reference to the existing object, so that it won't be destroyed during cleanup
|
|
//
|
|
SAFE_ADDREF( (*ppCodecInfo3) );
|
|
}
|
|
assert( *ppCodecInfo3 );
|
|
|
|
//
|
|
// It should now not matter if the IWMCodecInfo3 was just created or was passed in
|
|
//
|
|
}
|
|
while ( FALSE );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: SetCodecVBRSettings()
|
|
// Desc: Enables VBR with the specified number of passes, or disables it.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP SetCodecVBRSettings( IWMCodecInfo3* pCodecInfo3,
|
|
GUID guidCodecType,
|
|
DWORD dwCodecIndex,
|
|
BOOL fIsVBR,
|
|
DWORD dwVBRPasses )
|
|
{
|
|
HRESULT hr;
|
|
|
|
if ( !pCodecInfo3 )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
do
|
|
{
|
|
//
|
|
// Configure the codec to use or not use VBR as requested
|
|
//
|
|
hr = pCodecInfo3->SetCodecEnumerationSetting( guidCodecType, dwCodecIndex, g_wszVBREnabled, WMT_TYPE_BOOL, (BYTE*) &fIsVBR, sizeof( BOOL ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
//
|
|
// If VBR is requested, then it's a problem, but otherwise the codec may just not support VBR
|
|
//
|
|
if ( ( !fIsVBR ) && ( NS_E_UNSUPPORTED_PROPERTY == hr ) )
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( fIsVBR )
|
|
{
|
|
hr = pCodecInfo3->SetCodecEnumerationSetting( guidCodecType, dwCodecIndex, g_wszNumPasses, WMT_TYPE_DWORD, (BYTE*) &dwVBRPasses, sizeof( DWORD ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
while ( FALSE );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: SetStreamLanguage()
|
|
// Desc: Sets the language in the stream configuration.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP SetStreamLanguage( IWMStreamConfig * pStreamConfig, LCID dwLanguage )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig3 * pStreamConfig3 = NULL;
|
|
IMultiLanguage * pMLang = NULL;
|
|
BSTR bstrLanguage = NULL;
|
|
|
|
do
|
|
{
|
|
hr = CoCreateInstance( CLSID_CMultiLanguage,
|
|
NULL,
|
|
CLSCTX_ALL,
|
|
IID_IMultiLanguage,
|
|
(VOID **) &pMLang );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pMLang->GetRfc1766FromLcid( dwLanguage, &bstrLanguage );
|
|
if( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->QueryInterface( IID_IWMStreamConfig3, (void**)&pStreamConfig3 );
|
|
if( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig3->SetLanguage( bstrLanguage );
|
|
if( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (FALSE);
|
|
|
|
SAFE_RELEASE( pMLang );
|
|
SAFE_RELEASE( pStreamConfig3 );
|
|
|
|
if ( !bstrLanguage )
|
|
{
|
|
SysFreeString( bstrLanguage );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
** Functions that create media types for the various stream types
|
|
*/
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateUncompressedAudioMediaType()
|
|
// Desc: Initializes a WM_MEDIA_TYPE for uncompressed audio.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateUncompressedAudioMediaType( WM_MEDIA_TYPE** ppmtMediaType,
|
|
DWORD dwSamplesPerSecond,
|
|
WORD wNumChannels,
|
|
WORD wBitsPerSample )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WM_MEDIA_TYPE mtUncompressedAudio;
|
|
WAVEFORMATEX wfxUncompressedAudio;
|
|
|
|
if ( !ppmtMediaType )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
//
|
|
// pCodecInfo3 is allowed to be NULL, since CreateMediatypeForFormat calls EnsureIWMCodecInfo3
|
|
//
|
|
|
|
do
|
|
{
|
|
//
|
|
// Setup the local copy of the uncompressed media type
|
|
//
|
|
ZeroMemory( &mtUncompressedAudio, sizeof( mtUncompressedAudio ) );
|
|
|
|
mtUncompressedAudio.majortype = WMMEDIATYPE_Audio;
|
|
mtUncompressedAudio.subtype = WMMEDIASUBTYPE_PCM;
|
|
mtUncompressedAudio.bFixedSizeSamples = TRUE;
|
|
mtUncompressedAudio.bTemporalCompression = FALSE;
|
|
mtUncompressedAudio.lSampleSize = wNumChannels * wBitsPerSample / 8;
|
|
mtUncompressedAudio.formattype = WMFORMAT_WaveFormatEx;
|
|
mtUncompressedAudio.pUnk = NULL;
|
|
mtUncompressedAudio.cbFormat = sizeof( WAVEFORMATEX );
|
|
mtUncompressedAudio.pbFormat = (BYTE*) &wfxUncompressedAudio;
|
|
|
|
//
|
|
// Configure the WAVEFORMATEX structure for the uncompressed audio
|
|
//
|
|
ZeroMemory( &wfxUncompressedAudio, sizeof( wfxUncompressedAudio ) );
|
|
|
|
wfxUncompressedAudio.wFormatTag = 1;
|
|
wfxUncompressedAudio.nChannels = wNumChannels;
|
|
wfxUncompressedAudio.nSamplesPerSec = dwSamplesPerSecond;
|
|
wfxUncompressedAudio.nAvgBytesPerSec = dwSamplesPerSecond * ( wNumChannels * wBitsPerSample / 8 );
|
|
wfxUncompressedAudio.nBlockAlign = wNumChannels * wBitsPerSample / 8;
|
|
wfxUncompressedAudio.wBitsPerSample = wBitsPerSample;
|
|
wfxUncompressedAudio.cbSize = sizeof( WAVEFORMATEX );
|
|
|
|
//
|
|
// Return a copy of the media type to the caller, since the mediatype is on the stack
|
|
//
|
|
hr = CopyMediaType( ppmtMediaType, &mtUncompressedAudio );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while( FALSE );
|
|
|
|
return( hr );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateVideoMediaType()
|
|
// Desc: Initializes a WM_MEDIA_TYPE for video.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateVideoMediaType( WM_MEDIA_TYPE** ppmtMediaType,
|
|
IWMCodecInfo3* pCodecInfo3,
|
|
DWORD dwCodecIndex,
|
|
DWORD dwFPS,
|
|
DWORD dwWidth,
|
|
DWORD dwHeight,
|
|
DWORD dwBitrate,
|
|
BOOL fIsVBR,
|
|
DWORD dwNumberOfPasses )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WM_MEDIA_TYPE *pMediaType = NULL;
|
|
WMVIDEOINFOHEADER *pVIH;
|
|
|
|
if ( !ppmtMediaType )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
//
|
|
// pCodecInfo3 is allowed to be NULL, since CreateMediatypeForFormat calls EnsureIWMCodecInfo3
|
|
//
|
|
|
|
do
|
|
{
|
|
//
|
|
// Get the mediatype for the codec
|
|
//
|
|
hr = CreateMediatypeForFormat( &pMediaType,
|
|
pCodecInfo3,
|
|
NULL,
|
|
WMMEDIATYPE_Video,
|
|
dwCodecIndex,
|
|
0,
|
|
fIsVBR,
|
|
dwNumberOfPasses );
|
|
if( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaType );
|
|
|
|
//
|
|
// Configure the WMVIDEOINFOHEADER structure of the media type
|
|
//
|
|
pVIH = (WMVIDEOINFOHEADER*) pMediaType->pbFormat;
|
|
pVIH->dwBitRate = dwBitrate;
|
|
|
|
pVIH->rcSource.right = dwWidth;
|
|
pVIH->rcSource.bottom = dwHeight;
|
|
pVIH->rcTarget.right = dwWidth;
|
|
pVIH->rcTarget.bottom = dwHeight;
|
|
pVIH->bmiHeader.biWidth = dwWidth;
|
|
pVIH->bmiHeader.biHeight = dwHeight;
|
|
|
|
pVIH->AvgTimePerFrame = ( (LONGLONG) 10000000 ) / ( (LONGLONG) dwFPS );
|
|
|
|
//
|
|
// Return a copy of the media type to the caller
|
|
//
|
|
hr = CopyMediaType( ppmtMediaType, pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while( FALSE );
|
|
|
|
SAFE_ARRAYDELETE( pMediaType );
|
|
|
|
return( hr );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateUncompressedVideoMediaType()
|
|
// Desc: Initializes a WM_MEDIA_TYPE for uncompressed video.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateUncompressedVideoMediaType( WM_MEDIA_TYPE** ppmtMediaType,
|
|
GUID guidFormat,
|
|
DWORD dwFourCC,
|
|
WORD wBitsPerPixel,
|
|
BYTE* pbPaletteData,
|
|
DWORD cbPaletteDataSize,
|
|
DWORD dwFPS,
|
|
DWORD dwWidth,
|
|
DWORD dwHeight )
|
|
{
|
|
const DWORD BITFIELD_DATA_SIZE = sizeof( RGBQUAD ) * 3;
|
|
|
|
HRESULT hr;
|
|
WM_MEDIA_TYPE mtUncompressedVideo;
|
|
WMVIDEOINFOHEADER* pvihUncompressedVideo;
|
|
BYTE* pbFormatData = NULL;
|
|
DWORD dwFormatDataSize;
|
|
DWORD dwMaxColors;
|
|
BOOL fPalettePresent;
|
|
BYTE* pbPostVIHData;
|
|
DWORD cbExpectedPostVIHDataSize;
|
|
BOOL fBitfieldsPresent;
|
|
|
|
if ( !ppmtMediaType )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
//
|
|
// pCodecInfo3 is allowed to be NULL, since CreateMediatypeForFormat calls EnsureIWMCodecInfo3
|
|
//
|
|
|
|
//
|
|
// The width must be on a byte boundry
|
|
//
|
|
if ( dwWidth * wBitsPerPixel % 8 != 0 )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// The width, height, and frames per second must all be non-zero
|
|
//
|
|
if ( 0 == dwWidth || 0 == dwHeight || 0 == dwFPS )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
do
|
|
{
|
|
//
|
|
// Allocate space for the format data ( WMVIDEOINFOHEADER + pallete data )
|
|
//
|
|
dwFormatDataSize = sizeof( WMVIDEOINFOHEADER );
|
|
cbExpectedPostVIHDataSize = 0;
|
|
|
|
//
|
|
// If there are <= 8 bits / pixel, then there needs to be palette data following the WMVIDEOINFOHEADER
|
|
//
|
|
fPalettePresent = ( wBitsPerPixel <= 8 );
|
|
if ( fPalettePresent )
|
|
{
|
|
dwMaxColors = 1 << wBitsPerPixel;
|
|
cbExpectedPostVIHDataSize = sizeof( RGBQUAD ) * dwMaxColors;
|
|
}
|
|
|
|
//
|
|
// If the format uses bitfields, then make sure the data is following
|
|
//
|
|
fBitfieldsPresent = ( BI_BITFIELDS == dwFourCC );
|
|
if ( fBitfieldsPresent )
|
|
{
|
|
cbExpectedPostVIHDataSize = BITFIELD_DATA_SIZE;
|
|
}
|
|
|
|
if ( fPalettePresent || fBitfieldsPresent )
|
|
{
|
|
dwFormatDataSize += cbExpectedPostVIHDataSize;
|
|
if ( !pbPaletteData || ( cbPaletteDataSize != cbExpectedPostVIHDataSize ) )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pbFormatData = new BYTE[ dwFormatDataSize ];
|
|
if ( !pbFormatData )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
ZeroMemory( pbFormatData, dwFormatDataSize );
|
|
|
|
pbPostVIHData = pbFormatData + sizeof( WMVIDEOINFOHEADER );
|
|
pvihUncompressedVideo = (WMVIDEOINFOHEADER*) pbFormatData;
|
|
|
|
//
|
|
// Set up the local copy of the uncompressed media type
|
|
//
|
|
ZeroMemory( &mtUncompressedVideo, sizeof( mtUncompressedVideo ) );
|
|
|
|
mtUncompressedVideo.majortype = WMMEDIATYPE_Video;
|
|
mtUncompressedVideo.subtype = guidFormat;
|
|
mtUncompressedVideo.bFixedSizeSamples = TRUE;
|
|
mtUncompressedVideo.bTemporalCompression = FALSE;
|
|
mtUncompressedVideo.lSampleSize = wBitsPerPixel * dwWidth * dwHeight / 8;
|
|
mtUncompressedVideo.formattype = WMFORMAT_VideoInfo;
|
|
mtUncompressedVideo.pUnk = NULL;
|
|
mtUncompressedVideo.cbFormat = dwFormatDataSize;
|
|
mtUncompressedVideo.pbFormat = (BYTE*) pbFormatData;
|
|
|
|
//
|
|
// Configure the WMVIDEOINFOHEADER structure for uncompressed video
|
|
//
|
|
pvihUncompressedVideo->dwBitRate = mtUncompressedVideo.lSampleSize * dwFPS * 8;
|
|
|
|
pvihUncompressedVideo->rcSource.right = dwWidth;
|
|
pvihUncompressedVideo->rcSource.bottom = dwHeight;
|
|
pvihUncompressedVideo->rcTarget.right = dwWidth;
|
|
pvihUncompressedVideo->rcTarget.bottom = dwHeight;
|
|
|
|
|
|
pvihUncompressedVideo->bmiHeader.biSizeImage = mtUncompressedVideo.lSampleSize;
|
|
pvihUncompressedVideo->bmiHeader.biPlanes = 1;
|
|
pvihUncompressedVideo->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
|
|
pvihUncompressedVideo->bmiHeader.biWidth = dwWidth;
|
|
pvihUncompressedVideo->bmiHeader.biHeight = dwHeight;
|
|
pvihUncompressedVideo->bmiHeader.biCompression = dwFourCC;
|
|
pvihUncompressedVideo->bmiHeader.biBitCount = wBitsPerPixel;
|
|
|
|
pvihUncompressedVideo->AvgTimePerFrame = ( (LONGLONG) 10000000 ) / ( (LONGLONG) dwFPS );
|
|
|
|
//
|
|
// Copy the palette information, if present
|
|
//
|
|
if ( ( fPalettePresent || fBitfieldsPresent ) && pbPaletteData )
|
|
{
|
|
memcpy( pbPostVIHData, pbPaletteData, cbExpectedPostVIHDataSize );
|
|
}
|
|
|
|
//
|
|
// Return a copy of the media type to the caller, since the media type is on the stack
|
|
//
|
|
hr = CopyMediaType( ppmtMediaType, &mtUncompressedVideo );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while( FALSE );
|
|
|
|
SAFE_ARRAYDELETE( pbFormatData );
|
|
|
|
return( hr );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateScriptMediaType()
|
|
// Desc: Initializes a WM_MEDIA_TYPE for script.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateScriptMediaType( WM_MEDIA_TYPE** ppmtMediaType )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WM_MEDIA_TYPE wmtMediaType;
|
|
WMSCRIPTFORMAT wsfScriptFormat;
|
|
|
|
assert( ppmtMediaType );
|
|
|
|
do
|
|
{
|
|
ZeroMemory( &wmtMediaType, sizeof( wmtMediaType ) );
|
|
|
|
//
|
|
// Configure media type
|
|
//
|
|
wmtMediaType.majortype = WMMEDIATYPE_Script;
|
|
wmtMediaType.subtype = GUID_NULL;
|
|
wmtMediaType.bFixedSizeSamples = FALSE;
|
|
wmtMediaType.bTemporalCompression = TRUE;
|
|
wmtMediaType.lSampleSize = 0;
|
|
wmtMediaType.formattype = WMFORMAT_Script;
|
|
wmtMediaType.cbFormat = sizeof( WMSCRIPTFORMAT );
|
|
wmtMediaType.pbFormat = (BYTE*) &wsfScriptFormat;
|
|
|
|
wsfScriptFormat.scriptType = WMSCRIPTTYPE_TwoStrings;
|
|
|
|
//
|
|
// Return a copy of the media type to the caller
|
|
//
|
|
hr = CopyMediaType( ppmtMediaType, &wmtMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while ( FALSE );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateImageMediaType()
|
|
// Desc: Initializes a WM_MEDIA_TYPE for image.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateImageMediaType( WM_MEDIA_TYPE** ppmtMediaType,
|
|
DWORD dwWidth,
|
|
DWORD dwHeight,
|
|
DWORD dwBitrate )
|
|
{
|
|
static const WORD BIT_COUNT = 24;
|
|
|
|
HRESULT hr = S_OK;
|
|
WM_MEDIA_TYPE wmtMediaType;
|
|
WMVIDEOINFOHEADER vihVideoInfo;
|
|
|
|
do
|
|
{
|
|
ZeroMemory( &wmtMediaType, sizeof( wmtMediaType ) );
|
|
|
|
//
|
|
// Set up the WM_MEDIA_TYPE structure
|
|
//
|
|
wmtMediaType.majortype = WMMEDIATYPE_Image;
|
|
wmtMediaType.subtype = WMMEDIASUBTYPE_RGB24;
|
|
wmtMediaType.bFixedSizeSamples = FALSE;
|
|
wmtMediaType.bTemporalCompression = FALSE;
|
|
wmtMediaType.lSampleSize = 0;
|
|
wmtMediaType.bFixedSizeSamples = FALSE;
|
|
wmtMediaType.bTemporalCompression = FALSE;
|
|
wmtMediaType.lSampleSize = 0;
|
|
|
|
wmtMediaType.formattype = WMFORMAT_VideoInfo;
|
|
wmtMediaType.pUnk = NULL;
|
|
wmtMediaType.cbFormat = sizeof( WMVIDEOINFOHEADER );
|
|
wmtMediaType.pbFormat = (BYTE*) &vihVideoInfo;
|
|
|
|
//
|
|
// Set up the WMVIDEOINFOHEADER structure
|
|
//
|
|
ZeroMemory( &vihVideoInfo, sizeof( vihVideoInfo ) );
|
|
|
|
vihVideoInfo.rcSource.left = 0;
|
|
vihVideoInfo.rcSource.top = 0;
|
|
vihVideoInfo.rcSource.bottom = dwHeight;
|
|
vihVideoInfo.rcSource.right = dwWidth;
|
|
vihVideoInfo.rcTarget = vihVideoInfo.rcSource;
|
|
|
|
vihVideoInfo.dwBitRate = dwBitrate;
|
|
vihVideoInfo.dwBitErrorRate = 0;
|
|
vihVideoInfo.AvgTimePerFrame = 0;
|
|
|
|
vihVideoInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
|
|
vihVideoInfo.bmiHeader.biWidth = dwWidth;
|
|
vihVideoInfo.bmiHeader.biHeight = dwHeight;
|
|
vihVideoInfo.bmiHeader.biPlanes = 1;
|
|
vihVideoInfo.bmiHeader.biBitCount = BIT_COUNT;
|
|
vihVideoInfo.bmiHeader.biCompression = BI_RGB;
|
|
vihVideoInfo.bmiHeader.biSizeImage = ( dwHeight * dwWidth * vihVideoInfo.bmiHeader.biBitCount ) / 8;
|
|
vihVideoInfo.bmiHeader.biXPelsPerMeter = 0;
|
|
vihVideoInfo.bmiHeader.biYPelsPerMeter = 0;
|
|
vihVideoInfo.bmiHeader.biClrUsed = 0;
|
|
vihVideoInfo.bmiHeader.biClrImportant = 0;
|
|
|
|
//
|
|
// Return a copy of the media type to the caller
|
|
//
|
|
hr = CopyMediaType( ppmtMediaType, &wmtMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while ( FALSE );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateWebMediaType()
|
|
// Desc: Initializes a WM_MEDIA_TYPE for Web media.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateWebMediaType( WM_MEDIA_TYPE** ppmtMediaType )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WM_MEDIA_TYPE wmtMediaType;
|
|
WMT_WEBSTREAM_FORMAT wwfWebFormat;
|
|
|
|
do
|
|
{
|
|
ZeroMemory( &wmtMediaType, sizeof( wmtMediaType ) );
|
|
|
|
//
|
|
// Configure media type
|
|
//
|
|
wmtMediaType.majortype = WMMEDIATYPE_FileTransfer;
|
|
wmtMediaType.subtype = WMMEDIASUBTYPE_WebStream;
|
|
wmtMediaType.bFixedSizeSamples = FALSE;
|
|
wmtMediaType.bTemporalCompression = TRUE;
|
|
wmtMediaType.lSampleSize = 0;
|
|
wmtMediaType.formattype = WMFORMAT_WebStream;
|
|
wmtMediaType.pUnk = NULL;
|
|
wmtMediaType.cbFormat = sizeof( WMT_WEBSTREAM_FORMAT );
|
|
wmtMediaType.pbFormat = (BYTE*) &wwfWebFormat;
|
|
|
|
ZeroMemory( &wwfWebFormat, sizeof( wwfWebFormat ) );
|
|
wwfWebFormat.cbSize = sizeof( WMT_WEBSTREAM_FORMAT );
|
|
wwfWebFormat.cbSampleHeaderFixedData = sizeof( WMT_WEBSTREAM_SAMPLE_HEADER );
|
|
wwfWebFormat.wVersion = 1;
|
|
wwfWebFormat.wReserved = 0;
|
|
|
|
//
|
|
// Return a copy of the media type to the caller
|
|
//
|
|
hr = CopyMediaType( ppmtMediaType, &wmtMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while ( FALSE );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateFileMediaType()
|
|
// Desc: Initializes a WM_MEDIA_TYPE for file transfer.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateFileMediaType( WM_MEDIA_TYPE** ppmtMediaType )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WM_MEDIA_TYPE wmtMediaType;
|
|
|
|
do
|
|
{
|
|
ZeroMemory( &wmtMediaType, sizeof( wmtMediaType ) );
|
|
|
|
//
|
|
// Configure media type
|
|
//
|
|
wmtMediaType.majortype = WMMEDIATYPE_FileTransfer;
|
|
wmtMediaType.subtype = GUID_NULL;
|
|
wmtMediaType.bFixedSizeSamples = FALSE;
|
|
wmtMediaType.bTemporalCompression = FALSE;
|
|
wmtMediaType.lSampleSize = 0;
|
|
|
|
//
|
|
// Return a copy of the media type to the caller
|
|
//
|
|
hr = CopyMediaType( ppmtMediaType, &wmtMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while ( FALSE );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
** Functions that create various stream types
|
|
*/
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateAudioStream()
|
|
// Desc: Creates an audio stream and returns its configuration object.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateAudioStream( IWMStreamConfig** ppStreamConfig,
|
|
IWMCodecInfo3* pCodecInfo3,
|
|
IWMProfile *pProfile,
|
|
DWORD dwBufferWindow,
|
|
DWORD dwCodecIndex,
|
|
DWORD dwFormatIndex,
|
|
BOOL fIsVBR,
|
|
DWORD dwNumberOfPasses,
|
|
LCID dwLanguage )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig* pStreamConfig = NULL;
|
|
IWMStreamConfig* pFormatConfig = NULL;
|
|
IWMPropertyVault* pPropertyVault = NULL;
|
|
WM_MEDIA_TYPE* pMediaType = NULL;
|
|
IWMMediaProps* pMediaProps = NULL;
|
|
DWORD dwBitrate;
|
|
|
|
if ( !ppStreamConfig )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if ( !pProfile )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// pCodecInfo3 is allowed to be NULL, since CreateMediatypeForFormat calls EnsureIWMCodecInfo3
|
|
//
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create the audio stream
|
|
//
|
|
hr = pProfile->CreateNewStream( WMMEDIATYPE_Audio, &pStreamConfig );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pStreamConfig );
|
|
|
|
//
|
|
// Create the media type and get the format's stream configuration
|
|
//
|
|
hr = CreateMediatypeForFormat( &pMediaType,
|
|
pCodecInfo3,
|
|
&pFormatConfig,
|
|
WMMEDIATYPE_Audio,
|
|
dwCodecIndex,
|
|
dwFormatIndex,
|
|
fIsVBR,
|
|
dwNumberOfPasses );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaType );
|
|
|
|
//
|
|
// Configure the new audio stream
|
|
//
|
|
hr = pFormatConfig->GetBitrate( &dwBitrate );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->SetBitrate( dwBitrate );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->SetBufferWindow( dwBufferWindow );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the media type on the stream
|
|
//
|
|
hr = pStreamConfig->QueryInterface( IID_IWMMediaProps, (void**) &pMediaProps );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaProps );
|
|
|
|
hr = pMediaProps->SetMediaType( pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If this profile will be used by the writer, we should set
|
|
// the VBREnabled attribute properly
|
|
//
|
|
if ( SUCCEEDED( pStreamConfig->QueryInterface( IID_IWMPropertyVault, (void**)&pPropertyVault ) ) )
|
|
{
|
|
assert( pPropertyVault );
|
|
pPropertyVault->SetProperty( g_wszVBREnabled, WMT_TYPE_BOOL, (BYTE*)&fIsVBR, sizeof( fIsVBR ) );
|
|
|
|
SAFE_RELEASE( pPropertyVault );
|
|
}
|
|
|
|
hr = SetStreamLanguage( pStreamConfig, dwLanguage );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Return the pStreamConfig to the caller
|
|
//
|
|
SAFE_ADDREF( pStreamConfig );
|
|
*ppStreamConfig = pStreamConfig;
|
|
}
|
|
while ( FALSE );
|
|
|
|
SAFE_RELEASE( pStreamConfig );
|
|
SAFE_RELEASE( pFormatConfig );
|
|
SAFE_RELEASE( pPropertyVault );
|
|
SAFE_ARRAYDELETE( pMediaType );
|
|
SAFE_RELEASE( pMediaProps );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateAudioStream()
|
|
// Desc: Creates an audio stream and returns its configuration object.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateUncompressedAudioStream( IWMStreamConfig** ppStreamConfig,
|
|
IWMProfile *pProfile,
|
|
DWORD dwSamplesPerSecond,
|
|
WORD wNumChannels,
|
|
WORD wBitsPerSample,
|
|
LCID dwLanguage )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig* pStreamConfig = NULL;
|
|
IWMPropertyVault* pPropertyVault = NULL;
|
|
WM_MEDIA_TYPE* pMediaType = NULL;
|
|
IWMMediaProps* pMediaProps = NULL;
|
|
BOOL fFalse = FALSE;
|
|
|
|
if ( !ppStreamConfig )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if ( !pProfile )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// pCodecInfo3 is allowed to be NULL, since CreateMediatypeForFormat calls EnsureIWMCodecInfo3
|
|
//
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create the audio stream
|
|
//
|
|
hr = pProfile->CreateNewStream( WMMEDIATYPE_Audio, &pStreamConfig );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pStreamConfig );
|
|
|
|
//
|
|
// Create the media type for the uncompressed audio
|
|
//
|
|
hr = CreateUncompressedAudioMediaType( &pMediaType,
|
|
dwSamplesPerSecond,
|
|
wNumChannels,
|
|
wBitsPerSample );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaType );
|
|
|
|
//
|
|
// Configure the new audio stream
|
|
//
|
|
hr = pStreamConfig->SetBitrate( dwSamplesPerSecond * wNumChannels * wBitsPerSample );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->SetBufferWindow( 0 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the media type on the stream
|
|
//
|
|
hr = pStreamConfig->QueryInterface( IID_IWMMediaProps, (void**) &pMediaProps );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaProps );
|
|
|
|
hr = pMediaProps->SetMediaType( pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If this profile will be used by the writer, we should set
|
|
// VBREnabled attribute properly
|
|
//
|
|
if ( SUCCEEDED( pStreamConfig->QueryInterface( IID_IWMPropertyVault, (void**)&pPropertyVault ) ) )
|
|
{
|
|
assert( pPropertyVault );
|
|
pPropertyVault->SetProperty( g_wszVBREnabled, WMT_TYPE_BOOL, (BYTE*)&fFalse, sizeof( fFalse ) );
|
|
|
|
SAFE_RELEASE( pPropertyVault );
|
|
}
|
|
|
|
hr = SetStreamLanguage( pStreamConfig, dwLanguage );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Return the pStreamConfig to the caller
|
|
//
|
|
SAFE_ADDREF( pStreamConfig );
|
|
*ppStreamConfig = pStreamConfig;
|
|
}
|
|
while ( FALSE );
|
|
|
|
SAFE_RELEASE( pStreamConfig );
|
|
SAFE_RELEASE( pPropertyVault );
|
|
SAFE_ARRAYDELETE( pMediaType );
|
|
SAFE_RELEASE( pMediaProps );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateVideoStream()
|
|
// Desc: Creates a video stream and returns its configuration object.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateVideoStream( IWMStreamConfig** ppStreamConfig,
|
|
IWMCodecInfo3* pCodecInfo3,
|
|
IWMProfile *pProfile,
|
|
DWORD dwCodecIndex,
|
|
DWORD dwBitrate,
|
|
DWORD dwBufferWindow,
|
|
DWORD dwWidth,
|
|
DWORD dwHeight,
|
|
DWORD dwFPS,
|
|
DWORD dwQuality,
|
|
DWORD dwSecPerKey,
|
|
BOOL fIsVBR,
|
|
VIDEO_VBR_MODE vbrMode,
|
|
DWORD dwVBRQuality,
|
|
DWORD dwMaxBitrate,
|
|
DWORD dwMaxBufferWindow,
|
|
LCID dwLanguage )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig* pStreamConfig = NULL;
|
|
IWMPropertyVault* pPropertyVault = NULL;
|
|
WM_MEDIA_TYPE* pMediaType = NULL;
|
|
IWMVideoMediaProps* pVideoMediaProps = NULL;
|
|
DWORD dwNumberOfPasses;
|
|
|
|
if ( !ppStreamConfig )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if ( !pProfile )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
//
|
|
// pCodecInfo3 is allowed to be NULL, since CreateVideoMediatype calls EnsureIWMCodecInfo3
|
|
//
|
|
|
|
do
|
|
{
|
|
switch( vbrMode )
|
|
{
|
|
case VBR_OFF:
|
|
dwNumberOfPasses = 0;
|
|
break;
|
|
|
|
case VBR_QUALITYBASED:
|
|
dwNumberOfPasses = 1;
|
|
break;
|
|
|
|
case VBR_CONSTRAINED:
|
|
dwNumberOfPasses = 2;
|
|
break;
|
|
|
|
case VBR_UNCONSTRAINED:
|
|
dwNumberOfPasses = 2;
|
|
break;
|
|
|
|
default:
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create the video stream
|
|
//
|
|
hr = pProfile->CreateNewStream( WMMEDIATYPE_Video, &pStreamConfig );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pStreamConfig );
|
|
|
|
//
|
|
// Configure the new video stream
|
|
//
|
|
hr = pStreamConfig->SetBitrate( dwBitrate );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->SetBufferWindow( dwBufferWindow );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the media type for the stream
|
|
//
|
|
hr = CreateVideoMediaType( &pMediaType,
|
|
pCodecInfo3,
|
|
dwCodecIndex,
|
|
dwFPS,
|
|
dwWidth,
|
|
dwHeight,
|
|
dwBitrate,
|
|
fIsVBR,
|
|
dwNumberOfPasses );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaType );
|
|
|
|
hr = pStreamConfig->QueryInterface( IID_IWMVideoMediaProps, (void**) &pVideoMediaProps );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pVideoMediaProps );
|
|
|
|
hr = pVideoMediaProps->SetMediaType( pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set quality and MaxKeyFrameSpacing on the IWMVideoMediaProps object
|
|
//
|
|
hr = pVideoMediaProps->SetQuality( dwQuality );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pVideoMediaProps->SetMaxKeyFrameSpacing( (LONGLONG) dwSecPerKey * 10000000 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If this profile will be used by writer, we should set the properties
|
|
// on the stream configuration
|
|
//
|
|
if ( SUCCEEDED( pStreamConfig->QueryInterface( IID_IWMPropertyVault, (void**)&pPropertyVault ) ) )
|
|
{
|
|
assert( pPropertyVault );
|
|
hr = pPropertyVault->SetProperty( g_wszVBREnabled, WMT_TYPE_BOOL, (BYTE*) &fIsVBR, sizeof( fIsVBR ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
switch( vbrMode )
|
|
{
|
|
case VBR_QUALITYBASED:
|
|
//
|
|
// Only the quality needs to be set
|
|
//
|
|
hr = pPropertyVault->SetProperty( g_wszVBRQuality, WMT_TYPE_DWORD, (BYTE*) &dwVBRQuality, sizeof( DWORD ) );
|
|
break;
|
|
|
|
case VBR_CONSTRAINED:
|
|
//
|
|
// The peak bitrate and, optionally, max buffer window need to be set
|
|
//
|
|
hr = pPropertyVault->SetProperty( g_wszVBRBitrateMax, WMT_TYPE_DWORD, (BYTE*) &dwMaxBitrate, sizeof( DWORD ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( dwMaxBufferWindow != 0 )
|
|
{
|
|
hr = pPropertyVault->SetProperty( g_wszVBRBufferWindowMax, WMT_TYPE_DWORD, (BYTE*) &dwMaxBufferWindow, sizeof( DWORD ) );
|
|
}
|
|
break;
|
|
|
|
case VBR_UNCONSTRAINED:
|
|
break;
|
|
|
|
case VBR_OFF:
|
|
break;
|
|
|
|
default:
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
SAFE_RELEASE( pPropertyVault );
|
|
}
|
|
|
|
hr = SetStreamLanguage( pStreamConfig, dwLanguage );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Return the pStreamConfig to the caller
|
|
//
|
|
SAFE_ADDREF( pStreamConfig );
|
|
*ppStreamConfig = pStreamConfig;
|
|
}
|
|
while ( FALSE );
|
|
|
|
SAFE_RELEASE( pStreamConfig );
|
|
SAFE_RELEASE( pPropertyVault );
|
|
SAFE_ARRAYDELETE( pMediaType );
|
|
SAFE_RELEASE( pVideoMediaProps );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateUncompressedVideoStream()
|
|
// Desc: Creates an uncompressed video stream and returns its configuration object.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateUncompressedVideoStream( IWMStreamConfig** ppStreamConfig,
|
|
IWMProfile *pProfile,
|
|
GUID guidFormat,
|
|
DWORD dwFourCC,
|
|
WORD wBitsPerPixel,
|
|
BYTE* pbPaletteData,
|
|
DWORD cbPaletteDataSize,
|
|
DWORD dwWidth,
|
|
DWORD dwHeight,
|
|
DWORD dwFPS,
|
|
LCID dwLanguage )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig* pStreamConfig = NULL;
|
|
IWMPropertyVault* pPropertyVault = NULL;
|
|
WM_MEDIA_TYPE* pMediaType = NULL;
|
|
IWMVideoMediaProps* pVideoMediaProps = NULL;
|
|
BOOL fFalse = FALSE;
|
|
|
|
if ( !ppStreamConfig )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if ( !pProfile )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
//
|
|
// pCodecInfo3 is allowed to be NULL, since CreateVideoMediatype calls EnsureIWMCodecInfo3
|
|
//
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create the video stream
|
|
//
|
|
hr = pProfile->CreateNewStream( WMMEDIATYPE_Video, &pStreamConfig );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pStreamConfig );
|
|
|
|
//
|
|
// Configure the new video stream
|
|
//
|
|
hr = pStreamConfig->SetBitrate( wBitsPerPixel * dwWidth * dwHeight * dwFPS );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->SetBufferWindow( 0 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the media type for the stream
|
|
//
|
|
hr = CreateUncompressedVideoMediaType( &pMediaType,
|
|
guidFormat,
|
|
dwFourCC,
|
|
wBitsPerPixel,
|
|
pbPaletteData,
|
|
cbPaletteDataSize,
|
|
dwFPS,
|
|
dwWidth,
|
|
dwHeight );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaType );
|
|
|
|
hr = pStreamConfig->QueryInterface( IID_IWMVideoMediaProps, (void**) &pVideoMediaProps );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pVideoMediaProps );
|
|
|
|
hr = pVideoMediaProps->SetMediaType( pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If this profile will be used by writer, we should set the properties
|
|
// on the stream configuration
|
|
//
|
|
if ( SUCCEEDED( pStreamConfig->QueryInterface( IID_IWMPropertyVault, (void**)&pPropertyVault ) ) )
|
|
{
|
|
assert( pPropertyVault );
|
|
hr = pPropertyVault->SetProperty( g_wszVBREnabled, WMT_TYPE_BOOL, (BYTE*) &fFalse, sizeof( fFalse ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
SAFE_RELEASE( pPropertyVault );
|
|
}
|
|
|
|
hr = SetStreamLanguage( pStreamConfig, dwLanguage );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Return the pStreamConfig to the caller
|
|
//
|
|
SAFE_ADDREF( pStreamConfig );
|
|
*ppStreamConfig = pStreamConfig;
|
|
}
|
|
while ( FALSE );
|
|
|
|
SAFE_RELEASE( pStreamConfig );
|
|
SAFE_RELEASE( pPropertyVault );
|
|
SAFE_ARRAYDELETE( pMediaType );
|
|
SAFE_RELEASE( pVideoMediaProps );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateScriptStream()
|
|
// Desc: Creates a scripat stream and returns its configuration object.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateScriptStream( IWMStreamConfig** ppStreamConfig,
|
|
IWMProfile *pProfile,
|
|
DWORD dwBitrate,
|
|
DWORD dwBufferWindow,
|
|
LCID dwLanguage )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig* pStreamConfig = NULL;
|
|
WM_MEDIA_TYPE* pMediaType = NULL;
|
|
IWMMediaProps* pMediaProps = NULL;
|
|
|
|
if ( !ppStreamConfig )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if ( !pProfile )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create the script stream
|
|
//
|
|
hr = pProfile->CreateNewStream( WMMEDIATYPE_Script, &pStreamConfig );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pStreamConfig );
|
|
|
|
//
|
|
// Configure the new stream
|
|
//
|
|
hr = pStreamConfig->SetBitrate( dwBitrate );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->SetBufferWindow( dwBufferWindow );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the media type for the script stream
|
|
//
|
|
hr = CreateScriptMediaType( &pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->QueryInterface( IID_IWMMediaProps, (void**) &pMediaProps );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaProps );
|
|
|
|
hr = pMediaProps->SetMediaType( pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = SetStreamLanguage( pStreamConfig, dwLanguage );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Return the pStreamConfig to the caller
|
|
//
|
|
SAFE_ADDREF( pStreamConfig );
|
|
*ppStreamConfig = pStreamConfig;
|
|
}
|
|
while ( FALSE );
|
|
|
|
SAFE_RELEASE( pStreamConfig );
|
|
SAFE_ARRAYDELETE( pMediaType );
|
|
SAFE_RELEASE( pMediaProps );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateImageStream()
|
|
// Desc: Creates an image stream and returns its configuration object.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateImageStream( IWMStreamConfig** ppStreamConfig,
|
|
IWMProfile *pProfile,
|
|
DWORD dwBitrate,
|
|
DWORD dwBufferWindow,
|
|
DWORD dwWidth,
|
|
DWORD dwHeight,
|
|
LCID dwLanguage )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig* pStreamConfig = NULL;
|
|
WM_MEDIA_TYPE* pMediaType = NULL;
|
|
IWMMediaProps* pMediaProps = NULL;
|
|
|
|
if ( !ppStreamConfig )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if ( !pProfile )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create the image stream
|
|
//
|
|
hr = pProfile->CreateNewStream( WMMEDIATYPE_Image, &pStreamConfig );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pStreamConfig );
|
|
|
|
//
|
|
// Configure the new stream
|
|
//
|
|
hr = pStreamConfig->SetBitrate( dwBitrate );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->SetBufferWindow( dwBufferWindow );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the media type for the image stream
|
|
//
|
|
hr = CreateImageMediaType( &pMediaType,
|
|
dwBitrate,
|
|
dwWidth,
|
|
dwHeight );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->QueryInterface( IID_IWMMediaProps, (void**) &pMediaProps );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaProps );
|
|
|
|
hr = pMediaProps->SetMediaType( pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = SetStreamLanguage( pStreamConfig, dwLanguage );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Return the pStreamConfig to the caller
|
|
//
|
|
SAFE_ADDREF( pStreamConfig );
|
|
*ppStreamConfig = pStreamConfig;
|
|
}
|
|
while ( FALSE );
|
|
|
|
SAFE_RELEASE( pStreamConfig );
|
|
SAFE_ARRAYDELETE( pMediaType );
|
|
SAFE_RELEASE( pMediaProps );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateWebStream()
|
|
// Desc: Creates a Web stream and returns its configuration object.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateWebStream( IWMStreamConfig** ppStreamConfig,
|
|
IWMProfile *pProfile,
|
|
DWORD dwBitrate,
|
|
DWORD dwBufferWindow,
|
|
LCID dwLanguage )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig* pStreamConfig = NULL;
|
|
WM_MEDIA_TYPE* pMediaType = NULL;
|
|
IWMMediaProps* pMediaProps = NULL;
|
|
|
|
if ( !ppStreamConfig )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if ( !pProfile )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create the Web stream
|
|
//
|
|
hr = pProfile->CreateNewStream( WMMEDIATYPE_FileTransfer, &pStreamConfig );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pStreamConfig );
|
|
|
|
//
|
|
// Configure the new stream
|
|
//
|
|
hr = pStreamConfig->SetBitrate( dwBitrate );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->SetBufferWindow( dwBufferWindow );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the media type for the stream
|
|
//
|
|
hr = CreateWebMediaType( &pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->QueryInterface( IID_IWMMediaProps, (void**) &pMediaProps );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaProps );
|
|
|
|
hr = pMediaProps->SetMediaType( pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = SetStreamLanguage( pStreamConfig, dwLanguage );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Return the pStreamConfig to the caller
|
|
//
|
|
SAFE_ADDREF( pStreamConfig );
|
|
*ppStreamConfig = pStreamConfig;
|
|
}
|
|
while ( FALSE );
|
|
|
|
SAFE_RELEASE( pStreamConfig );
|
|
SAFE_ARRAYDELETE( pMediaType );
|
|
SAFE_RELEASE( pMediaProps );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateFileStream()
|
|
// Desc: Creates a file stream and returns its configuration object.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateFileStream( IWMStreamConfig** ppStreamConfig,
|
|
IWMProfile *pProfile,
|
|
DWORD dwBufferWindow,
|
|
DWORD dwBitrate,
|
|
WORD wMaxFilenameLength,
|
|
LCID dwLanguage )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig* pStreamConfig = NULL;
|
|
IWMStreamConfig2* pStreamConfig2 = NULL;
|
|
WM_MEDIA_TYPE* pMediaType = NULL;
|
|
IWMMediaProps* pMediaProps = NULL;
|
|
|
|
if ( !ppStreamConfig )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
if ( !pProfile )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create the file stream
|
|
//
|
|
hr = pProfile->CreateNewStream( WMMEDIATYPE_FileTransfer, &pStreamConfig );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pStreamConfig );
|
|
|
|
//
|
|
// Configure the new stream
|
|
//
|
|
hr = pStreamConfig->SetBitrate( dwBitrate );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->SetBufferWindow( dwBufferWindow );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the media type for the stream
|
|
//
|
|
hr = CreateFileMediaType( &pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = pStreamConfig->QueryInterface( IID_IWMMediaProps, (void**) &pMediaProps );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaProps );
|
|
|
|
hr = pMediaProps->SetMediaType( pMediaType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Add the filename data unit extension to the stream
|
|
//
|
|
hr = pStreamConfig->QueryInterface( IID_IWMStreamConfig2, (void**) &pStreamConfig2 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pStreamConfig2 );
|
|
|
|
hr = pStreamConfig2->AddDataUnitExtension( WM_SampleExtensionGUID_FileName,
|
|
wMaxFilenameLength,
|
|
NULL,
|
|
0 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = SetStreamLanguage( pStreamConfig, dwLanguage );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Return the pStreamConfig to the caller
|
|
//
|
|
SAFE_ADDREF( pStreamConfig );
|
|
*ppStreamConfig = pStreamConfig;
|
|
}
|
|
while ( FALSE );
|
|
|
|
SAFE_RELEASE( pStreamConfig );
|
|
SAFE_ARRAYDELETE( pMediaType );
|
|
SAFE_RELEASE( pMediaProps );
|
|
SAFE_RELEASE( pStreamConfig2 );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateMediatypeForFormat()
|
|
// Desc: Initializes a WM_MEDIA_TYPE for a codec format, setting VBR attributes.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateMediatypeForFormat( WM_MEDIA_TYPE** ppmtDestination,
|
|
IWMCodecInfo3* pCodecInfo3,
|
|
IWMStreamConfig** ppFormatConfig,
|
|
GUID guidCodecType,
|
|
DWORD dwCodecIndex,
|
|
DWORD dwFormatIndex,
|
|
BOOL fIsVBR,
|
|
DWORD dwVBRPasses )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMProfileManager* pProfileManager = NULL;
|
|
IWMStreamConfig* pStreamConfig = NULL;
|
|
IWMMediaProps* pMediaProps = NULL;
|
|
|
|
if ( !ppmtDestination )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
do
|
|
{
|
|
*ppmtDestination = NULL;
|
|
|
|
//
|
|
// Make sure the pCodecInfo3 exists, and there's an outstanding reference
|
|
//
|
|
hr = EnsureIWMCodecInfo3( &pCodecInfo3 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pCodecInfo3 );
|
|
|
|
//
|
|
// Set the VBR settings appropriately
|
|
//
|
|
hr = SetCodecVBRSettings( pCodecInfo3,
|
|
guidCodecType,
|
|
dwCodecIndex,
|
|
fIsVBR,
|
|
dwVBRPasses );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Call the version that doesn't set the VBR attributes
|
|
//
|
|
hr = CreateMediatypeForFormat( ppmtDestination,
|
|
pCodecInfo3,
|
|
ppFormatConfig,
|
|
guidCodecType,
|
|
dwCodecIndex,
|
|
dwFormatIndex );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( *ppmtDestination );
|
|
}
|
|
while ( FALSE );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SAFE_ARRAYDELETE( (*ppmtDestination) );
|
|
}
|
|
|
|
SAFE_RELEASE( pCodecInfo3 );
|
|
SAFE_RELEASE( pProfileManager );
|
|
SAFE_RELEASE( pStreamConfig );
|
|
SAFE_RELEASE( pMediaProps );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CreateMediatypeForFormat() (Overloaded)
|
|
// Desc: Initializes a WM_MEDIA_TYPE for a codec format, without setting
|
|
// VBR attributes.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP CreateMediatypeForFormat( WM_MEDIA_TYPE** ppmtDestination,
|
|
IWMCodecInfo3* pCodecInfo3,
|
|
IWMStreamConfig** ppFormatConfig,
|
|
GUID guidCodecType,
|
|
DWORD dwCodecIndex,
|
|
DWORD dwFormatIndex )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMProfileManager* pProfileManager = NULL;
|
|
IWMStreamConfig* pFormatConfig = NULL;
|
|
IWMMediaProps* pMediaProps = NULL;
|
|
DWORD dwMediaTypeLength;
|
|
|
|
if ( !ppmtDestination )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
do
|
|
{
|
|
*ppmtDestination = NULL;
|
|
|
|
//
|
|
// Make sure the pCodecInfo3 exists, and there's an outstanding reference
|
|
//
|
|
hr = EnsureIWMCodecInfo3( &pCodecInfo3 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pCodecInfo3 );
|
|
|
|
//
|
|
// Get the stream configuration for the given format
|
|
//
|
|
hr = pCodecInfo3->GetCodecFormat( guidCodecType, dwCodecIndex, dwFormatIndex, &pFormatConfig );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pFormatConfig );
|
|
|
|
//
|
|
// Get the media type for the requested format
|
|
//
|
|
hr = pFormatConfig->QueryInterface( IID_IWMMediaProps, (void**) &pMediaProps );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pMediaProps );
|
|
|
|
dwMediaTypeLength = 0;
|
|
hr = pMediaProps->GetMediaType( NULL, &dwMediaTypeLength );
|
|
if( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
*ppmtDestination = (WM_MEDIA_TYPE *) new BYTE[ dwMediaTypeLength ];
|
|
if( !*ppmtDestination )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
hr = pMediaProps->GetMediaType( *ppmtDestination, &dwMediaTypeLength );
|
|
if( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( *ppmtDestination );
|
|
|
|
if ( ppFormatConfig )
|
|
{
|
|
SAFE_ADDREF( pFormatConfig );
|
|
*ppFormatConfig = pFormatConfig;
|
|
}
|
|
}
|
|
while ( FALSE );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SAFE_ARRAYDELETE( *ppmtDestination );
|
|
}
|
|
|
|
SAFE_RELEASE( pCodecInfo3 );
|
|
SAFE_RELEASE( pProfileManager );
|
|
SAFE_RELEASE( pFormatConfig );
|
|
SAFE_RELEASE( pMediaProps );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: WriteProfileAsPRX()
|
|
// Desc: Writes a profile to a PRX file.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP WriteProfileAsPRX( LPCTSTR tszFilename, LPCWSTR wszProfileData, DWORD dwProfileDataLength )
|
|
{
|
|
HANDLE hFile = NULL;
|
|
HRESULT hr = S_OK;
|
|
DWORD dwBytesWritten;
|
|
BOOL bResult;
|
|
|
|
assert( tszFilename );
|
|
assert( wszProfileData );
|
|
assert( 0 != dwProfileDataLength );
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create the file, overwriting any existing file
|
|
//
|
|
hFile = CreateFile( tszFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
|
|
if ( INVALID_HANDLE_VALUE == hFile )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Write the profile data to the file
|
|
//
|
|
bResult = WriteFile( hFile, wszProfileData, dwProfileDataLength, &dwBytesWritten, NULL );
|
|
if ( !bResult )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
break;
|
|
}
|
|
}
|
|
while ( FALSE );
|
|
|
|
//
|
|
// Close the file, if it was opened successfully
|
|
//
|
|
SAFE_CLOSEHANDLE( hFile );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: AddSMPTEExtensionToStream()
|
|
// Desc: Add a data unit extension for SMPTE time code.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP AddSMPTEExtensionToStream( IWMStreamConfig* pStream )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig2* pStreamConfig2 = NULL;
|
|
|
|
if ( !pStream )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
do
|
|
{
|
|
//
|
|
// Get the IWMStreamConfig2 interface
|
|
//
|
|
hr = pStream->QueryInterface( IID_IWMStreamConfig2, (void**) &pStreamConfig2 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
assert( pStreamConfig2 );
|
|
|
|
//
|
|
// Add SMPTE extension
|
|
//
|
|
hr = pStreamConfig2->AddDataUnitExtension( WM_SampleExtensionGUID_Timecode,
|
|
sizeof( WMT_TIMECODE_EXTENSION_DATA ),
|
|
NULL,
|
|
0 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while ( FALSE );
|
|
|
|
SAFE_RELEASE( pStreamConfig2 );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: GetUncompressedWaveFormatCount()
|
|
// Desc: Returns the number of uncompressed wave formats, four for each
|
|
// frequency in the WaveFrequency array.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP GetUncompressedWaveFormatCount( DWORD * pdwCount )
|
|
{
|
|
*pdwCount = 4 * sizeof( WaveFrequency ) / sizeof( WaveFrequency[0] );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: GetUncompressedWaveFormat()
|
|
// Desc: Retrieves wave format parameters by index.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP GetUncompressedWaveFormat( DWORD dwIndex,
|
|
DWORD * pdwSamplesPerSecond,
|
|
WORD * pwNumChannels,
|
|
WORD * pwBitsPerSample )
|
|
{
|
|
if ( NULL == pdwSamplesPerSecond
|
|
|| NULL == pwNumChannels
|
|
|| NULL == pwBitsPerSample )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
DWORD dwCount;
|
|
HRESULT hr;
|
|
|
|
hr = GetUncompressedWaveFormatCount( &dwCount );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if ( dwIndex >= dwCount )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pdwSamplesPerSecond = WaveFrequency[ dwIndex / 4 ];
|
|
|
|
switch ( dwIndex % 4 )
|
|
{
|
|
case 0:
|
|
*pwBitsPerSample = 8;
|
|
*pwNumChannels = 1;
|
|
break;
|
|
case 1:
|
|
*pwBitsPerSample = 8;
|
|
*pwNumChannels = 2;
|
|
break;
|
|
case 2:
|
|
*pwBitsPerSample = 16;
|
|
*pwNumChannels = 1;
|
|
break;
|
|
case 3:
|
|
*pwBitsPerSample = 16;
|
|
*pwNumChannels = 2;
|
|
break;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: GetUncompressedPixelFormatCount()
|
|
// Desc: Returns the number of formats in the PixelFormats array.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP GetUncompressedPixelFormatCount( DWORD * pdwCount )
|
|
{
|
|
*pdwCount = sizeof( PixelFormats ) / sizeof( PixelFormats[0] );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: GetUncompressedPixelFormat()
|
|
// Desc: Retrieves pixel format parameters by index.
|
|
//------------------------------------------------------------------------------
|
|
STDMETHODIMP GetUncompressedPixelFormat( DWORD dwIndex,
|
|
GUID * pguidFormat,
|
|
DWORD * pdwFourCC,
|
|
WORD * pwBitsPerPixel )
|
|
{
|
|
if ( NULL == pguidFormat
|
|
|| NULL == pdwFourCC
|
|
|| NULL == pwBitsPerPixel )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
DWORD dwCount = sizeof( PixelFormats ) / sizeof( PixelFormats[0] );
|
|
|
|
if ( dwIndex >= dwCount )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pguidFormat = *PixelFormats[ dwIndex ].guidFormat;
|
|
*pdwFourCC = PixelFormats[ dwIndex ].dwFourCC;
|
|
*pwBitsPerPixel = PixelFormats[ dwIndex ].wBitsPerPixel;
|
|
|
|
return S_OK;
|
|
}
|