323 lines
9.7 KiB
C++
323 lines
9.7 KiB
C++
// 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 <windows.h>
|
|
#include <mmsystem.h>
|
|
|
|
#include <malloc.h>
|
|
#include <mediaobj.h>
|
|
|
|
#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;
|
|
}
|