930 lines
24 KiB
C++
930 lines
24 KiB
C++
//*****************************************************************************
|
|
//
|
|
// Microsoft Windows Media
|
|
// Copyright (C) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// FileName: reader.cpp
|
|
//
|
|
// Abstract: Implementation of the CReader class
|
|
//
|
|
//*****************************************************************************
|
|
|
|
#include "Reader.h"
|
|
//////////////////////////////////////////////////////////////////////
|
|
// The CReader object reads stream data from an input (file or URL)
|
|
// specified by the pwszFile parameter of the Configure method and
|
|
// sends it the output, which is a CWriter or CWaveOut object,
|
|
// depending which one of them has been attached. Data sent to CWriter
|
|
// is compressed, while data sent to CWaveOut is decompressed by CReader.
|
|
// The GetStats method enables you to get statistics at any time during
|
|
// data transmission.
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
CReader::CReader()
|
|
{
|
|
m_pReaderHeaderInfo = NULL ;
|
|
m_pReaderAdvanced = NULL ;
|
|
m_pReader = NULL ;
|
|
m_pReaderStreamClock = NULL ;
|
|
m_hEvent = NULL ;
|
|
m_fEOF = false ;
|
|
m_qwTime = 0 ;
|
|
m_hrAsync = S_OK ;
|
|
m_fReaderStarted = false;
|
|
m_fNetReading = false;
|
|
m_pWriter = NULL;
|
|
m_dwAudioStreamNum = 0;
|
|
m_dwTimerId = 0;
|
|
|
|
}
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
CReader::~CReader()
|
|
{
|
|
SAFE_RELEASE( m_pReaderStreamClock );
|
|
SAFE_RELEASE( m_pReaderHeaderInfo );
|
|
SAFE_RELEASE( m_pReaderAdvanced ) ;
|
|
SAFE_RELEASE( m_pReader ) ;
|
|
|
|
if( NULL != m_hEvent )
|
|
{
|
|
CloseHandle( m_hEvent ) ;
|
|
m_hEvent = NULL ;
|
|
}
|
|
}
|
|
///////////////////////////////////////////////////////////////
|
|
// Initialize Reader object:
|
|
// create all necessary interfaces and an event
|
|
///////////////////////////////////////////////////////////////
|
|
HRESULT CReader::Init()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( m_fReaderStarted || m_pReaderHeaderInfo )
|
|
return E_FAIL;
|
|
|
|
do
|
|
{
|
|
m_hrAsync = S_OK ;
|
|
|
|
m_hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ) ;
|
|
|
|
if ( NULL == m_hEvent )
|
|
{
|
|
_tprintf( _T( "Could not Create Event.\n" ));
|
|
break;
|
|
}
|
|
if ( FAILED( hr = WMCreateReader( NULL, WMT_RIGHT_PLAYBACK, &m_pReader )))
|
|
{
|
|
_tprintf( _T( "Could not create reader (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
|
|
if ( FAILED( hr = m_pReader->QueryInterface( IID_IWMReaderAdvanced, ( void** )&m_pReaderAdvanced )))
|
|
{
|
|
_tprintf( _T( "Could not QI for IWMReaderAdvanced (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
|
|
hr = m_pReader->QueryInterface( IID_IWMHeaderInfo, ( VOID ** )&m_pReaderHeaderInfo );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not QI for IWMHeaderInfo (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
|
|
hr = m_pReader->QueryInterface( IID_IWMReaderStreamClock, ( VOID ** )&m_pReaderStreamClock );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not QI for IWMReaderStreamClock (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
|
|
|
|
} while( FALSE );
|
|
|
|
if (FAILED( hr ) )
|
|
{
|
|
SAFE_RELEASE( m_pReaderStreamClock );
|
|
SAFE_RELEASE( m_pReaderHeaderInfo );
|
|
SAFE_RELEASE( m_pReaderAdvanced );
|
|
SAFE_RELEASE( m_pReader );
|
|
CloseHandle( m_hEvent );
|
|
}
|
|
|
|
return( hr );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Configure previously intialized reader object
|
|
// pwszFile - URL of input file
|
|
//
|
|
HRESULT CReader::Configure( const WCHAR *pwszFile )
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
const WCHAR * wszAttributes[] = { g_wszWMTitle,
|
|
g_wszWMAuthor,
|
|
g_wszWMDescription,
|
|
g_wszWMRating,
|
|
g_wszWMCopyright,
|
|
g_wszWMAlbumTitle,
|
|
g_wszWMTrack,
|
|
g_wszWMPromotionURL,
|
|
g_wszWMAlbumCoverURL,
|
|
g_wszWMGenre,
|
|
g_wszWMYear,
|
|
g_wszWMGenreID,
|
|
g_wszWMMCDI,
|
|
g_wszWMBannerImageType,
|
|
g_wszWMBannerImageData,
|
|
g_wszWMBannerImageURL,
|
|
g_wszWMCopyrightURL };
|
|
|
|
//
|
|
// Check, if it's a net location.
|
|
//
|
|
|
|
if ( NULL == pwszFile || NULL == wcslen(pwszFile))
|
|
return E_INVALIDARG;
|
|
|
|
m_fNetReading = _wcsnicmp( pwszFile, L"http", 4 )? FALSE : TRUE ;
|
|
|
|
//
|
|
// Open the requested file
|
|
//
|
|
|
|
hr = m_pReader->Open( pwszFile, this, NULL );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not open file %ws (hr=0x%08x).\n" ), pwszFile ,hr );
|
|
return( hr );
|
|
}
|
|
|
|
//
|
|
// Wait for the open to finish
|
|
//
|
|
|
|
WaitForEvent();
|
|
|
|
if ( FAILED( m_hrAsync ) )
|
|
{
|
|
_tprintf( _T( "Open failed (hr=0x%08x).\n" ), m_hrAsync );
|
|
return( m_hrAsync );
|
|
}
|
|
|
|
//
|
|
// Turn on manual stream selection, so we get all streams.
|
|
//
|
|
|
|
hr = m_pReaderAdvanced->SetManualStreamSelection( TRUE );
|
|
if( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Failed to set manual stream selection (hr=0x%08x).\n" ), hr );
|
|
return( hr );
|
|
}
|
|
|
|
//
|
|
// Get the profile interface
|
|
//
|
|
|
|
IWMProfile* pProfile = NULL;
|
|
|
|
hr = m_pReader->QueryInterface( IID_IWMProfile, ( VOID ** )&pProfile );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not QI for IWMProfile (hr=0x%08x).\n" ), hr );
|
|
return( hr );
|
|
}
|
|
|
|
m_dwAudioStreamNum = 0;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create the list of data unit extensions defined for all streams
|
|
// in this profile
|
|
//
|
|
hr = m_ExtDataList.Create( pProfile );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Creating data unit extension list failed (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If output is writer, do not decompress samples
|
|
//
|
|
|
|
if ( NULL != m_pWriter )
|
|
{
|
|
hr = SetCodecOff( pProfile );
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Turn on the user clock if reading from file
|
|
//
|
|
|
|
if ( !m_fNetReading )
|
|
{
|
|
hr = m_pReaderAdvanced->SetUserProvidedClock( TRUE );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "SetUserProvidedClock failed (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Configure writer - if attached
|
|
//
|
|
|
|
if ( NULL != m_pWriter )
|
|
{
|
|
hr = m_pWriter->Configure( pProfile );
|
|
if (FAILED ( hr ) )
|
|
break;
|
|
|
|
int attrs = sizeof( wszAttributes ) / sizeof( wszAttributes[ 0 ] );
|
|
for ( int i = 0; i < attrs; i++ )
|
|
{
|
|
hr = CopyAttribToWriter( wszAttributes[ i ] );
|
|
if (FAILED ( hr ) )
|
|
break;
|
|
}
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
hr = CopyScriptsToWriter();
|
|
if (FAILED ( hr ) )
|
|
break;
|
|
}
|
|
|
|
|
|
}while( FALSE );
|
|
|
|
SAFE_RELEASE( pProfile );
|
|
|
|
return( hr );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Attach writer object used to output stream data
|
|
// This function stops an already attached writer object or
|
|
// closes an already attached WaveOut object
|
|
//
|
|
HRESULT CReader::AttachWriter( CWriter *pWriter )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( NULL == pWriter )
|
|
return E_INVALIDARG;
|
|
|
|
if ( NULL != m_pWriter )
|
|
m_pWriter->Stop();
|
|
|
|
m_pWriter = pWriter;
|
|
|
|
return( hr );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Start sending data to attached output. If a writer object has been
|
|
// attached, it is initialized. This function is synchronous and waits until all
|
|
// data is sent. Since the current writer object implementation has only a
|
|
// network sink, all data sent to this object is left compressed; that is, the
|
|
// codec is off and data is passed thru OnStreamSample. If a WaveOut object
|
|
// is attached, data is decompressed and passed through theOnSample method.
|
|
//
|
|
HRESULT CReader::Start()
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( m_fReaderStarted || NULL == m_pReader )
|
|
{
|
|
return( E_FAIL );
|
|
}
|
|
|
|
if ( NULL != m_pWriter )
|
|
{
|
|
hr = m_pWriter->Start();
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return( hr );
|
|
}
|
|
}
|
|
|
|
hr = m_pReader->Start( 0, 0, 1.0, 0 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not start IWMReader (hr=0x%08x).\n" ), hr );
|
|
return( hr );
|
|
}
|
|
|
|
m_fReaderStarted = true;
|
|
|
|
//
|
|
// wait until all data sent to output
|
|
//
|
|
|
|
WaitForEvent();
|
|
|
|
if ( FAILED( m_hrAsync ) )
|
|
{
|
|
_tprintf( _T( "IWMReader failed (hr=0x%08x).\n" ), m_hrAsync );
|
|
return( m_hrAsync );
|
|
}
|
|
|
|
|
|
return( hr );
|
|
}
|
|
///////////////////////////////////////////////////////////////
|
|
// Stop both reader and writer object (if attached). Synchronous method
|
|
//
|
|
HRESULT CReader::Stop( HANDLE *hThread, int cHandles )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwStatus = 0;
|
|
|
|
if ( !m_fReaderStarted || NULL == m_pReader )
|
|
{
|
|
return( E_FAIL );
|
|
}
|
|
|
|
if( NULL != hThread && cHandles > 0 )
|
|
{
|
|
dwStatus = WaitForMultipleObjects( cHandles, hThread, TRUE, 20000 );
|
|
if( WAIT_TIMEOUT == dwStatus )
|
|
{
|
|
return E_FAIL ;
|
|
}
|
|
}
|
|
|
|
if ( NULL != m_pWriter )
|
|
{
|
|
hr = m_pWriter->Stop();
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not Stop IWMWriter (hr=0x%08x).\n" ), hr );
|
|
return( hr );
|
|
}
|
|
}
|
|
|
|
hr = m_pReader->Stop();
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not Stop IWMReader (hr=0x%08x).\n" ), hr );
|
|
return( hr );
|
|
}
|
|
|
|
WaitForEvent();
|
|
|
|
m_fReaderStarted = false;
|
|
|
|
return hr ;
|
|
|
|
}
|
|
///////////////////////////////////////////////////////////////
|
|
// Stop and close reader object. If WaveOut is attached, wait
|
|
// until it finishes with all samples and close it before closing
|
|
// the reader. Asynchronous method
|
|
//
|
|
HRESULT CReader::Close( HANDLE *hThread, int cHandles )
|
|
{
|
|
HRESULT hr = S_OK ;
|
|
|
|
if ( m_fReaderStarted )
|
|
{
|
|
hr = Stop( hThread, cHandles );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Error while stopping reader (hr=0x%08x).\n" ), hr);
|
|
}
|
|
}
|
|
|
|
if( NULL != m_pReader )
|
|
{
|
|
hr = m_pReader->Close();
|
|
}
|
|
|
|
if( FAILED ( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
WaitForEvent();
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Get current reader statistics
|
|
//
|
|
HRESULT CReader::GetStats( WM_READER_STATISTICS *pStats )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( NULL == pStats )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( NULL != m_pReaderAdvanced )
|
|
{
|
|
ZeroMemory( pStats, sizeof( WM_READER_STATISTICS ));
|
|
pStats->cbSize = sizeof( WM_READER_STATISTICS );
|
|
|
|
hr = m_pReaderAdvanced->GetStatistics( pStats );
|
|
}
|
|
return( hr );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Used for synchronization
|
|
//
|
|
void CReader::WaitForEvent()
|
|
{
|
|
WaitForSingleObject( m_hEvent, INFINITE );
|
|
return;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Callback used to send decompressed samples to attached
|
|
// WaveOut object
|
|
//
|
|
HRESULT CReader::OnSample( DWORD dwOutputNum,
|
|
QWORD cnsSampleTime,
|
|
QWORD cnsSampleDuration,
|
|
DWORD dwFlags,
|
|
INSSBuffer __RPC_FAR *pSample, void __RPC_FAR *pvContext )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( NULL == pSample )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( NULL != m_hEvent )
|
|
{
|
|
//
|
|
// TODO: Insert per-sample code here
|
|
//
|
|
|
|
}
|
|
return S_OK;
|
|
}
|
|
///////////////////////////////////////////////////////////////
|
|
// Callback function used to send compressed samples to attached writer object
|
|
//
|
|
HRESULT CReader::OnStreamSample( WORD wStreamNum,
|
|
QWORD cnsSampleTime,
|
|
QWORD cnsSampleDuration,
|
|
DWORD dwFlags,
|
|
INSSBuffer __RPC_FAR *pSample,
|
|
void __RPC_FAR *pvContext )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( NULL == m_pWriter || NULL == pSample)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( cnsSampleTime % cnsSampleDuration )
|
|
{
|
|
_tprintf( _T( "*" ) );
|
|
}
|
|
|
|
//
|
|
// Getting extension data:
|
|
// find what extensions are defined for this stream and then
|
|
// iterate thru them, get their values and display them
|
|
//
|
|
CExtensionData *pExtData = NULL;
|
|
INSSBuffer3 *pMS3 = NULL;
|
|
DWORD pvBuffer = 0;
|
|
|
|
bool ret = m_ExtDataList.Find( ( WORD )wStreamNum, &pExtData );
|
|
if( ret )
|
|
{
|
|
hr = pSample->QueryInterface( IID_INSSBuffer3, (void**)&pMS3 );
|
|
}
|
|
|
|
while( ret )
|
|
{
|
|
DWORD dwTemp = pExtData->m_cbExtensionDataSize;
|
|
hr = pMS3->GetProperty( pExtData->m_guidDUExt, pExtData->m_pValue, &dwTemp );
|
|
pExtData->DisplayData();
|
|
ret = m_ExtDataList.Find( 0, &pExtData );
|
|
}
|
|
|
|
SAFE_RELEASE( pMS3 );
|
|
|
|
|
|
//
|
|
// Pass uncompressed samples to writer
|
|
//
|
|
|
|
hr = m_pWriter->WriteStreamSample( wStreamNum,
|
|
cnsSampleTime,
|
|
0,
|
|
cnsSampleDuration,
|
|
dwFlags,
|
|
pSample );
|
|
return( hr );
|
|
}
|
|
///////////////////////////////////////////////////////////////
|
|
// Callback used for setting synchronization event and getting
|
|
// current status of data transfer
|
|
//
|
|
HRESULT CReader::OnStatus( WMT_STATUS Status,
|
|
HRESULT hr,
|
|
WMT_ATTR_DATATYPE dwType,
|
|
BYTE __RPC_FAR *pValue,
|
|
void __RPC_FAR *pvContext )
|
|
{
|
|
switch( Status )
|
|
{
|
|
|
|
case WMT_OPENED:
|
|
|
|
m_hrAsync = hr;
|
|
SetEvent( m_hEvent );
|
|
break;
|
|
|
|
case WMT_EOF:
|
|
|
|
m_fEOF = true;
|
|
_tprintf( _T( "EndOfStream detected in reader.\n" ) );
|
|
|
|
SetEvent( m_hEvent );
|
|
break;
|
|
|
|
case WMT_CLOSED:
|
|
|
|
m_hrAsync = hr;
|
|
SetEvent( m_hEvent );
|
|
break ;
|
|
|
|
case WMT_STOPPED:
|
|
|
|
m_hrAsync = hr;
|
|
SetEvent( m_hEvent );
|
|
break;
|
|
|
|
case WMT_STARTED:
|
|
|
|
//
|
|
//Ask for the specific duration of the stream to be delivered
|
|
//
|
|
|
|
if (!m_fNetReading)
|
|
{
|
|
m_qwTime = 0;
|
|
m_qwTime += 1000 * 10000;
|
|
|
|
hr = m_pReaderAdvanced->DeliverTime( m_qwTime );
|
|
}
|
|
break;
|
|
|
|
case WMT_LOCATING:
|
|
//
|
|
// The stream is being read from a network; set the variable.
|
|
//
|
|
m_fNetReading = TRUE;
|
|
break;
|
|
|
|
case WMT_TIMER :
|
|
_tprintf( _T( "Timer ...........................\n" ) );
|
|
break;
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
///////////////////////////////////////////////////////////////
|
|
// Callback : set user defined clock if stream data is read from file
|
|
|
|
HRESULT CReader::OnTime( QWORD cnsCurrentTime, void __RPC_FAR *pvContext)
|
|
{
|
|
//
|
|
// Keep asking for the specific duration of the stream till EOF
|
|
//
|
|
HRESULT hr = S_OK;
|
|
|
|
if( NULL == m_fEOF )
|
|
{
|
|
m_qwTime += 10000000 ; // 1 second
|
|
hr = m_pReaderAdvanced->DeliverTime( m_qwTime );
|
|
}
|
|
|
|
return( hr );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Switch codec off so compressed samples are passed through OnStreamSample
|
|
//
|
|
HRESULT CReader::SetCodecOff(IWMProfile* pProfile)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig* pStream = NULL;
|
|
DWORD dwStreams = 0;
|
|
GUID pguidStreamType;
|
|
|
|
if (!pProfile)
|
|
return E_INVALIDARG;
|
|
|
|
|
|
hr = pProfile->GetStreamCount( &dwStreams );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "GetStreamCount on IWMProfile failed (hr=0x%08x).\n" ), hr );
|
|
return hr;
|
|
}
|
|
|
|
for ( DWORD i = 0; i < dwStreams; i++ )
|
|
{
|
|
hr = pProfile->GetStream( i, &pStream );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not get Stream %d of %d from IWMProfile (hr=0x%08x).\n" ),
|
|
i, dwStreams, hr );
|
|
break;
|
|
}
|
|
|
|
WORD wStreamNumber = 0 ;
|
|
|
|
//
|
|
// Get the stream number of the current stream
|
|
//
|
|
|
|
hr = pStream->GetStreamNumber( &wStreamNumber );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not get stream number from IWMStreamConfig %d of %d (hr=0x%08x).\n" ),
|
|
i, dwStreams, hr );
|
|
break;
|
|
}
|
|
|
|
hr = pStream->GetStreamType( &pguidStreamType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T("Could not get stream type of stream %d of %d from IWMStreamConfig (hr=0x%08x).\n" ),
|
|
i, dwStreams, hr ) ;
|
|
break ;
|
|
}
|
|
|
|
//
|
|
// Set the stream to be received in compressed mode
|
|
//
|
|
|
|
hr = m_pReaderAdvanced->SetReceiveStreamSamples( wStreamNumber, TRUE );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not SetReceivedStreamSamples for stream number %d (hr=0x%08x).\n" ),
|
|
wStreamNumber, hr );
|
|
break;
|
|
}
|
|
|
|
SAFE_RELEASE( pStream );
|
|
}
|
|
|
|
return( hr );
|
|
}
|
|
///////////////////////////////////////////////////////////////
|
|
// Copy attribute value from reader to attached writer.
|
|
// pwszName - attribute name
|
|
//
|
|
HRESULT CReader::CopyAttribToWriter( const WCHAR *pwszName )
|
|
{
|
|
WORD nstreamNum = 0;
|
|
WORD cbLength = 0;
|
|
WMT_ATTR_DATATYPE type;
|
|
HRESULT hr = S_OK;
|
|
BYTE* pValue = NULL;
|
|
|
|
|
|
if ( NULL == pwszName || 0 == wcslen(pwszName))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( NULL == m_pWriter)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Get the number of bytes to be allocated for pValue
|
|
//
|
|
|
|
hr = m_pReaderHeaderInfo->GetAttributeByName( &nstreamNum,
|
|
pwszName,
|
|
&type,
|
|
NULL,
|
|
&cbLength );
|
|
if ( FAILED( hr ) && hr != ASF_E_NOTFOUND )
|
|
{
|
|
_tprintf( _T( "GetAttributeByName failed for Attribute name %ws (hr=0x%08x).\n" ), pwszName, hr);
|
|
return hr;
|
|
}
|
|
|
|
if( 0 == cbLength && hr == ASF_E_NOTFOUND )
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
pValue = new BYTE[ cbLength ];
|
|
if ( NULL == pValue )
|
|
{
|
|
_tprintf( _T( "Unable to allocate memory for the Attribute name %ws" ), pwszName);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
//
|
|
// Dummy do-while loop
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// Get the value
|
|
//
|
|
|
|
hr = m_pReaderHeaderInfo->GetAttributeByName( &nstreamNum,
|
|
pwszName,
|
|
&type,
|
|
pValue,
|
|
&cbLength );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "GetAttributeByName failed for Attribute name %ws (hr=0x%08x).\n" ),
|
|
pwszName, hr);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the attribute
|
|
//
|
|
|
|
hr = m_pWriter->SetAttribute( nstreamNum,
|
|
pwszName,
|
|
type,
|
|
pValue,
|
|
cbLength );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "SetAttribute failed for Attribute name %ws (hr=0x%08x).\n" ),
|
|
pwszName, hr);
|
|
break;
|
|
}
|
|
}
|
|
while( FALSE );
|
|
|
|
if (NULL != pValue)
|
|
{
|
|
delete[] pValue;
|
|
pValue = NULL;
|
|
}
|
|
|
|
return( hr );
|
|
}
|
|
///////////////////////////////////////////////////////////////
|
|
// Copy all scripts from reader to attached writer
|
|
//
|
|
HRESULT CReader::CopyScriptsToWriter()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR* pwszCommand = NULL;
|
|
WCHAR* pwszType = NULL;
|
|
QWORD cnsScriptTime = 0;
|
|
WORD cScript = 0;
|
|
WORD cchTypeLen = 0;
|
|
WORD cchCommandLen = 0;
|
|
|
|
if ( NULL == m_pWriter || NULL == m_pReaderHeaderInfo)
|
|
return E_FAIL;
|
|
|
|
hr = m_pReaderHeaderInfo->GetScriptCount( &cScript );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "GetScriptCount failed (hr=0x%08x).\n" ), hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
for( WORD i = 0 ; i < cScript ; i++)
|
|
{
|
|
//
|
|
// Get the memory required for this script
|
|
//
|
|
|
|
hr = m_pReaderHeaderInfo->GetScript( i ,
|
|
NULL ,
|
|
&cchTypeLen ,
|
|
NULL ,
|
|
&cchCommandLen ,
|
|
&cnsScriptTime );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "GetScript failed for Script no %d (hr=0x%08x).\n" ), i, hr ) ;
|
|
break ;
|
|
}
|
|
|
|
pwszType = new WCHAR[ cchTypeLen ];
|
|
pwszCommand = new WCHAR[ cchCommandLen ];
|
|
|
|
if( NULL == pwszType || NULL == pwszCommand )
|
|
{
|
|
_tprintf( _T( "Insufficient Memory" ) );
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the script
|
|
//
|
|
|
|
hr = m_pReaderHeaderInfo->GetScript( i ,
|
|
pwszType ,
|
|
&cchTypeLen ,
|
|
pwszCommand ,
|
|
&cchCommandLen ,
|
|
&cnsScriptTime );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "GetScript failed for Script no %d (hr=0x%08x).\n" ), i, hr );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Add the script to the writer
|
|
//
|
|
|
|
hr = m_pWriter->AddScript( pwszType ,
|
|
pwszCommand ,
|
|
cnsScriptTime );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "AddScript failed for Script no %d (hr=0x%08x).\n" ), i, hr);
|
|
break;
|
|
}
|
|
|
|
delete[] pwszType;
|
|
delete[] pwszCommand;
|
|
|
|
pwszType = pwszCommand = NULL;
|
|
|
|
cchTypeLen = 0;
|
|
cchCommandLen = 0;
|
|
}
|
|
|
|
if(NULL != pwszType)
|
|
{
|
|
delete[] pwszType;
|
|
pwszType = NULL;
|
|
}
|
|
if(NULL != pwszCommand)
|
|
{
|
|
delete[] pwszCommand;
|
|
pwszCommand = NULL;
|
|
}
|
|
|
|
pwszType = pwszCommand = NULL;
|
|
|
|
return( hr );
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
////////
|
|
HRESULT STDMETHODCALLTYPE CReader::QueryInterface( REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
|
|
{
|
|
if ( riid == IID_IWMReaderCallback )
|
|
{
|
|
*ppvObject = ( IWMReaderCallback* )this;
|
|
}
|
|
else if( riid == IID_IWMReaderCallbackAdvanced )
|
|
{
|
|
*ppvObject = ( IWMReaderCallbackAdvanced* )this;
|
|
}
|
|
else if( riid == IID_IUnknown )
|
|
{
|
|
*ppvObject = this;
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
return S_OK;
|
|
}
|