1406 lines
38 KiB
C++
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 );
|
|
}
|