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

1785 lines
53 KiB
C++

//*****************************************************************************
//
// Microsoft Windows Media
// Copyright ( C) Microsoft Corporation. All rights reserved.
//
// FileName: WMVRecompress.cpp
//
// Abstract: Implementation of CWMVRecompress class.
//
//*****************************************************************************
#include <stdio.h>
#include <tchar.h>
#include <assert.h>
#include <windows.h>
#include <mmsystem.h>
#include "WMVRecompress.h"
//------------------------------------------------------------------------------
// Name: CWMVRecompress::CWMVRecompress()
// Desc: Constructor.
//------------------------------------------------------------------------------
CWMVRecompress::CWMVRecompress()
{
//
// Set the reference count to 1 when creating this class.
//
m_cRef = 1;
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::~CWMVRecompress()
// Desc: Destructor.
//------------------------------------------------------------------------------
CWMVRecompress::~CWMVRecompress()
{
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::CreateReader()
// Desc: Creates a reader and opens the source file using this reader. .
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::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 );
}
//
// Get the profile of the reader
//
hr = m_pReader->QueryInterface( IID_IWMProfile, (void **)&m_pReaderProfile );
if( FAILED( hr ) )
{
return( hr );
}
m_hr = S_OK;
ResetEvent( m_hEvent );
//
// Open the reader, using "this" as the callback interface.
//
hr = m_pReader->Open( pwszInputFile, this, NULL );
if( FAILED( hr ) )
{
return( hr );
}
//
// Wait until the WMT_OPENED status message is received in OnStatus()
//
hr = WaitForCompletion();
if( FAILED( hr ) )
{
return( hr );
}
//
// Get the duration of the source file
//
WORD wStreamNum = 0;
WMT_ATTR_DATATYPE enumType;
WORD cbLength = sizeof( m_qwDuration );
hr = m_pReaderHeaderInfo->GetAttributeByName( &wStreamNum,
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 );
}
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::CreateWriter()
// Desc: Creates a writer and sets the profile and output of this writer.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::CreateWriter( const WCHAR * pwszOutputFile,
IWMProfile * pProfile )
{
HRESULT hr = S_OK;
_tprintf( _T( "Creating the Writer...\n" ) );
//
// Create a writer
//
hr = WMCreateWriter( NULL, &m_pWriter );
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
//
hr = m_pWriter->SetProfile( pProfile );
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: CWMVRecompress::GetOutputMap()
// Desc: Creates the map from the reader ouputs to the writer inputs and
// the map from the reader outputs to the reader streams.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::GetOutputMap()
{
HRESULT hr = S_OK;
IWMInputMediaProps * pWriterInputProps = NULL;
IWMOutputMediaProps * pReaderOutputProps = NULL;
IWMStreamConfig * pReaderStreamConfig = NULL;
DWORD cReaderStream = 0;
GUID guidReaderOutput;
GUID guidWriterInput;
WCHAR * pwszOutputConnectionName = NULL;
WCHAR * pwszStreamConnectionName = NULL;
WORD cbConnectionName = 0;
BOOL fMatch = FALSE;
do
{
//
// Get the output count of the reader
//
hr = m_pReader->GetOutputCount( &m_cReaderOutput );
if( FAILED( hr ) )
{
break;
}
//
// Get the input count of the writer
//
hr = m_pWriter->GetInputCount( &m_cWriterInput );
if( FAILED( hr ) )
{
break;
}
//
// Get the stream count of the reader
//
hr = m_pReaderProfile->GetStreamCount( &cReaderStream );
if( FAILED( hr ) )
{
break;
}
//
// Allocate memory for the map
//
m_pdwOutputToInput = new DWORD[ m_cReaderOutput ];
m_pdwOutputToStream = new DWORD[ m_cReaderOutput ];
if( NULL == m_pdwOutputToInput || NULL == m_pdwOutputToStream )
{
hr = E_OUTOFMEMORY;
break;
}
//
// Iterate all outputs of the reader
//
for( DWORD i = 0; i < m_cReaderOutput; i ++ )
{
//
// Get the output property interface of the reader
//
hr = m_pReader->GetOutputProps( i, &pReaderOutputProps );
if( FAILED( hr ) )
{
break;
}
//
// Get the type of this output property
//
hr = pReaderOutputProps->GetType( &guidReaderOutput );
if( FAILED( hr ) )
{
break;
}
//
// Get the connection name of this output
//
hr = pReaderOutputProps->GetConnectionName( NULL, &cbConnectionName );
if( FAILED( hr ) )
{
break;
}
pwszOutputConnectionName = new WCHAR[ cbConnectionName ];
if( NULL == pwszOutputConnectionName )
{
hr = E_OUTOFMEMORY;
break;
}
hr = pReaderOutputProps->GetConnectionName( pwszOutputConnectionName, &cbConnectionName );
if( FAILED( hr ) )
{
break;
}
//
// This loop tries to find a matching input of the writer for this output:
// 1. The input must not be matched by other outputs of the reader.
// 2. The input must have the same type as this output.
//
DWORD j;
for( j = 0; j < m_cWriterInput; j ++ )
{
//
// Seach for the current reader outputs to writer inputs map
//
DWORD k;
for( k = 0; k < i; k ++ )
{
if( m_pdwOutputToInput[ k ] == j )
{
break;
}
}
//
// If this input has been matched by other outputs of the reader,
// then don't use this input.
//
if( k < i )
{
continue;
}
//
// Get the input property of the writer
//
hr = m_pWriter->GetInputProps( j, &pWriterInputProps );
if( FAILED( hr ) )
{
break;
}
//
// Get the type of this input property
//
hr = pWriterInputProps->GetType( &guidWriterInput );
if( FAILED( hr ) )
{
break;
}
SAFE_RELEASE( pWriterInputProps );
//
// If this input type of the writer is equal to the output
// type of the reader, we found a match.
//
if( guidReaderOutput == guidWriterInput )
{
fMatch = TRUE;
m_pdwOutputToInput[ i ] = j;
_tprintf( _T( "Output %d of the reader is mapped to input %d of the writer.\n" ), i, j );
break;
}
}
if( FAILED( hr ) )
{
break;
}
//
// If we cannot find a match for this output, mark it in the map.
//
if( j >= m_cWriterInput )
{
m_pdwOutputToInput[ i ] = 0xFFFFFFFF;
}
//
// In a multiple bitrate(MBR) file, several streams could have the
// same output number. When playing the MBR file, the reader
// determines the best stream to use based on the available resource.
//
// This loop finds the actual stream from which this reader output
// comes. This information will be used to set up multichannel
// encoding and smart recompression.
//
for( j = 0; j < cReaderStream; j ++ )
{
//
// Get the stream configuration from the reader's profile
//
hr = m_pReaderProfile->GetStream( j, &pReaderStreamConfig );
if( FAILED( hr ) )
{
break;
}
//
// Get the connection name of this stream configuration
//
hr = pReaderStreamConfig->GetConnectionName( NULL, &cbConnectionName );
if( FAILED( hr ) )
{
break;
}
pwszStreamConnectionName = new WCHAR[ cbConnectionName ];
if( NULL == pwszStreamConnectionName )
{
hr = E_OUTOFMEMORY;
break;
}
hr = pReaderStreamConfig->GetConnectionName( pwszStreamConnectionName, &cbConnectionName );
if( FAILED( hr ) )
{
break;
}
SAFE_RELEASE( pReaderStreamConfig );
//
// If this output comes from this stream, they should have the
// same conneciton name
//
if( 0 == _wcsicmp( pwszStreamConnectionName, pwszOutputConnectionName ) )
{
m_pdwOutputToStream[ i ] = j;
SAFE_ARRAYDELETE( pwszStreamConnectionName );
break;
}
SAFE_ARRAYDELETE( pwszStreamConnectionName );
}
if( FAILED( hr ) )
{
break;
}
SAFE_RELEASE( pReaderOutputProps );
SAFE_ARRAYDELETE( pwszOutputConnectionName );
}
if( FAILED( hr ) )
{
break;
}
//
// At least one output of the reader should be mapped to the input
// of the writer.
//
if( !fMatch )
{
hr = E_FAIL;
_tprintf( _T( "Could not map any stream from the input file to the output file.\n" ) );
break;
}
}
while( FALSE );
//
// Release all resources
//
SAFE_ARRAYDELETE( pwszStreamConnectionName );
SAFE_ARRAYDELETE( pwszOutputConnectionName );
SAFE_RELEASE( pReaderStreamConfig );
SAFE_RELEASE( pReaderOutputProps );
SAFE_RELEASE( pWriterInputProps );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::SetWriterInput()
// Desc: Sets the input properties of the writer. The method will set up
// multichannel source and smart recompression if it's necessary.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::SetWriterInput( BOOL fMultiChannel,
BOOL fSmartRecompression )
{
HRESULT hr = S_OK;
IWMReaderAdvanced2 * pReaderAdvanced2;
IWMOutputMediaProps * pReaderOutputProps = NULL;
IWMStreamConfig * pReaderStreamConfig = NULL;
IWMMediaProps * pReaderStreamProps = NULL;
IWMInputMediaProps * pWriterInputProps = NULL;
GUID enumType;
WM_MEDIA_TYPE * pOutputMediaType = NULL;
WM_MEDIA_TYPE * pStreamMediaType = NULL;
IWMPropertyVault * pPropertyVault = NULL;
DWORD cbMediaType = 0;
_tprintf( _T( "Setting the inputs of the writer...\n" ) );
do
{
//
// Get IWMReaderAdvanced2 interface from the reader
//
hr = m_pReader->QueryInterface( IID_IWMReaderAdvanced2, (void **)&pReaderAdvanced2 );
if( FAILED( hr ) )
{
break;
}
//
// Iterate all outputs of the reader
//
for( DWORD i = 0; i < m_cReaderOutput; i ++ )
{
//
// If this output has a matching input in the writer, set up the input
//
if( 0xFFFFFFFF != m_pdwOutputToInput[ i ] )
{
//
// Get the output property of the reader
//
hr = m_pReader->GetOutputProps( i, &pReaderOutputProps );
if( FAILED( hr ) )
{
break;
}
// Get the input media properties of the writer
hr = m_pWriter->GetInputProps( m_pdwOutputToInput[ i ],
&pWriterInputProps );
if( FAILED( hr ) )
{
break;
}
// Get the media type
hr = pWriterInputProps->GetType( &enumType );
if( FAILED( hr ) )
{
break;
}
//
// We need do more work if the stream type is audio and
// multichannel output or smart recompression is enabled.
//
if( ( fMultiChannel || fSmartRecompression ) &&
WMMEDIATYPE_Audio == enumType )
{
//
// Get the stream from which this output comes
//
hr = m_pReaderProfile->GetStream( m_pdwOutputToStream[ i ],
&pReaderStreamConfig );
if( FAILED( hr ) )
{
break;
}
//
// Get the media property interface of this stream
//
hr = pReaderStreamConfig->QueryInterface( IID_IWMMediaProps,
(void **)&pReaderStreamProps );
if( FAILED( hr ) )
{
break;
}
//
// Get the media type of this stream
//
hr = pReaderStreamProps->GetMediaType( NULL, &cbMediaType );
if( FAILED( hr ) )
{
break;
}
pStreamMediaType = (WM_MEDIA_TYPE *)new BYTE[ cbMediaType ];
if( NULL == pStreamMediaType )
{
hr = E_OUTOFMEMORY;
break;
}
hr = pReaderStreamProps->GetMediaType( pStreamMediaType,
&cbMediaType );
if( FAILED( hr ) )
{
break;
}
//
// Enable multichannel output for the reader if it's required.
// We'll only enable multichannel output when the source has
// more than 2 channels.
//
// Multichannel output only works on Windodws XP, and it's
// not necessary unless a multichannel profile is used in
// the writer.
//
WAVEFORMATEX * pWFX = (WAVEFORMATEX *)pStreamMediaType->pbFormat;
if( fMultiChannel && 2 < pWFX->nChannels )
{
_tprintf( _T( "Multichannel output is enabled for output %d of the reader.\n" ), i );
BOOL fEnableDiscreteOutput = TRUE;
hr = pReaderAdvanced2->SetOutputSetting( i,
g_wszEnableDiscreteOutput,
WMT_TYPE_BOOL,
(BYTE *)&fEnableDiscreteOutput,
sizeof( BOOL ) );
if( FAILED( hr ) )
{
break;
}
DWORD dwSpeakerConfig = pWFX->nChannels;
hr = pReaderAdvanced2->SetOutputSetting( i,
g_wszSpeakerConfig,
WMT_TYPE_DWORD,
(BYTE *)&dwSpeakerConfig,
sizeof( DWORD ) );
if( FAILED( hr ) )
{
break;
}
//
// We need to call SetOutputProps() to change output properties accordingly
//
SAFE_RELEASE( pReaderOutputProps );
hr = m_pReader->GetOutputFormat( i, 0, &pReaderOutputProps );
if( FAILED( hr ) )
{
break;
}
hr = m_pReader->SetOutputProps( i, pReaderOutputProps );
if( FAILED( hr ) )
{
break;
}
}
//
// Set smart recompression if it's required.
//
if( fSmartRecompression )
{
_tprintf( _T( "Smart recompression is enabled for input %d of the writer.\n" ),
m_pdwOutputToInput[ i ] );
hr = pWriterInputProps->QueryInterface( IID_IWMPropertyVault,
(void **)&pPropertyVault );
if( FAILED( hr ))
{
break;
}
hr = pPropertyVault->SetProperty( g_wszOriginalWaveFormat,
WMT_TYPE_BINARY,
pStreamMediaType->pbFormat,
pStreamMediaType->cbFormat );
if( FAILED( hr ))
{
break;
}
}
}
//
// Get the media type of the output property
//
hr = pReaderOutputProps->GetMediaType( NULL, &cbMediaType );
if( FAILED( hr ) )
{
break;
}
pOutputMediaType = (WM_MEDIA_TYPE *)new BYTE[ cbMediaType ];
if( NULL == pOutputMediaType )
{
hr = E_OUTOFMEMORY;
break;
}
hr = pReaderOutputProps->GetMediaType( pOutputMediaType,
&cbMediaType );
if( FAILED( hr ) )
{
break;
}
//
// Apply the media type of the output to the input property
// of the writer
//
hr = pWriterInputProps->SetMediaType( pOutputMediaType );
if( FAILED( hr ) )
{
break;
}
//
// Apply the changes of input properties to the writer
//
hr = m_pWriter->SetInputProps( m_pdwOutputToInput[ i ], pWriterInputProps );
if( FAILED( hr ) )
{
break;
}
//
// Release all resources
//
SAFE_ARRAYDELETE( pStreamMediaType );
SAFE_ARRAYDELETE( pOutputMediaType );
SAFE_RELEASE( pPropertyVault );
SAFE_RELEASE( pReaderStreamProps );
SAFE_RELEASE( pReaderStreamConfig );
SAFE_RELEASE( pWriterInputProps );
SAFE_RELEASE( pReaderOutputProps );
}
}
if( FAILED( hr ) )
{
break;
}
}
while( FALSE );
//
// Release all resources
//
SAFE_ARRAYDELETE( pStreamMediaType );
SAFE_ARRAYDELETE( pOutputMediaType );
SAFE_RELEASE( pPropertyVault );
SAFE_RELEASE( pWriterInputProps );
SAFE_RELEASE( pReaderOutputProps );
SAFE_RELEASE( pReaderStreamProps );
SAFE_RELEASE( pReaderStreamConfig );
SAFE_RELEASE( pReaderAdvanced2 );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::Preprocess()
// Desc: Preprocesses the samples from the reader.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::Preprocess()
{
HRESULT hr = S_OK;
//
// Get the IWMWriterPreprocess interface from the writer
//
hr = m_pWriter->QueryInterface( IID_IWMWriterPreprocess,
(void **)&m_pWriterPreprocess );
if( FAILED( hr ) )
{
return( hr );
}
//
// Allocate memroy for an array to store the preprocessing passes
//
m_pdwPreprocessPass = new DWORD[ m_cWriterInput ];
if( NULL == m_pdwPreprocessPass )
{
hr = E_OUTOFMEMORY;
return( hr );
}
//
// Before preprocessing, we need to iterate all inputs of the writer
// and get the preprocessing passes. Different inputs of the writer
// could have different preprocessing passes.
//
DWORD i;
for( i = 0; i < m_cWriterInput; i ++ )
{
//
// If this input doesn't have a matching input in the reader,
// we don't need to do preprocessing for this input.
//
DWORD j;
for( j = 0; j < m_cReaderOutput; j ++ )
{
if( m_pdwOutputToInput[ j ] == i )
{
break;
}
}
if( j < m_cReaderOutput )
{
//
// Get the maximum number of preprocessing passes for this input
//
hr = m_pWriterPreprocess->GetMaxPreprocessingPasses( i,
0,
&m_pdwPreprocessPass[ i ] );
if( FAILED( hr ) )
{
return( hr );
}
//
// We do preprocessing only if the number of preprocessing passes is not 0
//
if( 0 != m_pdwPreprocessPass[ i ] )
{
//
// Use the maximum number of preprocessing passes
//
hr = m_pWriterPreprocess->SetNumPreprocessingPasses( i,
0,
m_pdwPreprocessPass[ i ] );
if( FAILED( hr ) )
{
return( hr );
}
//
// Begin preprocessing for this input
//
hr = m_pWriterPreprocess->BeginPreprocessingPass( i, 0 );
if( FAILED( hr ) )
{
return( hr );
}
}
}
else
{
//
// Set the preprocessing pass to 0 if the input doesn't have
// a matching output in the reader
//
m_pdwPreprocessPass[ i ] = 0;
}
}
while( TRUE )
{
//
// We do preprocessing only if at least one input has more than zero
// preprocessing passes.
//
for( i = 0; i < m_cWriterInput; i ++ )
{
if( 0 < m_pdwPreprocessPass[ i ] )
{
break;
}
}
if( i == m_cWriterInput )
{
//
// We don't need to do preprocessing again, because the preprocessing
// passes of all writer inputs are zero now
//
break;
}
//
// Set m_bPreprocessing flag to true, so OnSample() will deliver the
// sample to m_pWriterPreprocess, not to m_pWriter.
//
m_bPreprocessing = TRUE;
m_hr = S_OK;
m_fEOF = FALSE;
m_qwReaderTime = 0;
m_dwProgress = 0;
ResetEvent( m_hEvent );
_tprintf( _T( " 0%%-------20%%-------40%%-------60%%-------80%%-------100%%\n" ) );
_tprintf( _T( "Preprocess: " ) );
//
// 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 );
}
//
// Stop the reader
//
hr = m_pReader->Stop( );
if( FAILED( hr ) )
{
return( hr );
}
//
// Decrease the preprocessing passes of each input
//
for( i = 0; i < m_cWriterInput; i ++ )
{
if( 0 < m_pdwPreprocessPass[ i ] )
{
m_pdwPreprocessPass[ i ] --;
if( 0 == m_pdwPreprocessPass[ i ] )
{
//
// If we don't need to do preprocessing for this input again,
// call EndPreprocessingPass() to stop preprocessing.
//
hr = m_pWriterPreprocess->EndPreprocessingPass( i, 0 );
if( FAILED( hr ) )
{
return( hr );
}
}
}
}
}
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::Process()
// Desc: Processes the samples from the reader.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::Process()
{
HRESULT hr = S_OK;
//
// Set m_bPreprocessing flag to false, so OnSample() will deliver the
// sample to m_pWriter, not to m_pWriterPreprocess.
//
m_bPreprocessing = FALSE;
m_hr = S_OK;
m_fEOF = FALSE;
m_qwReaderTime = 0;
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 );
}
//
// Stop the reader
//
hr = m_pReader->Stop( );
if( FAILED( hr ) )
{
return( hr );
}
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::WaitForCompletion()
// Desc: Waits until the event is signaled.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::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: CWMVRecompress::Recompress()
// Desc: Copies the input file to the output file, using the specified profile.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::Recompress( const WCHAR * pwszInputFile,
const WCHAR * pwszOutputFile,
IWMProfile * pProifle,
BOOL fMultiPass,
BOOL fMultiChannel,
BOOL fSmartRecompression )
{
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_pWriterPreprocess = NULL;
m_pWriterHeaderInfo = NULL;
m_pdwPreprocessPass = NULL;
m_pdwOutputToInput = NULL;
m_pdwOutputToStream = NULL;
if( NULL == pwszInputFile || NULL == pwszOutputFile || NULL == pProifle )
{
return E_INVALIDARG;
}
//
// Dummy do-while loop to do cleanup operation before exiting
//
do
{
//
// 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 for file %ws (hr=0x%08x).\n" ), pwszInputFile, hr );
break;
}
//
// Create the writer
//
hr = CreateWriter( pwszOutputFile, pProifle );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not create the Writer for file %ws (hr=0x%08x).\n" ), pwszOutputFile, hr );
break;
}
//
// Get the map from the reader ouputs to the writer inputs and
// the map from the reader outputs to the reader streams
//
hr = GetOutputMap();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not get the output map (hr=0x%08x).\n" ), hr );
break;
}
//
// Set the properties of writer inputs
//
hr = SetWriterInput( fMultiChannel, fSmartRecompression );
if( FAILED( hr ) )
{
if( NS_E_INVALID_INPUT_FORMAT == hr )
{
_tprintf( _T( "Set writer input failed: The input format is invalid (hr=0x%08x).\n" ), hr );
}
else
{
_tprintf( _T( "Set writer input failed: Error (hr=0x%08x).\n" ), hr );
}
break;
}
//
// Start the encoding
//
hr = m_pWriter->BeginWriting( );
if( FAILED( hr ) )
{
if( NS_E_VIDEO_CODEC_NOT_INSTALLED == hr )
{
_tprintf( _T( "BeginWriting failed: Video codec not installed\n" ) );
}
if( NS_E_AUDIO_CODEC_NOT_INSTALLED == hr )
{
_tprintf( _T( "BeginWriting failed: Audio codec not installed\n" ) );
}
else if( NS_E_INVALID_OUTPUT_FORMAT == hr )
{
_tprintf( _T( "BeginWriting failed: Invalid output format \n" ) );
}
else if( NS_E_VIDEO_CODEC_ERROR == hr )
{
_tprintf( _T( "BeginWriting failed: An unexpected error occurred with the video codec \n" ) );
}
else if( NS_E_AUDIO_CODEC_ERROR == hr )
{
_tprintf( _T( "BeginWriting failed: An unexpected error occurred with the audio codec \n" ) );
}
else
{
_tprintf( _T( "BeginWriting failed: Error (hr=0x%08x)\n" ), hr );
}
break;
}
//
// Preprocess the samples if multi-pass is enabled
//
if( fMultiPass )
{
hr = Preprocess();
if(FAILED(hr ))
{
if( NS_E_INVALID_NUM_PASSES == hr )
{
_tprintf( _T( "Preprocessing samples failed: Invalid preprocessing passes. Don't use -m option\n" ) );
}
else
{
_tprintf( _T( "Preprocessing samples failed: Error (hr=0x%08x)\n" ), hr );
}
break;
}
}
//
// Process all samples from the reader
//
hr = Process();
if(FAILED(hr ))
{
if( NS_E_INVALID_NUM_PASSES == hr )
{
_tprintf( _T( "Processing samples failed: Invalid preprocessing passes. Use -m option\n" ) );
}
else
{
_tprintf( _T( "Processing samples failed: Error (hr=0x%08x)\n" ), hr );
}
break;
}
//
// End writing
//
hr = m_pWriter->EndWriting( );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not end writing (hr=0x%08x).\n" ), hr );
break;
}
//
// Close the reader
//
hr = m_pReader->Close();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not close the reader (hr=0x%08x).\n" ), hr );
break;
}
_tprintf( _T( "Recompression finished.\n" ) );
//
// Note: The output file is indexed automatically.
// You can use IWMWriterFileSink3::SetAutoIndexing(FALSE) to disable
// auto indexing.
//
}
while( FALSE );
//
// Release all resources
//
SAFE_ARRAYDELETE( m_pdwOutputToStream );
SAFE_ARRAYDELETE( m_pdwOutputToInput );
SAFE_ARRAYDELETE( m_pdwPreprocessPass );
SAFE_RELEASE( m_pWriterPreprocess );
SAFE_RELEASE( m_pWriterHeaderInfo );
SAFE_RELEASE( m_pWriter );
SAFE_RELEASE( m_pReaderProfile );
SAFE_RELEASE( m_pReaderHeaderInfo );
SAFE_RELEASE( m_pReaderAdvanced );
SAFE_RELEASE( m_pReader );
SAFE_CLOSEHANDLE( m_hEvent );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::OnSample()
// Desc: Implementation of IWMReaderCallback::OnSample.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::OnSample( /* [in] */ DWORD dwOutputNum,
/* [in] */ QWORD qwSampleTime,
/* [in] */ QWORD qwSampleDuration,
/* [in] */ DWORD dwFlags,
/* [in] */ INSSBuffer __RPC_FAR * pSample,
/* [in] */ void __RPC_FAR * pvContext )
{
HRESULT hr = S_OK;
//
// Get the input of the writer that matches this output.
//
DWORD dwInput = m_pdwOutputToInput[ dwOutputNum ];
//
// If this output of the reader doesn't have a matching input of the writer,
// we'll not pass this sample to the writer.
//
if( 0xFFFFFFFF != dwInput )
{
//
// Display the progress information to the user
//
while( m_dwProgress <= qwSampleTime * 50 / m_qwDuration )
{
m_dwProgress ++;
_tprintf( _T( "*" ) );
}
//
// If it's preprocessing, we pass the sample to m_pWriterPreprocess,
// otherwise we pass the sample to the m_pWriter.
//
if( m_bPreprocessing )
{
//
// If the preprocessing passes of the input is 0, we'll not
// preprocess this sample.
//
if( m_pdwPreprocessPass[ dwInput ] > 0 )
{
hr = m_pWriterPreprocess->PreprocessSample( dwInput, // input number
qwSampleTime, // presentation time
dwFlags, // flags
pSample ); // the data
}
}
else
{
hr = m_pWriter->WriteSample( dwInput, // input number
qwSampleTime, // presentation time
dwFlags, // flags
pSample ); // the data
}
//
// If an error occured in Reader, save this error code and set the event.
//
if( FAILED( hr ) )
{
m_hr = hr;
SetEvent( m_hEvent );
}
}
return(S_OK);
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::OnStatus()
// Desc: Implementation of IWMStatusCallback::OnStatus.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::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);
}
//
// Status gives the current status of the reading of the input file
//
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: CWMVRecompress::OnTime()
// Desc: Implementation of IWMReaderCallbackAdvanced::OnTime.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::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);
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::OnStreamSample()
// Desc: Implementation of IWMReaderCallbackAdvanced::OnStreamSample.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::OnStreamSample( /* [in] */ WORD wStreamNum,
/* [in] */ QWORD cnsSampleTime,
/* [in] */ QWORD cnsSampleDuration,
/* [in] */ DWORD dwFlags,
/* [in] */ INSSBuffer __RPC_FAR * pSample,
/* [in] */ void __RPC_FAR * pvContext )
{
//
// The samples are expected in OnSample
//
m_hr = E_UNEXPECTED;
_tprintf( _T( "Reader Callback: Received a compressed sample (hr=0x%08x).\n" ), m_hr );
SetEvent( m_hEvent );
return(S_OK);
}
//------------------------------------------------------------------------------
// Implementation of other IWMReaderCallbackAdvanced methods.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::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 CWMVRecompress::OnOutputPropsChanged( /* [in] */ DWORD dwOutputNum,
/* [in] */ WM_MEDIA_TYPE __RPC_FAR * pMediaType,
/* [in] */ void __RPC_FAR * pvContext )
{
return(S_OK);
}
HRESULT CWMVRecompress::AllocateForOutput( /* [in] */ DWORD dwOutputNum,
/* [in] */ DWORD cbBuffer,
/* [out] */ INSSBuffer __RPC_FAR *__RPC_FAR * ppBuffer,
/* [in] */ void __RPC_FAR * pvContext)
{
return E_NOTIMPL;
}
HRESULT CWMVRecompress::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 CWMVRecompress::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 CWMVRecompress::AddRef()
{
return( InterlockedIncrement( &m_cRef ) );
}
ULONG CWMVRecompress::Release()
{
if( 0 == InterlockedDecrement( &m_cRef ) )
{
delete this;
}
return( m_cRef );
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::ListSystemProfile()
// Desc: Enumerates all system profiles (version 8.0), and displays their
// indexes and names.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::ListSystemProfile()
{
HRESULT hr = S_OK;
DWORD dwIndex = 0;
DWORD cProfiles = 0;
IWMProfileManager * pIWMProfileManager = NULL;
IWMProfileManager2 * pIWMProfileManager2 = NULL;
IWMProfile * pIWMProfile = NULL;
LPWSTR pwszName = NULL;
DWORD cchName = 0;
do
{
//
// Create profile manager
//
hr = WMCreateProfileManager( &pIWMProfileManager );
if( FAILED( hr ) )
{
break;
}
hr = pIWMProfileManager->QueryInterface( IID_IWMProfileManager2,
( void ** )&pIWMProfileManager2 );
if( FAILED( hr ) )
{
break;
}
//
// Set system profile version to 8.0
//
hr = pIWMProfileManager2->SetSystemProfileVersion( WMT_VER_8_0 );
if( FAILED( hr ) )
{
break;
}
hr = pIWMProfileManager->GetSystemProfileCount( &cProfiles );
if( FAILED( hr ) )
{
break;
}
_tprintf( _T( "Profile Indexes are as follows:\n" ) );
//
// Iterate all system profiles
//
for( dwIndex = 0; dwIndex < cProfiles; dwIndex++ )
{
hr = pIWMProfileManager->LoadSystemProfile( dwIndex, &pIWMProfile );
if ( FAILED( hr ) )
{
break;
}
hr = pIWMProfile->GetName( NULL, &cchName );
if ( FAILED( hr ) )
{
break;
}
pwszName = new WCHAR[ cchName ];
if( NULL == pwszName )
{
hr = E_OUTOFMEMORY;
break;
}
hr = pIWMProfile->GetName( pwszName, &cchName );
if ( FAILED( hr ) )
{
break;
}
//
// Display the system profile index and name
//
_tprintf( _T( " %d - %ws \n" ), dwIndex + 1, pwszName );
SAFE_ARRAYDELETE( pwszName );
SAFE_RELEASE( pIWMProfile );
}
if( FAILED( hr ) )
{
break;
}
}
while( FALSE );
//
// Release all resources
//
SAFE_ARRAYDELETE( pwszName );
SAFE_RELEASE( pIWMProfile );
SAFE_RELEASE( pIWMProfileManager2 );
SAFE_RELEASE( pIWMProfileManager );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::LoadSystemProfile()
// Desc: Loads a system profile (version 8.0) by the index.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::LoadSystemProfile( DWORD dwProfileIndex,
IWMProfile ** ppIWMProfile )
{
HRESULT hr = S_OK;
IWMProfileManager * pIWMProfileManager = NULL;
IWMProfileManager2 * pIWMProfileManager2 = NULL;
if( NULL == ppIWMProfile )
{
return( E_POINTER );
}
do
{
//
// Create profile manager
//
hr = WMCreateProfileManager( &pIWMProfileManager );
if( FAILED( hr ) )
{
break;
}
hr = pIWMProfileManager->QueryInterface( IID_IWMProfileManager2,
( void ** )&pIWMProfileManager2 );
if( FAILED( hr ) )
{
break;
}
//
// Set system profile version to 8.0
//
hr = pIWMProfileManager2->SetSystemProfileVersion( WMT_VER_8_0 );
if( FAILED( hr ) )
{
break;
}
//
// Load the system profile by index
//
hr = pIWMProfileManager->LoadSystemProfile( dwProfileIndex,
ppIWMProfile );
if( FAILED( hr ) )
{
break;
}
}
while( FALSE );
//
// Release all resources
//
SAFE_RELEASE( pIWMProfileManager2 );
SAFE_RELEASE( pIWMProfileManager );
return( hr );
}
//------------------------------------------------------------------------------
// Name: CWMVRecompress::LoadCustomProfile()
// Desc: Loads a custom profile from file.
//------------------------------------------------------------------------------
HRESULT CWMVRecompress::LoadCustomProfile( const WCHAR * pwszProfileFile,
IWMProfile ** ppIWMProfile )
{
HRESULT hr = S_OK;
DWORD dwLength = 0;
DWORD dwBytesRead = 0;
HANDLE hFile = INVALID_HANDLE_VALUE;
IWMProfileManager * pProfileManager = NULL;
WCHAR * pProfile = NULL;
if( NULL == ppIWMProfile || NULL == pwszProfileFile )
{
return( E_POINTER );
}
do
{
//
// Create profile manager
//
hr = WMCreateProfileManager( &pProfileManager );
if( FAILED( hr ) )
{
break;
}
//
// Open the profile file
//
hFile = CreateFileW( pwszProfileFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if( INVALID_HANDLE_VALUE == hFile )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
break;
}
if( FILE_TYPE_DISK != GetFileType( hFile ) )
{
hr = NS_E_INVALID_NAME;
break;
}
dwLength = GetFileSize( hFile, NULL );
if( -1 == dwLength )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
break;
}
//
// Allocate memory for profile buffer
//
pProfile = (WCHAR *) new BYTE[ dwLength + sizeof(WCHAR) ];
if( NULL == pProfile )
{
hr = E_OUTOFMEMORY;
break;
}
// The buffer must be NULL terminated.
memset( pProfile, 0, dwLength + sizeof(WCHAR) );
//
// Read the profile to a buffer
//
if( !ReadFile( hFile, pProfile, dwLength, &dwBytesRead, NULL ) )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
break;
}
//
// Load the profile from the buffer
//
hr = pProfileManager->LoadProfileByData( pProfile,
ppIWMProfile );
if( FAILED(hr) )
{
break;
}
}
while( FALSE );
//
// Release all resources
//
SAFE_ARRAYDELETE( pProfile );
SAFE_CLOSEFILEHANDLE( hFile );
SAFE_RELEASE( pProfileManager );
return( hr );
}