// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // File: AppStream.cpp // // Desc: DirectShow sample code - implementation of CAppStream class. //------------------------------------------------------------------------------ #include #include #include #include #include "uuids.h" #include "dmo.h" #include "wave.h" #include "appstream.h" #include "dxutil.h" //to use free memory macro // // CAppStream - reads data from a WAV file, transforms it using a DMO and then // copies the results into an output buffer. // //----------------------------------------------------------------------------- // Name: CAppStream::CAppStream() // Desc: Constructor //----------------------------------------------------------------------------- CAppStream::CAppStream(): m_pObject(NULL), m_pObjectInPlace(NULL), m_pbInData(NULL), m_pwfx(NULL), m_uDataSize(0) { ZeroMemory(&m_mt, sizeof(m_mt)); } //----------------------------------------------------------------------------- // Name: CAppStream::~CAppStream() // Desc: Destructor //----------------------------------------------------------------------------- CAppStream::~CAppStream() { SAFE_RELEASE( m_pObject); SAFE_RELEASE( m_pObjectInPlace); SafeGlobalFree(m_pbInData); } //----------------------------------------------------------------------------- // Name: CAppStream::StreamData() // Desc: Load data from input file, create media object and set input&output type //----------------------------------------------------------------------------- HRESULT CAppStream::StreamData( LPTSTR lpszInputFile, REFGUID rclsid, HWND hDlg, BYTE **ppbOutData, ULONG *pbDataSize, LPWAVEFORMATEX *ppwfx ) { HRESULT hr; hr = Init( lpszInputFile, rclsid, hDlg ); if ( FAILED( hr ) ) { return hr; } hr = Stream( ppbOutData, pbDataSize, ppwfx ); if ( FAILED( hr )) { MessageBox( hDlg, TEXT("Streaming data failed."), TEXT(DEMO_NAME), MB_OK | MB_ICONERROR ); return hr; } return S_OK; } //----------------------------------------------------------------------------- // Name: CAppStream::Init() // Desc: Load data from input file, create media object and set input&output type //----------------------------------------------------------------------------- HRESULT CAppStream::Init(LPTSTR lpszInputFile, REFGUID rclsid, HWND hDlg) { // create DMO HRESULT hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC, IID_IMediaObject, (void **) &m_pObject); if ( FAILED( hr ) ){ MessageBox( hDlg, TEXT("Can't create this DMO."), TEXT(DEMO_NAME),MB_OK|MB_ICONERROR ); return hr; } hr = m_pObject->QueryInterface(IID_IMediaObjectInPlace, (void**)&m_pObjectInPlace); // read wave file if( WaveLoadFile( lpszInputFile, (UINT*) &m_uDataSize, &m_pwfx, &m_pbInData ) != 0 ){ MessageBox( hDlg, TEXT("Can't load input file."), TEXT(DEMO_NAME),MB_OK|MB_ICONERROR ); return E_FAIL; } if( m_pwfx->wFormatTag != WAVE_FORMAT_PCM ) { MessageBox( hDlg, TEXT("Can't process compressed data."), TEXT(DEMO_NAME),MB_OK|MB_ICONERROR ); return E_FAIL; } m_mt.majortype = MEDIATYPE_Audio; m_mt.subtype = MEDIASUBTYPE_PCM; m_mt.formattype = FORMAT_WaveFormatEx; m_mt.cbFormat = sizeof(WAVEFORMATEX); m_mt.pbFormat = (BYTE*) (m_pwfx); m_mt.pUnk = NULL; // CopyMediaType will crash if we don't intialize this hr = m_pObject->SetInputType( 0, //Input Stream index &m_mt, 0 ); // No flags specified if ( FAILED( hr ) ){ MessageBox( hDlg, TEXT("Can't set input type."), TEXT(DEMO_NAME),MB_OK | MB_ICONERROR ); return hr; } hr = m_pObject->SetOutputType( 0, // Output Stream Index &m_mt, 0); // No flags specified if ( FAILED( hr ) ){ MessageBox( hDlg, TEXT("Can't set output type."), TEXT(DEMO_NAME),MB_OK | MB_ICONERROR ); return hr; } return S_OK; } //----------------------------------------------------------------------------- // Name: CAppStream::Stream() // Desc: called to get the output from DMO //----------------------------------------------------------------------------- HRESULT CAppStream::Stream( BYTE **ppbOutData, ULONG *pbDataSize, LPWAVEFORMATEX *ppwfx ) { HRESULT hr = S_OK; BYTE *pOut; *pbDataSize = m_uDataSize; *ppwfx = m_pwfx; if ( m_pObjectInPlace ){ pOut = new BYTE [m_uDataSize]; if( pOut == 0 ){ return E_OUTOFMEMORY; } CopyMemory(pOut, m_pbInData, m_uDataSize); // pass the number of samples to Process() hr = m_pObjectInPlace->Process( m_uDataSize, pOut, 0, DMO_INPLACE_NORMAL); if( FAILED( hr ) ){ return hr; } *ppbOutData = pOut; SAFE_RELEASE( m_pObjectInPlace ); } else { CMediaBuffer *pInputBuffer; const REFERENCE_TIME rtStart = 0; const REFERENCE_TIME rtStop = 0; BYTE* pBuffer; DWORD dwLength; // create and fill CMediaBuffer hr = CreateBuffer(m_uDataSize, &pInputBuffer); if( FAILED( hr ) ){ return hr; } hr = pInputBuffer->GetBufferAndLength( &pBuffer, &dwLength ); if( FAILED( hr ) ){ return hr; } CopyMemory(pBuffer, m_pbInData, m_uDataSize); hr = pInputBuffer->SetLength( m_uDataSize ); if( FAILED( hr ) ){ return hr; } // call processInput hr = m_pObject->ProcessInput( 0, pInputBuffer, DMO_INPUT_DATA_BUFFERF_SYNCPOINT, rtStart, rtStop - rtStart); if( FAILED( hr ) ){ return hr; } //release input buffer SAFE_RELEASE( pInputBuffer ); // retrieve the output data from DMO and put into pOut if(S_FALSE == hr){ return E_FAIL; } else { pOut = NULL; hr = ProcessOutputs( &pOut ); if( FAILED( hr ) ){ delete [] pOut; return hr; } } *ppbOutData = pOut; SAFE_RELEASE( m_pObject ); } return S_OK; } //----------------------------------------------------------------------------- // Name: CAppStream::ProcessOutputs() // Desc: retrieve the output data from DMO //----------------------------------------------------------------------------- HRESULT CAppStream::ProcessOutputs( BYTE **ppbOutData ) { HRESULT hr = S_OK; DWORD dwStatus=0; ULONG ulSize=0; BYTE *pOut=0; CMediaBuffer *pOutputBuffer; DMO_OUTPUT_DATA_BUFFER dataBufferStruct; hr = CreateBuffer( m_uDataSize,&pOutputBuffer ); if ( FAILED( hr ) ) { return hr; } dataBufferStruct.pBuffer = pOutputBuffer; dataBufferStruct.dwStatus = 0; // No flag is set dataBufferStruct.rtTimestamp = 0; // not used in ProcessOutput() dataBufferStruct.rtTimelength = 0; // not used in ProcessOutput() *ppbOutData = new BYTE[m_uDataSize]; if( *ppbOutData == 0 ){ return E_OUTOFMEMORY; } //process until no more data if (SUCCEEDED(hr)) do { hr = m_pObject->ProcessOutput( DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER, 1, //output buffer count &dataBufferStruct, &dwStatus ); if ( FAILED( hr ) ) { return hr; } if( SUCCEEDED(hr) && (hr != S_FALSE) ) { hr = dataBufferStruct.pBuffer->GetBufferAndLength(&pOut, &ulSize); if ( FAILED( hr ) ) { return hr; } CopyMemory(*ppbOutData, pOut, m_uDataSize); hr = dataBufferStruct.pBuffer->SetLength( 0 ); if( FAILED( hr ) ) { break; } } } while ( dataBufferStruct.dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE ); // free output buffer allocated: SAFE_RELEASE( pOutputBuffer ); // Send Discontinuity on output stream hr = m_pObject->Discontinuity( 0 ); if ( FAILED( hr ) ) { return hr; } return hr; } //----------------------------------------------------------------------------- // Name: CreateBuffer() // Desc: create a CMediaBuffer //----------------------------------------------------------------------------- HRESULT CreateBuffer(DWORD cbMaxLength, CMediaBuffer **ppBuffer) { CMediaBuffer *pBuffer = new CMediaBuffer( cbMaxLength ); if ( pBuffer == NULL || FAILED( pBuffer->Init() ) ) { delete pBuffer; *ppBuffer = NULL; return E_OUTOFMEMORY; } *ppBuffer = pBuffer; (*ppBuffer)->AddRef(); return S_OK; }