408 lines
13 KiB
C++
408 lines
13 KiB
C++
//*****************************************************************************
|
|
//
|
|
// Microsoft Windows Media
|
|
// Copyright (C) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// FileName: Streamdata.cpp
|
|
//
|
|
// Abstract: Implementation of CStreamData class
|
|
//
|
|
//*****************************************************************************
|
|
#include "stdafx.h"
|
|
#include "StreamData.h"
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CStreamData::CStreamData()
|
|
// Desc: Constructor.
|
|
//------------------------------------------------------------------------------
|
|
CStreamData::CStreamData( DWORD dwStreamCount )
|
|
{
|
|
m_dwStreamCount = dwStreamCount;
|
|
m_ptrStreamNumArray = NULL;
|
|
m_ptrMediaArray = NULL;
|
|
m_ptrStreamBufferWindow = NULL;
|
|
m_pfVBRStream = NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CStreamData::~CStreamData()
|
|
// Desc: Destructor.
|
|
//------------------------------------------------------------------------------
|
|
CStreamData::~CStreamData()
|
|
{
|
|
if( m_ptrMediaArray )
|
|
{
|
|
for( DWORD i = 0; i < m_dwStreamCount; i++ )
|
|
{
|
|
if( m_ptrMediaArray[i] )
|
|
{
|
|
delete[] (BYTE*)m_ptrMediaArray[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
SAFE_ARRAYDELETE( m_ptrMediaArray );
|
|
SAFE_ARRAYDELETE( m_ptrStreamNumArray );
|
|
SAFE_ARRAYDELETE( m_ptrStreamBufferWindow );
|
|
SAFE_ARRAYDELETE( m_pfVBRStream );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CStreamData::SetAllStreamData()
|
|
// Desc: Sets the stream numbers and media types in the member variables
|
|
// for the specified profile.
|
|
//------------------------------------------------------------------------------
|
|
HRESULT CStreamData::SetAllStreamData( IWMProfile * pProfile )
|
|
{
|
|
if( NULL == pProfile )
|
|
{
|
|
return( E_INVALIDARG );
|
|
}
|
|
//
|
|
// Make an array of pointers to WM_MEDIA_TYPE
|
|
//
|
|
m_ptrMediaArray = new WM_MEDIA_TYPE* [m_dwStreamCount];
|
|
|
|
m_ptrStreamNumArray = new WORD [m_dwStreamCount];
|
|
|
|
m_ptrStreamBufferWindow = new DWORD [m_dwStreamCount];
|
|
|
|
m_pfVBRStream = new BOOL[m_dwStreamCount];
|
|
|
|
if( NULL == m_ptrMediaArray || NULL == m_ptrStreamNumArray || NULL == m_ptrStreamBufferWindow )
|
|
{
|
|
_tprintf( _T( "Internal Error: Out of memory\n" ) );
|
|
return( E_OUTOFMEMORY );
|
|
}
|
|
|
|
ZeroMemory( m_ptrMediaArray, m_dwStreamCount * sizeof( WM_MEDIA_TYPE * ) );
|
|
|
|
ZeroMemory( m_ptrStreamNumArray, m_dwStreamCount * sizeof( WORD ) );
|
|
|
|
ZeroMemory( m_ptrStreamBufferWindow, m_dwStreamCount * sizeof( DWORD ) );
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD cbType = 0;
|
|
|
|
IWMMediaProps * pProps = NULL;
|
|
IWMStreamConfig * pStream = NULL;
|
|
IWMPropertyVault * pPropertyVault = NULL;
|
|
WMT_ATTR_DATATYPE enumAttrType;
|
|
DWORD dwAttrSize;
|
|
|
|
//
|
|
// Get all the stream numbers and the WM_MEDIA_TYPEs in the arrays
|
|
//
|
|
for( DWORD i = 0; i < m_dwStreamCount; i++ )
|
|
{
|
|
|
|
hr = pProfile->GetStream( i, &pStream );
|
|
if( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not get Stream %d from IWMProfile (hr=0x%08x).\n" ), i, hr );
|
|
break;
|
|
}
|
|
|
|
pStream->GetStreamNumber( &m_ptrStreamNumArray[i] );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not GetStreamNumber from IWMStreamConfig %d (hr=0x%08x).\n" ), i, hr );
|
|
break;
|
|
}
|
|
|
|
hr = pStream->QueryInterface( IID_IWMMediaProps, ( VOID ** )&pProps );
|
|
if( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not QI for IWMMediaProps (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
|
|
hr = pStream->GetBufferWindow( &m_ptrStreamBufferWindow[ i ] );
|
|
if( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not get Buffer Window from IWMStreamConfig (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
|
|
hr = pStream->QueryInterface( IID_IWMPropertyVault, ( VOID ** )&pPropertyVault );
|
|
if( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not QI for IWMMediaProps (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check to see if this stream is a VBR stream
|
|
//
|
|
dwAttrSize = sizeof( m_pfVBRStream[i] );
|
|
hr = pPropertyVault->GetPropertyByName( g_wszVBREnabled, &enumAttrType, (BYTE *)&m_pfVBRStream[ i ], &dwAttrSize );
|
|
if( FAILED( hr ) )
|
|
{
|
|
m_pfVBRStream[ i ] = FALSE;
|
|
hr = S_OK;
|
|
}
|
|
|
|
//
|
|
// Get the memory required for WM_MEDIA_TYPE of this stream
|
|
//
|
|
hr = pProps->GetMediaType( NULL, &cbType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not Get Media Type (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
|
|
m_ptrMediaArray[i] = (WM_MEDIA_TYPE*) new BYTE[ cbType ];
|
|
|
|
if( m_ptrMediaArray[i] == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_tprintf( _T( "Internal Error: Out of memory\n" ) );
|
|
break;
|
|
}
|
|
|
|
hr = pProps->GetMediaType( m_ptrMediaArray[i], &cbType );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not Get Media Type (hr=0x%08x).\n" ), hr );
|
|
break;
|
|
}
|
|
|
|
SAFE_RELEASE( pStream );
|
|
SAFE_RELEASE( pPropertyVault );
|
|
SAFE_RELEASE( pProps );
|
|
cbType = 0;
|
|
}
|
|
|
|
SAFE_RELEASE( pProps );
|
|
SAFE_RELEASE( pStream );
|
|
SAFE_RELEASE( pPropertyVault );
|
|
|
|
return( hr );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CStreamData::SetAllStreamsBufferWindow()
|
|
// Desc: Sets the buffer window for each stream in the profile to the value
|
|
// stored in m_ptrStreamBufferWindow[].
|
|
//------------------------------------------------------------------------------
|
|
HRESULT CStreamData::SetAllStreamsBufferWindow( IWMProfile * pProfile )
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
IWMStreamConfig * pStream = NULL;
|
|
|
|
if( NULL == pProfile )
|
|
{
|
|
return( E_INVALIDARG );
|
|
}
|
|
|
|
for( DWORD i = 0; i < m_dwStreamCount; i++ )
|
|
{
|
|
|
|
if( 0 != m_ptrStreamNumArray[i] )
|
|
{
|
|
hr = pProfile->GetStreamByNumber( m_ptrStreamNumArray[i], &pStream );
|
|
if( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not get Stream %d from IWMProfile (hr=0x%08x).\n" ), m_ptrStreamNumArray[i], hr );
|
|
break;
|
|
}
|
|
|
|
hr = pStream->SetBufferWindow( m_ptrStreamBufferWindow[ i ] );
|
|
if( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not set Buffer Window for Stream %d (hr=0x%08x).\n" ), m_ptrStreamNumArray[i], hr );
|
|
break;
|
|
}
|
|
|
|
hr = pProfile->ReconfigStream( pStream );
|
|
if( FAILED( hr ) )
|
|
{
|
|
_tprintf( _T( "Could not reconfig stream %d (hr=0x%08x).\n" ), m_ptrStreamNumArray[i], hr );
|
|
break;
|
|
}
|
|
|
|
SAFE_RELEASE( pStream );
|
|
}
|
|
}
|
|
|
|
SAFE_RELEASE( pStream );
|
|
|
|
return( hr );
|
|
}
|
|
|
|
//
|
|
// Map the stream numbers of this instance of the class
|
|
// with that of another instance given by the calling function.
|
|
// The mapped stream numbers are filled up in an array of DWORDs.
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
// Name: CStreamData::MapStreamNums()
|
|
// Desc: Maps the stream numbers of this instance of the class with those of
|
|
// another instance given by the calling function.
|
|
//------------------------------------------------------------------------------
|
|
BOOL CStreamData::MapStreamNums( CStreamData& data2, WORD ** ptrNumMap )
|
|
{
|
|
if( NULL == ptrNumMap || NULL == m_ptrMediaArray || NULL == data2.m_ptrMediaArray )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
WORD wNum = 0;
|
|
//
|
|
// Allot memory for 2 * m_dwStreamCount number of WORDs.
|
|
// The first half of the WORDs will be the stream number for first profile.
|
|
// The second half of the WORDs will be the corresponding stream numbers
|
|
// from the second profile. Corresponding streams of both the halves
|
|
// will be of the same type.
|
|
//
|
|
(*ptrNumMap) = new WORD[2 * m_dwStreamCount];
|
|
if( NULL == (*ptrNumMap) )
|
|
{
|
|
_tprintf( _T( "Internal Error: Out of memory\n" ) );
|
|
return( FALSE );
|
|
}
|
|
|
|
ZeroMemory( (*ptrNumMap), 2 * m_dwStreamCount * sizeof( WORD ) );
|
|
|
|
for( WORD i = 0; i < m_dwStreamCount; i++ )
|
|
{
|
|
(*ptrNumMap)[i] = m_ptrStreamNumArray[i];
|
|
//
|
|
// Get the same media in the second profile
|
|
//
|
|
|
|
DWORD dwBufferWindow = 0;
|
|
|
|
wNum = GetSameMediaType( *ptrNumMap, m_ptrMediaArray[i], m_pfVBRStream[i],
|
|
data2, &dwBufferWindow );
|
|
if( wNum == (WORD) -1 )
|
|
{
|
|
_tprintf( _T( "Mismatch in Media types of both the Streams.\n" ) );
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// We will be concatenating the contents of two different ASF files.
|
|
// Each was encoded so that the stream data falls within the bitrate
|
|
// and buffer window specified for that stream in that file.
|
|
// However, concatenated together, Stream N of File 1 and Stream N of File 2
|
|
// may no longer stay within the bitrate/buffer window specified for that stream
|
|
// (since the resultant stream might require extra buffer window
|
|
// around the juncture point). To be safe, we increase the buffer window size
|
|
// to be the sum of the buffer window size in the two files.
|
|
// While this might be excessive, it does ensure that the output file will stay
|
|
// within the bitrate/buffer window numbers specified in its profile.
|
|
//
|
|
// The following assumes that this CStreamData will be used to set up the
|
|
// writer's profile. Let's store the sum of the buffer window values of matching streams
|
|
// from input profiles here.
|
|
//
|
|
m_ptrStreamBufferWindow[ i ] += dwBufferWindow;
|
|
(*ptrNumMap)[i + m_dwStreamCount] = wNum;
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CStreamData::GetSameMediaType()
|
|
// Desc: Finds the buffer window for a stream of the specified media type.
|
|
//------------------------------------------------------------------------------
|
|
WORD CStreamData::GetSameMediaType( WORD * ptrNumMap,
|
|
WM_MEDIA_TYPE * pMediaToFind,
|
|
BOOL fVBR,
|
|
CStreamData& data2,
|
|
DWORD * pdwBufferWindow )
|
|
{
|
|
if( NULL == ptrNumMap || NULL == pMediaToFind || NULL == pdwBufferWindow )
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
DWORD dwCount = m_dwStreamCount * 2;
|
|
for( DWORD i =0; i < m_dwStreamCount; i++ )
|
|
{
|
|
if( fVBR == m_pfVBRStream[i]
|
|
&& CompareMediaTypes( pMediaToFind, data2.m_ptrMediaArray[i], fVBR ) )
|
|
{
|
|
//
|
|
// Skip stream if already chosen
|
|
//
|
|
DWORD j;
|
|
for( j = m_dwStreamCount; j < dwCount; j++ )
|
|
{
|
|
if( ptrNumMap[j] == data2.m_ptrStreamNumArray[i] )
|
|
break;
|
|
}
|
|
if( j == dwCount )
|
|
{
|
|
*pdwBufferWindow = data2.m_ptrStreamBufferWindow[i];
|
|
return( data2.m_ptrStreamNumArray[i] );
|
|
}
|
|
}
|
|
}
|
|
return( -1 );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name: CStreamData::CompareMediaTypes()
|
|
// Desc: Returns TRUE if two media types are identical.
|
|
//------------------------------------------------------------------------------
|
|
BOOL CStreamData::CompareMediaTypes(WM_MEDIA_TYPE * pMedia1,
|
|
WM_MEDIA_TYPE * pMedia2,
|
|
BOOL fVBR )
|
|
{
|
|
if( pMedia1->majortype != pMedia2->majortype )
|
|
return( FALSE );
|
|
|
|
if( pMedia1->subtype != pMedia2->subtype )
|
|
return( FALSE );
|
|
|
|
if( pMedia1->bFixedSizeSamples != pMedia2->bFixedSizeSamples )
|
|
return( FALSE );
|
|
|
|
if( pMedia1->bTemporalCompression != pMedia2->bTemporalCompression )
|
|
return( FALSE );
|
|
|
|
if( pMedia1->lSampleSize != pMedia2->lSampleSize )
|
|
return( FALSE );
|
|
|
|
if( pMedia1->formattype != pMedia2->formattype )
|
|
return( FALSE );
|
|
|
|
if( pMedia1->cbFormat != pMedia2->cbFormat )
|
|
return( FALSE );
|
|
|
|
if ( fVBR )
|
|
{
|
|
//
|
|
// VBR streams may have different average bitrate even if they're created
|
|
// using the same profile. We should ignore this difference.
|
|
//
|
|
if ( pMedia1->formattype == WMFORMAT_VideoInfo )
|
|
{
|
|
WMVIDEOINFOHEADER * pVideoFormat1 = (WMVIDEOINFOHEADER *)pMedia1->pbFormat;
|
|
WMVIDEOINFOHEADER * pVideoFormat2 = (WMVIDEOINFOHEADER *)pMedia2->pbFormat;
|
|
|
|
pVideoFormat1->dwBitRate = 0;
|
|
pVideoFormat2->dwBitRate = 0;
|
|
}
|
|
else if ( pMedia1->formattype == WMFORMAT_WaveFormatEx )
|
|
{
|
|
WAVEFORMATEX * pWaveFormat1 = (WAVEFORMATEX *)pMedia1->pbFormat;
|
|
WAVEFORMATEX * pWaveFormat2 = (WAVEFORMATEX *)pMedia2->pbFormat;
|
|
|
|
pWaveFormat1->nAvgBytesPerSec = 0;
|
|
pWaveFormat2->nAvgBytesPerSec = 0;
|
|
}
|
|
}
|
|
|
|
if( 0 != memcmp( pMedia1->pbFormat, pMedia2->pbFormat, pMedia1->cbFormat ) )
|
|
return( FALSE );
|
|
|
|
return( TRUE );
|
|
}
|