2025-11-28 00:35:46 +09:00

1406 lines
38 KiB
C++

//*****************************************************************************
//
// Microsoft Windows Media
// Copyright ( C) Microsoft Corporation. All rights reserved.
//
// FileName: WMVCopy.cpp
//
// Abstract: Implementation of CWMVCopy class.
//
//*****************************************************************************
#include <stdio.h>
#include <tchar.h>
#include "wmvcopy.h"
//------------------------------------------------------------------------------
// Name: CWMVCopy::CWMVCopy()
// Desc: Constructor.
//------------------------------------------------------------------------------
CWMVCopy::CWMVCopy()
{
//
// Set the reference count to 1 when creating this class.
//
m_cRef = 1;
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::~CWMVCopy()
// Desc: Destructor.
//------------------------------------------------------------------------------
CWMVCopy::~CWMVCopy()
{
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::CreateReader()
// Desc: Creates a reader and opens the source file using this reader.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::CreateReader( const WCHAR * pwszInputFile )
{
HRESULT hr = S_OK;
_tprintf( _T( "Creating the Reader...\n" ) );
//
// Create a reader
//
hr = WMCreateReader( NULL, 0, &m_pReader );
if( FAILED( hr ) )
{
return( hr );
}
//
// Get the IWMReaderAdvanced interface
//
hr = m_pReader->QueryInterface( IID_IWMReaderAdvanced, (void **)&m_pReaderAdvanced );
if( FAILED( hr ) )
{
return( hr );
}
//
// Get the IWMHeaderInfo interface of the reader
//
hr = m_pReader->QueryInterface( IID_IWMHeaderInfo, (void **)&m_pReaderHeaderInfo );
if( FAILED( hr ) )
{
return( hr );
}
m_hr = S_OK;
//
// Open the reader; use "this" as the callback interface.
//
hr = m_pReader->Open( pwszInputFile, this, NULL );
if( FAILED ( hr ) )
{
return( hr );
}
//
// Wait until WMT_OPENED status message is received in OnStatus()
//
hr = WaitForCompletion();
if( FAILED( hr ) )
{
return( hr );
}
//
// Get the duration of the source file
//
WORD wStreamNumber = 0;
WMT_ATTR_DATATYPE enumType;
WORD cbLength = sizeof( m_qwDuration );
hr = m_pReaderHeaderInfo->GetAttributeByName( &wStreamNumber,
g_wszWMDuration,
&enumType,
(BYTE *)&m_qwDuration,
&cbLength );
if( FAILED( hr ) )
{
return( hr );
}
if( m_qwDuration == 0 )
{
hr = E_INVALIDARG;
return( hr );
}
//
// Turn on the user clock
//
hr = m_pReaderAdvanced->SetUserProvidedClock( TRUE );
if( FAILED( hr ) )
{
return( hr );
}
//
// Turn on manual stream selection, so we get all streams.
//
hr = m_pReaderAdvanced->SetManualStreamSelection( TRUE );
if( FAILED( hr ) )
{
return( hr );
}
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::GetProfileInfo()
// Desc: Gets the profile information from the reader.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::GetProfileInfo()
{
HRESULT hr = S_OK;
IWMStreamConfig * pStreamConfig = NULL;
IWMMediaProps * pMediaProperty = NULL;
//
// Get the profile of the reader
//
hr = m_pReader->QueryInterface( IID_IWMProfile, (void **)&m_pReaderProfile );
if( FAILED( hr ) )
{
return( hr );
}
//
// Get stream count
//
hr = m_pReaderProfile->GetStreamCount( &m_dwStreamCount );
if( FAILED( hr ) )
{
return( hr );
}
//
// Allocate memory for the stream type array and stream number array
//
m_pguidStreamType = new GUID[ m_dwStreamCount ];
m_pwStreamNumber = new WORD[ m_dwStreamCount ];
if( NULL == m_pwStreamNumber || NULL == m_pguidStreamType )
{
hr = E_OUTOFMEMORY;
return ( hr );
}
for( DWORD i = 0; i < m_dwStreamCount; i++ )
{
hr = m_pReaderProfile->GetStream( i, &pStreamConfig );
if( FAILED( hr ) )
{
break;
}
//
// Get the stream number of the current stream
//
hr = pStreamConfig->GetStreamNumber( &m_pwStreamNumber[i] );
if( FAILED( hr ) )
{
break;
}
//
// Set the stream to be received in compressed mode
//
hr = m_pReaderAdvanced->SetReceiveStreamSamples( m_pwStreamNumber[i], TRUE );
if( FAILED( hr ) )
{
break;
}
hr = pStreamConfig->QueryInterface( IID_IWMMediaProps, (void **)&pMediaProperty );
if( FAILED( hr ) )
{
break;
}
//
// Get the stream type of the current stream
//
hr = pMediaProperty->GetType( &m_pguidStreamType[i] );
if( FAILED( hr ) )
{
break;
}
SAFE_RELEASE( pMediaProperty );
SAFE_RELEASE( pStreamConfig );
}
SAFE_RELEASE( pMediaProperty );
SAFE_RELEASE( pStreamConfig );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::CreateWriter()
// Desc: Creates a writer and sets the profile and output of this writer.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::CreateWriter( const WCHAR * pwszOutputFile )
{
HRESULT hr = S_OK;
DWORD dwInputCount = 0;
_tprintf( _T( "Creating the Writer...\n" ) );
//
// Create a writer
//
hr = WMCreateWriter( NULL, &m_pWriter );
if( FAILED( hr ) )
{
return( hr );
}
//
// Get the IWMWriterAdvanced interface of the writer
//
hr = m_pWriter->QueryInterface( IID_IWMWriterAdvanced, (void **)&m_pWriterAdvanced );
if( FAILED( hr ) )
{
return( hr );
}
//
// Get the IWMHeaderInfo interface of the writer
//
hr = m_pWriter->QueryInterface( IID_IWMHeaderInfo, (void **)&m_pWriterHeaderInfo );
if( FAILED( hr ) )
{
return( hr );
}
//
// Set the profile of the writer to the reader's profile
//
hr = m_pWriter->SetProfile( m_pReaderProfile );
if( FAILED( hr ) )
{
return( hr );
}
hr = m_pWriter->GetInputCount( &dwInputCount );
if( FAILED( hr ) )
{
return( hr );
}
//
// Set the input property to NULL so the SDK knows we're going to
// send compressed samples to the inputs of the writer.
//
for ( DWORD i = 0; i < dwInputCount; i ++ )
{
hr = m_pWriter->SetInputProps( i, NULL );
if( FAILED( hr ) )
{
return( hr );
}
}
//
// Set the output file of the writer
//
hr = m_pWriter->SetOutputFilename( pwszOutputFile );
if( FAILED( hr ) )
{
return( hr );
}
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::CopyAttribute()
// Desc: Copies all the header attributes from the reader file to the writer.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::CopyAttribute()
{
HRESULT hr = S_OK;
WORD wStreamNumber;
WORD wAttributeCount;
WMT_ATTR_DATATYPE enumType;
WORD cbNameLength = 0;
WORD cbValueLength = 0;
WCHAR * pwszName = NULL;
BYTE * pbValue = NULL;
for( DWORD i = 0; i <= m_dwStreamCount; i ++ )
{
if( i == m_dwStreamCount )
{
//
// When the stream number is 0, the attribute is a file-level attribute
//
wStreamNumber = 0;
}
else
{
wStreamNumber = m_pwStreamNumber[i];
}
//
// Get the attribute count
//
hr = m_pReaderHeaderInfo->GetAttributeCount( wStreamNumber,
&wAttributeCount );
if( FAILED( hr ) )
{
break;
}
//
// Copy all attributes of this stream
//
for( WORD j = 0; j < wAttributeCount; j ++ )
{
//
// Get the attribute name and value length
//
hr = m_pReaderHeaderInfo->GetAttributeByIndex( j,
&wStreamNumber,
NULL,
&cbNameLength,
&enumType,
NULL,
&cbValueLength );
if( FAILED( hr ) )
{
break;
}
pwszName = new WCHAR[ cbNameLength ];
pbValue = new BYTE[ cbValueLength ];
if( NULL == pwszName || NULL == pbValue )
{
hr = E_OUTOFMEMORY;
break;
}
//
// Get the attribute name and value
//
hr = m_pReaderHeaderInfo->GetAttributeByIndex( j,
&wStreamNumber,
pwszName,
&cbNameLength,
&enumType,
pbValue,
&cbValueLength );
if( FAILED( hr ) )
{
break;
}
//
// Set the attribute for the writer
//
hr = m_pWriterHeaderInfo->SetAttribute( wStreamNumber,
pwszName,
enumType,
pbValue,
cbValueLength );
if( E_INVALIDARG == hr )
{
//
// Some attributes are read-only; we cannot set them.
// They'll be set automatically by the writer.
//
hr = S_OK;
}
if( FAILED( hr ) )
{
break;
}
SAFE_ARRAYDELETE( pwszName );
SAFE_ARRAYDELETE( pbValue );
}
if( FAILED( hr ) )
{
break;
}
}
//
// Release all resources
//
SAFE_ARRAYDELETE( pwszName );
SAFE_ARRAYDELETE( pbValue );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy:CopyCodecInfo()
// Desc: Copies codec information from the reader header to the writer header.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::CopyCodecInfo()
{
HRESULT hr = S_OK;
DWORD cCodecInfo;
WCHAR * pwszName = NULL;
WCHAR * pwszDescription = NULL;
BYTE * pbCodecInfo = NULL;
IWMHeaderInfo3 * pReaderHeaderInfo3 = NULL;
IWMHeaderInfo3 * pWriterHeaderInfo3 = NULL;
do
{
hr = m_pReaderHeaderInfo->QueryInterface( IID_IWMHeaderInfo3,
(void **)&pReaderHeaderInfo3 );
if ( FAILED( hr ) )
{
break;
}
hr = m_pWriterHeaderInfo->QueryInterface( IID_IWMHeaderInfo3,
(void **)&pWriterHeaderInfo3 );
if ( FAILED( hr ) )
{
break;
}
hr = pReaderHeaderInfo3->GetCodecInfoCount( &cCodecInfo );
if ( FAILED( hr ) )
{
break;
}
for( DWORD i = 0; i < cCodecInfo; i++ )
{
WMT_CODEC_INFO_TYPE enumCodecType;
WORD cchName = 0;
WORD cchDescription = 0;
WORD cbCodecInfo = 0;
//
// Get codec info from the source
//
hr = pReaderHeaderInfo3->GetCodecInfo( i, &cchName, NULL,
&cchDescription, NULL, &enumCodecType,
&cbCodecInfo, NULL );
if( FAILED( hr ) )
{
break;
}
pwszName = new WCHAR [ cchName ];
pwszDescription = new WCHAR [ cchDescription ];
pbCodecInfo = new BYTE [ cbCodecInfo ];
if( NULL == pwszName || NULL == pwszDescription || NULL == pbCodecInfo )
{
hr = E_OUTOFMEMORY;
break;
}
hr = pReaderHeaderInfo3->GetCodecInfo( i, &cchName, pwszName,
&cchDescription, pwszDescription, &enumCodecType,
&cbCodecInfo, pbCodecInfo );
if( FAILED( hr ) )
{
break;
}
//
// Add the codec info to the writer
//
hr = pWriterHeaderInfo3->AddCodecInfo( pwszName, pwszDescription, enumCodecType,
cbCodecInfo, pbCodecInfo );
if( FAILED( hr ) )
{
break;
}
SAFE_ARRAYDELETE( pwszName );
SAFE_ARRAYDELETE( pwszDescription );
SAFE_ARRAYDELETE( pbCodecInfo );
}
}
while( FALSE );
SAFE_ARRAYDELETE( pwszName );
SAFE_ARRAYDELETE( pwszDescription );
SAFE_ARRAYDELETE( pbCodecInfo );
SAFE_RELEASE( pReaderHeaderInfo3 );
SAFE_RELEASE( pWriterHeaderInfo3 );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::CopyScriptInHeader()
// Desc: Copies the script in the header of the source file to the header
// of the destination file .
//------------------------------------------------------------------------------
HRESULT CWMVCopy::CopyScriptInHeader()
{
HRESULT hr = S_OK;
WORD cScript = 0;
WCHAR * pwszType = NULL;
WCHAR * pwszCommand = NULL;
QWORD cnsScriptTime = 0;
hr = m_pReaderHeaderInfo->GetScriptCount( &cScript );
if( FAILED( hr ) )
{
return( hr );
}
for( WORD i = 0; i < cScript; i++ )
{
WORD cchTypeLen = 0;
WORD cchCommandLen = 0;
//
// Get the memory size for this script
//
hr = m_pReaderHeaderInfo->GetScript( i,
NULL,
&cchTypeLen,
NULL,
&cchCommandLen,
&cnsScriptTime );
if( FAILED( hr ) )
{
break;
}
pwszType = new WCHAR[cchTypeLen];
pwszCommand = new WCHAR[cchCommandLen];
if( pwszType == NULL || pwszCommand == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
//
// Get the script
//
hr = m_pReaderHeaderInfo->GetScript( i,
pwszType,
&cchTypeLen,
pwszCommand,
&cchCommandLen,
&cnsScriptTime );
if( FAILED( hr ) )
{
break;
}
//
// Add the script to the writer
//
hr = m_pWriterHeaderInfo->AddScript( pwszType,
pwszCommand,
cnsScriptTime );
if( FAILED( hr ) )
{
break;
}
SAFE_ARRAYDELETE( pwszType );
SAFE_ARRAYDELETE( pwszCommand );
}
//
// Release all resources
//
SAFE_ARRAYDELETE( pwszType );
SAFE_ARRAYDELETE( pwszCommand );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::Process()
// Desc: Processes the samples from the reader..
//------------------------------------------------------------------------------
HRESULT CWMVCopy::Process()
{
HRESULT hr = S_OK;
//
// Begin writing
//
hr = m_pWriter->BeginWriting( );
if( FAILED( hr ) )
{
return( hr );
}
m_hr = S_OK;
m_fEOF = FALSE;
m_dwProgress = 0;
ResetEvent( m_hEvent );
_tprintf( _T( " 0%%-------20%%-------40%%-------60%%-------80%%-------100%%\n" ) );
_tprintf( _T( "Process: " ) );
//
// Start the reader
//
hr = m_pReader->Start( 0, 0, 1.0, 0 );
if( FAILED( hr ) )
{
return( hr );
}
//
// Wait until the reading is finished
//
hr = WaitForCompletion();
_tprintf( _T( "\n" ) );
if( FAILED( hr ) )
{
return( hr );
}
//
// End writing
//
hr = m_pWriter->EndWriting( );
if( FAILED( hr ) )
{
return( hr );
}
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::CopyMarker()
// Desc: Copies the markers from the source file to the destination file.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::CopyMarker( const WCHAR * pwszOutputFile )
{
HRESULT hr = S_OK;
WORD cMarker = 0;
IWMMetadataEditor * pEditor = NULL;
IWMHeaderInfo * pWriterHeaderInfo = NULL;
WCHAR * pwszMarkerName = NULL;
do
{
hr = m_pReaderHeaderInfo->GetMarkerCount( &cMarker );
if( FAILED( hr ) )
{
break;
}
//
// Markers can be copied only by the metadata editor.
// Create an editor
//
hr = WMCreateEditor( &pEditor );
if( FAILED( hr ) )
{
break;
}
//
// Open the output using the editor
//
hr = pEditor->Open( pwszOutputFile );
if( FAILED ( hr ) )
{
break;
}
hr = pEditor->QueryInterface( IID_IWMHeaderInfo, (void **) &pWriterHeaderInfo );
if( FAILED( hr ) )
{
break;
}
for( WORD i = 0; i < cMarker; i++)
{
WORD cchMarkerNameLen = 0;
QWORD cnsMarkerTime = 0;
//
// Get the memory size for this marker
//
hr = m_pReaderHeaderInfo->GetMarker( i,
NULL,
&cchMarkerNameLen,
&cnsMarkerTime );
if( FAILED( hr ) )
{
break;
}
pwszMarkerName = new WCHAR[cchMarkerNameLen];
if( pwszMarkerName == NULL )
{
hr = E_OUTOFMEMORY;
break;
}
hr = m_pReaderHeaderInfo->GetMarker( i,
pwszMarkerName,
&cchMarkerNameLen,
&cnsMarkerTime );
if( FAILED( hr ) )
{
break;
}
//
// Add marker to the writer
//
hr = pWriterHeaderInfo->AddMarker( pwszMarkerName,
cnsMarkerTime );
if( FAILED( hr ) )
{
break;
}
SAFE_ARRAYDELETE( pwszMarkerName );
}
if( FAILED( hr ) )
{
break;
}
//
// Close and release the editor
//
hr = pEditor->Flush();
if( FAILED( hr ) )
{
break;
}
hr = pEditor->Close();
if( FAILED( hr ) )
{
break;
}
}
while( FALSE );
SAFE_ARRAYDELETE( pwszMarkerName );
SAFE_RELEASE( pWriterHeaderInfo );
SAFE_RELEASE( pEditor );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::CopyScriptInList()
// Desc: Copies scripts in m_ScriptList to the header of the writer.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::CopyScriptInList( const WCHAR * pwszOutputFile )
{
HRESULT hr = S_OK;
CScript * pScript = NULL;
IWMMetadataEditor * pEditor = NULL;
IWMHeaderInfo * pWriterHeaderInfo = NULL;
do
{
//
// Scripts can be added by the metadata editor.
// Create an editor
//
hr = WMCreateEditor( &pEditor );
if( FAILED( hr ) )
{
break;
}
//
// Open the output using the editor
//
hr = pEditor->Open( pwszOutputFile );
if( FAILED ( hr ) )
{
break;
}
hr = pEditor->QueryInterface( IID_IWMHeaderInfo, (void **) &pWriterHeaderInfo );
if( FAILED( hr ) )
{
break;
}
while( m_ScriptList.GetScript( &pScript ) )
{
//
// Add the script to the writer
//
hr = pWriterHeaderInfo->AddScript( pScript->GetType( ),
pScript->GetParameter( ),
pScript->GetTime( ) ) ;
SAFE_DELETE( pScript );
if( FAILED( hr ) )
{
break;
}
}
if( FAILED( hr ) )
{
break;
}
//
// Close and release the editor
//
hr = pEditor->Flush();
if( FAILED( hr ) )
{
break;
}
hr = pEditor->Close();
if( FAILED( hr ) )
{
break;
}
}
while( FALSE );
SAFE_RELEASE( pWriterHeaderInfo );
SAFE_RELEASE( pEditor );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::WaitForCompletion()
// Desc: Waits until the event is signaled.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::WaitForCompletion()
{
HRESULT hr = S_OK;
DWORD dwResult = WaitForSingleObject( m_hEvent, INFINITE );
if( WAIT_OBJECT_0 == dwResult )
{
hr = m_hr;
}
else
{
hr = HRESULT_FROM_WIN32( dwResult );
}
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::Copy()
// Desc: Copies the input file to the output file. The script stream is moved
// to the header if fMoveScriptStream is TRUE.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::Copy( const WCHAR * pwszInputFile,
const WCHAR * pwszOutputFile,
QWORD qwMaxDuration,
BOOL fMoveScriptStream )
{
HRESULT hr = S_OK;
//
// Initialize the pointers
//
m_hEvent = NULL;
m_pReader = NULL;
m_pReaderAdvanced = NULL;
m_pReaderHeaderInfo = NULL;
m_pReaderProfile = NULL;
m_pWriter = NULL;
m_pWriterAdvanced = NULL;
m_pWriterHeaderInfo = NULL;
m_dwStreamCount = 0;
m_pguidStreamType = NULL;
m_pwStreamNumber = NULL;
if( NULL == pwszInputFile || NULL == pwszOutputFile )
{
return( E_INVALIDARG );
}
//
// Dummy do-while loop to do clean up operation before exiting
//
do
{
m_fMoveScriptStream = fMoveScriptStream;
m_qwMaxDuration = qwMaxDuration;
//
// Event for the asynchronous calls
//
m_hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
if( NULL == m_hEvent )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
_tprintf( _T( "Create event failed (hr=0x%08x).\n" ), hr );
break;
}
//
// Create the Reader
//
hr = CreateReader( pwszInputFile );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not create the Reader (hr=0x%08x).\n" ), hr );
break;
}
//
// Get profile information
//
hr = GetProfileInfo();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not update profile information (hr=0x%08x).\n" ), hr );
break;
}
//
// Create the Writer
//
hr = CreateWriter( pwszOutputFile );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not create the Writer (hr=0x%08x).\n" ), hr );
break;
}
//
// Copy all attributes
//
hr = CopyAttribute();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not copy attributes (hr=0x%08x).\n" ), hr );
break;
}
//
// Copy codec info
//
hr = CopyCodecInfo();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not copy codec info (hr=0x%08x).\n" ), hr );
break;
}
//
// Copy all scripts in the header
//
hr = CopyScriptInHeader();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not copy scripts (hr=0x%08x).\n" ), hr );
break;
}
//
// Process samples: read from the reader, and write to the writer
//
hr = Process();
if( FAILED( hr ) )
{
//
// Output some common error messages.
//
if( NS_E_VIDEO_CODEC_NOT_INSTALLED == hr )
{
_tprintf( _T( "Processing samples failed: Video codec not installed\n" ) );
}
if( NS_E_AUDIO_CODEC_NOT_INSTALLED == hr )
{
_tprintf( _T( "Processing samples failed: Audio codec not installed\n" ) );
}
else if( NS_E_INVALID_OUTPUT_FORMAT == hr )
{
_tprintf( _T( "Processing samples failed: Invalid output format \n" ) );
}
else if( NS_E_VIDEO_CODEC_ERROR == hr )
{
_tprintf( _T( "Processing samples failed: An unexpected error occurred with the video codec \n" ) );
}
else if( NS_E_AUDIO_CODEC_ERROR == hr )
{
_tprintf( _T( "Processing samples failed: An unexpected error occurred with the audio codec \n" ) );
}
else
{
_tprintf( _T( "Processing samples failed: Error (hr=0x%08x)\n" ), hr );
}
break;
}
//
// Copy all scripts in m_ScriptList
//
hr = CopyScriptInList( pwszOutputFile );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not copy scripts (hr=0x%08x).\n" ), hr );
break;
}
//
// Copy marker information
//
hr = CopyMarker( pwszOutputFile );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not copy marker (hr=0x%08x).\n" ), hr );
break;
}
_tprintf( _T( "Copy finished.\n" ) );
//
// Note: The output file is indexed automatically.
// You can use IWMWriterFileSink3::SetAutoIndexing(FALSE) to disable
// auto indexing.
//
}
while( FALSE );
SAFE_RELEASE( m_pReaderProfile );
SAFE_RELEASE( m_pReaderHeaderInfo );
SAFE_RELEASE( m_pReaderAdvanced );
SAFE_RELEASE( m_pReader );
SAFE_RELEASE( m_pWriterHeaderInfo );
SAFE_RELEASE( m_pWriterAdvanced );
SAFE_RELEASE( m_pWriter );
SAFE_ARRAYDELETE( m_pguidStreamType );
SAFE_ARRAYDELETE( m_pwStreamNumber );
SAFE_CLOSEHANDLE( m_hEvent );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::OnSample()
// Desc: Implementation of IWMReaderCallback::OnSample.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::OnSample( /* [in] */ DWORD dwOutputNum,
/* [in] */ QWORD qwSampleTime,
/* [in] */ QWORD qwSampleDuration,
/* [in] */ DWORD dwFlags,
/* [in] */ INSSBuffer __RPC_FAR * pSample,
/* [in] */ void __RPC_FAR * pvContext )
{
//
// The samples are expected in OnStreamSample
//
m_hr = E_UNEXPECTED;
_tprintf( _T( "Reader Callback: Received a decompressed sample (hr=0x%08x).\n" ), m_hr );
SetEvent( m_hEvent );
return( S_OK );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::OnStatus()
// Desc: Implementation of IWMStatusCallback::OnStatus.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::OnStatus( /* [in] */ WMT_STATUS Status,
/* [in] */ HRESULT hr,
/* [in] */ WMT_ATTR_DATATYPE dwType,
/* [in] */ BYTE __RPC_FAR * pValue,
/* [in] */ void __RPC_FAR * pvContext)
{
//
// If an error code already exists, just set the event and return.
//
if( FAILED( m_hr ) )
{
SetEvent( m_hEvent );
return( S_OK );
}
//
// If an error occurred in the reader, save this error code and set the event.
//
if( FAILED(hr) )
{
m_hr = hr;
SetEvent( m_hEvent );
return( S_OK );
}
switch ( Status )
{
case WMT_OPENED:
_tprintf( _T( "Reader Callback: File is opened.\n" ) );
m_hr = S_OK;
SetEvent( m_hEvent );
break;
case WMT_STARTED:
//
// Ask for 1 second of the stream to be delivered
//
m_qwReaderTime = 10000000;
hr = m_pReaderAdvanced->DeliverTime( m_qwReaderTime );
if( FAILED( hr ) )
{
m_hr = hr;
SetEvent( m_hEvent );
}
break;
case WMT_EOF:
m_hr = S_OK;
m_fEOF = TRUE;
SetEvent( m_hEvent );
break;
}
return( S_OK );
}
//------------------------------------------------------------------------------
// Name: CWMVCopy::OnTime()
// Desc: Implementation of IWMReaderCallbackAdvanced::OnTime.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::OnTime( /* [in] */ QWORD qwCurrentTime,
/* [in] */ void __RPC_FAR * pvContext)
{
//
// Keep asking for 1 second of the stream till EOF
//
if( !m_fEOF )
{
m_qwReaderTime += 10000000;
HRESULT hr = m_pReaderAdvanced->DeliverTime( m_qwReaderTime );
if( FAILED( hr ) )
{
//
// If an error occurred in the reader, save this error code and set the event.
//
m_hr = hr;
SetEvent( m_hEvent );
}
}
return( S_OK );
}
HRESULT CWMVCopy::OnStreamSample( /* [in] */ WORD wStreamNum,
/* [in] */ QWORD cnsSampleTime,
/* [in] */ QWORD cnsSampleDuration,
/* [in] */ DWORD dwFlags,
/* [in] */ INSSBuffer __RPC_FAR * pSample,
/* [in] */ void __RPC_FAR * pvContext)
{
HRESULT hr = S_OK;
BOOL fMoveScript = FALSE;
while( m_dwProgress <= cnsSampleTime * 50 / m_qwDuration )
{
m_dwProgress ++;
_tprintf( _T( "*" ) );
}
if ( m_qwMaxDuration > 0 && cnsSampleTime > m_qwMaxDuration )
{
SetEvent( m_hEvent );
return( hr );
}
if( m_fMoveScriptStream )
{
//
// We may have multiple script streams in this file.
//
for( DWORD i = 0; i < m_dwStreamCount; i ++ )
{
if( m_pwStreamNumber[i] == wStreamNum )
{
if( WMMEDIATYPE_Script == m_pguidStreamType[ i ] )
{
fMoveScript = TRUE;
}
break;
}
}
}
if( fMoveScript )
{
DWORD dwBufferLength;
int nStringLength;
WCHAR * pwszType = NULL;
WCHAR * pwszCommand = NULL;
do
{
//
// Read the buffer and length of the script stream sample
//
hr = pSample->GetBufferAndLength( (BYTE **)&pwszType, &dwBufferLength );
if( FAILED( hr ) )
{
break;
}
nStringLength = dwBufferLength / 2;
if( nStringLength > 0 )
{
//
// Set the NULL terminator of this sample in case this sample
// doesn't have NULL terminator.
//
pwszType[ nStringLength - 1 ] = 0;
//
// Get the command string of this script
//
pwszCommand = wcschr( pwszType, NULL );
if( pwszCommand - pwszType < nStringLength - 1 )
{
pwszCommand ++;
}
else
{
pwszCommand = L" ";
}
//
// Add the script to the script list. We cannot write scripts
// directly to the writer after writing has begun.
//
hr = m_ScriptList.AddScript( pwszType, pwszCommand, cnsSampleTime );
if( FAILED( hr ) )
{
break;
}
}
}
while( FALSE );
}
else
{
hr = m_pWriterAdvanced->WriteStreamSample( wStreamNum,
cnsSampleTime,
0,
cnsSampleDuration,
dwFlags,
pSample );
}
//
// Set the event if an error occurred
//
if( FAILED( hr ) )
{
m_hr = hr;
SetEvent( m_hEvent );
}
return( S_OK );
}
//------------------------------------------------------------------------------
// Implementation of other IWMReaderCallbackAdvanced methods.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::OnStreamSelection( /* [in] */ WORD wStreamCount,
/* [in] */ WORD __RPC_FAR * pStreamNumbers,
/* [in] */ WMT_STREAM_SELECTION __RPC_FAR * pSelections,
/* [in] */ void __RPC_FAR * pvContext)
{
return( S_OK );
}
HRESULT CWMVCopy::OnOutputPropsChanged( /* [in] */ DWORD dwOutputNum,
/* [in] */ WM_MEDIA_TYPE __RPC_FAR * pMediaType,
/* [in] */ void __RPC_FAR * pvContext )
{
return( S_OK );
}
HRESULT CWMVCopy::AllocateForOutput( /* [in] */ DWORD dwOutputNum,
/* [in] */ DWORD cbBuffer,
/* [out] */ INSSBuffer __RPC_FAR *__RPC_FAR * ppBuffer,
/* [in] */ void __RPC_FAR * pvContext)
{
return( E_NOTIMPL );
}
HRESULT CWMVCopy::AllocateForStream( /* [in] */ WORD wStreamNum,
/* [in] */ DWORD cbBuffer,
/* [out] */ INSSBuffer __RPC_FAR *__RPC_FAR * ppBuffer,
/* [in] */ void __RPC_FAR * pvContext)
{
return( E_NOTIMPL );
}
//------------------------------------------------------------------------------
// Implementation of IUnknown methods.
//------------------------------------------------------------------------------
HRESULT CWMVCopy::QueryInterface( /* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR * ppvObject)
{
if( NULL == ppvObject )
{
return( E_INVALIDARG );
}
if( riid == IID_IWMStatusCallback )
{
*ppvObject = static_cast< IWMStatusCallback * >( this );
AddRef();
}
else if( riid == IID_IWMReaderCallback )
{
*ppvObject = static_cast< IWMReaderCallback * >( this );
AddRef();
}
else if( riid == IID_IWMReaderCallbackAdvanced )
{
*ppvObject = static_cast< IWMReaderCallbackAdvanced * >( this );
AddRef();
}
else if( riid == IID_IUnknown )
{
*ppvObject = static_cast< IWMReaderCallback * >( this );
AddRef();
}
else
{
*ppvObject = NULL;
return( E_NOINTERFACE );
}
return( S_OK );
}
ULONG CWMVCopy::AddRef()
{
return( InterlockedIncrement( &m_cRef ) );
}
ULONG CWMVCopy::Release()
{
if( 0 == InterlockedDecrement( &m_cRef ) )
{
delete this;
}
return( m_cRef );
}