DirectShow filter development-read audio file filter

Download the DLL produced by the code in this article
This filter parses and reads the audio file, decodes the audio into an uncompressed PCM audio stream and outputs it on the output pin. The audio file formats that can be parsed are: aac, m4a, m4r, mp3, wav, wma.

Filter parameter information

Filter name: Read audio files
Filter GUID: {9EA694F1-8B08-428D-9718-A353932B7995}
DLL registration function name: DllRegisterServer
Delete registered function name: DllUnregisterServer
The filter has 1 output pin.
Output pin designation: 1
Output pin media type:
Main type: MEDIATYPE_Audio
Subtype: MEDIASUBTYPE_PCM
Format type: FORMAT_WaveFormatEx

Filter development process

The filter is derived from CSource and implements the IFileSourceFilter and IMediaSeeking interfaces. The IFileSourceFilter interface is used to specify the audio file to be read. In the Load method of IFileSourceFilter, a thread is created, and a source reader is created in the thread to obtain all information about the media type when the specified media type is PCM audio. The IMediaSeeking interface is used to adjust the current position of playback.

Pins are derived from CSourceStream.
Rewritten the ThreadProc function, which is the thread function of the pin. A second source reader is created in the function, and the media type of the source reader audio stream is specified as the media type obtained in the Load method of IFileSourceFilter. When the specified media type succeeds, the source reader will instantiate the decoder. A BOOL variable B_Pasue is declared in the pin class. When a run, stop, or pause request is received, the value of B_Pasue is set. The other code of the ThreadProc function is copied from the CSourceStream::ThreadProc definition.
The DoBufferProcessingLoop function has been rewritten, and the sending code using the B_Pasue variable to control the sample has been added to the function.
The FillBuffer function has been rewritten. In the function, read the sample from the source reader, including the display time, duration, valid data length, and sample data of the sample; use these parameters to fill the pin sample buffer and specify each parameter of the pin sample.
The GetMediaType function has been rewritten to specify the media type of the pin.
Overridden DecideBufferSize function, used to determine the size of the pin sample buffer.

The following is the entire code of this filter DLL

DLL module definition file: AudioReader.def

LIBRARY AudioReader.dll
EXPORTS
            DllMain PRIVATE
            DllGetClassObject PRIVATE
            DllCanUnloadNow PRIVATE
            DllRegisterServer PRIVATE
            DllUnregisterServer PRIVATE

DLL header file: AudioReader.h

#ifndef DLL_FILE
#define DLL_FILE

#include "streams.h"
#include "initguid.h"

#if _DEBUG
#pragma comment(lib, "Strmbasd.lib")//C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses\Debug\ \strmbasd.lib
#else
#pragma comment(lib, "Strmbase.lib")//C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses\Release\ \strmbase.lib
#endif
#pragma comment(lib, "Winmm.lib")//C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib\Winmm.lib
#pragma comment(lib, "msvcrt.lib")//C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\msvcrt.lib

#include "strsafe.h"
#include "mfapi.h"
#include "mfidl.h"
#include "mfreadwrite.h"
#include "mferror.h"
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")

template <class T> void SafeRelease(T** ppT)
{<!-- -->
if (*ppT)
{<!-- -->
(*ppT)->Release();
*ppT = NULL;
}
}

// {9EA694F1-8B08-428D-9718-A353932B7995}
DEFINE_GUID(CLSID_AudioReader,
0x9ea694f1, 0x8b08, 0x428d, 0x97, 0x18, 0xa3, 0x53, 0x93, 0x2b, 0x79, 0x95);

#endif // DLL_FILE

DLL source file: AudioReader.cpp

#include "AudioReader.h"
#include "CFilter.h"


const AMOVIESETUP_MEDIATYPE PinTypes =
{<!-- -->
     & amp;MEDIATYPE_Audio, // Main type
     & amp;MEDIASUBTYPE_PCM // Subtype
};

const AMOVIESETUP_PIN PinInfo = // Pin information
{<!-- -->
L"Out", //Pin name
FALSE, //Input pins must be rendered
TRUE, //output pin
FALSE, //Have zero instances of this pin
FALSE, //Can create more than one instance of pin
& amp;CLSID_NULL, //Class ID of the filter connected to this pin
NULL, //The name of the pin connected to this pin
1, //The number of media types supported by the pin
& amp;PinTypes //Media type information
};

const AMOVIESETUP_FILTER FilterInfo = //Filter registration information
{<!-- -->
     & amp;CLSID_AudioReader, //Filter class identifier
    L"Read audio file", //The name of the filter
    MERIT_DO_NOT_USE, //Filter priority value
    1, //Number of pins
     & amp;PinInfo //Pin information
};

CFactoryTemplate g_Templates [] = {<!-- -->
    {<!-- -->
L"Read audio file"
      , &CLSID_AudioReader
      , CFilter::CreateInstance
      , NULL
      , &FilterInfo
}
};

int g_cTemplates = 1;

STDAPI DllRegisterServer()//Register DLL
{<!-- -->
    return AMovieDllRegisterServer2(TRUE);
}

STDAPI DllUnregisterServer()//Delete DLL registration
{<!-- -->
    return AMovieDllRegisterServer2(FALSE);
}

extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{<!-- -->
    return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}

Filter header file: CFilter.h

#ifndef FILTER_FILE
#define FILTER_FILE

#include "AudioReader.h"
#include "CPin.h"

class CFilter : public CSource, public IFileSourceFilter, public IMediaSeeking
{<!-- -->
friend class CPin;
public:
CFilter(LPUNKNOWN pUnk,HRESULT *phr);
~CFilter();
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
DECLARE_IUNKNOWN
    STDMETHODIMP Load(LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt);
STDMETHODIMP GetCurFile(LPOLESTR * ppszFileName, AM_MEDIA_TYPE *pmt);
CPin* pCAudioOut;//Audio pin pointer
LPWSTR m_pFileName; //Audio file path to be read
HANDLE hInit;//"Get information completed" event handle
HANDLE hAReset;//"Audio change playback position" event handle
IMFMediaType* pUncompressedAudioType;
LONGLONG CUR; //Current audio time, 100 nanosecond unit
LONGLONG DUR;//Audio duration, 100 nanosecond unit
LONGLONG AResetPos;//New audio position, 100 nanosecond unit
private:
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
public:
HRESULT STDMETHODCALLTYPE CheckCapabilities(DWORD *pCapabilities);
HRESULT STDMETHODCALLTYPE ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat);
HRESULT STDMETHODCALLTYPE GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest);
HRESULT STDMETHODCALLTYPE GetCapabilities(DWORD *pCapabilities);
HRESULT STDMETHODCALLTYPE GetCurrentPosition(LONGLONG *pCurrent);
HRESULT STDMETHODCALLTYPE GetDuration(LONGLONG *pDuration);
HRESULT STDMETHODCALLTYPE GetPositions(LONGLONG *pCurrent, LONGLONG *pStop);
HRESULT STDMETHODCALLTYPE GetPreroll(LONGLONG *pllPreroll);
HRESULT STDMETHODCALLTYPE GetRate(double *pdRate);
HRESULT STDMETHODCALLTYPE GetStopPosition(LONGLONG *pStop);
HRESULT STDMETHODCALLTYPE GetTimeFormat(GUID *pFormat);
HRESULT STDMETHODCALLTYPE IsFormatSupported(const GUID *pFormat);
HRESULT STDMETHODCALLTYPE IsUsingTimeFormat(const GUID *pFormat);
HRESULT STDMETHODCALLTYPE QueryPreferredFormat(GUID *pFormat);
HRESULT STDMETHODCALLTYPE SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags);
HRESULT STDMETHODCALLTYPE SetRate(double dRate);
HRESULT STDMETHODCALLTYPE SetTimeFormat(const GUID *pFormat);
};

#endif // FILTER_FILE

Filter source file: CFilter.cpp

#include "CFilter.h"
#include "CPin.h"

CFilter::CFilter(LPUNKNOWN lpunk, HRESULT *phr) : CSource(NAME("Read audio file"), lpunk, CLSID_AudioReader)
{<!-- -->
m_paStreams = new CSourceStream*[1];
pCAudioOut=new CPin(phr, this, L"Out");//Create audio pin
m_paStreams[0]=(CSourceStream*)pCAudioOut;
pUncompressedAudioType = NULL;
DUR=0;//Audio duration, 100 nanosecond unit
AResetPos=0;
hInit = CreateEvent(NULL, TRUE, FALSE, NULL); //Create event, manual reset, no signal in the initial state
hAReset = CreateEvent(NULL, FALSE, FALSE, NULL); //Create event, automatically reset, no signal in the initial state
}

CFilter::~CFilter()
{<!-- -->
CloseHandle(hInit);CloseHandle(hAReset);
SafeRelease( & amp;pUncompressedAudioType);
}

STDMETHODIMP CFilter::NonDelegatingQueryInterface(REFIID iid, void ** ppv)
{<!-- -->
if(iid==IID_IMediaSeeking)
{<!-- -->
return GetInterface(static_cast<IMediaSeeking*>(this), ppv);
}
else if(iid==IID_IFileSourceFilter)
{<!-- -->
return GetInterface(static_cast<IFileSourceFilter*>(this), ppv);
}
else
return CBaseFilter::NonDelegatingQueryInterface(iid, ppv);
}

CUnknown * WINAPI CFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
{<!-- -->
    return new CFilter(pUnk, phr);//Create filter
}

DWORD WINAPI GetInfoThread(LPVOID pParam);//"Read audio parameters" thread function declaration

STDMETHODIMP CFilter::Load(LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt)
{<!-- -->
    CheckPointer(lpwszFileName,E_POINTER);
    if(wcslen(lpwszFileName) > MAX_PATH || wcslen(lpwszFileName)<4)
        return ERROR_FILENAME_EXCED_RANGE;

    size_t len = 1 + lstrlenW(lpwszFileName);
WCHAR* pWch=new WCHAR[len];
    m_pFileName = (LPWSTR)pWch;
    if (m_pFileName == NULL)return E_OUTOFMEMORY;
    HRESULT hr = StringCchCopyW(m_pFileName, len, lpwszFileName);

wchar_t ExName[5]={<!-- -->m_pFileName[len-5],m_pFileName[len-4],m_pFileName[len-3],m_pFileName[len-2],0};
if(wcscmp(ExName,L".aac") != 0 & amp; & amp; wcscmp(ExName,L".m4a") != 0 & amp; & amp; wcscmp(ExName,L\ ".m4r") != 0
& amp; & amp; wcscmp(ExName,L".mp3") != 0 & amp; & amp; wcscmp(ExName,L".wav") != 0 & amp; & amp; wcscmp( ExName,L".wma") != 0)//If it is not the specified audio file
{<!-- -->
delete[] pWch; m_pFileName=NULL;
return VFW_E_INVALID_FILE_FORMAT;//Failed to set file name
}
ResetEvent(hInit);//Set "Acquisition of information completed" no signal
CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)GetInfoThread,this,0,NULL);//Create a "read audio parameter" thread
    return S_OK;
}

STDMETHODIMP CFilter::GetCurFile(LPOLESTR * ppszFileName, AM_MEDIA_TYPE *pmt)
{<!-- -->
CheckPointer(ppszFileName, E_POINTER);
*ppszFileName = NULL;
if (m_pFileName !=NULL)
{<!-- -->
DWORD n = sizeof(WCHAR)*(1 + lstrlenW(m_pFileName));
*ppszFileName = (LPOLESTR)CoTaskMemAlloc(n);
if (*ppszFileName!=NULL)CopyMemory(*ppszFileName, m_pFileName, n);
}
return S_OK;
}

DWORD WINAPI GetInfoThread(LPVOID pParam)//"Read audio parameters" thread
{<!-- -->
CFilter* pCFilter=(CFilter*)pParam;//The parameter is the filter pointer
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (hr != S_OK)
{<!-- -->
MessageBox(NULL,L"Failed to initialize COM library",NULL,MB_OK);
return 0;
}
    hr = MFStartup(MF_VERSION);
    if (hr != S_OK)
{<!-- -->
MessageBox(NULL,L"Failed to initialize media base",NULL,MB_OK);
CoUninitialize();//Close the COM library
return 0;
}
IMFSourceReader* pReader = NULL;
hr = MFCreateSourceReaderFromURL(pCFilter->m_pFileName, NULL, & amp;pReader);
if (hr != S_OK)
{<!-- -->
MessageBox(NULL,L"Failed to create source reader",NULL,MB_OK);
MFShutdown();//Close the media base
CoUninitialize();//Close the COM library
return 0;
}
IMFMediaType* pPartialType = NULL;
if (SUCCEEDED(hr))
{<!-- -->
hr = MFCreateMediaType( & amp;pPartialType);//Create an empty media type
}
if (SUCCEEDED(hr))
{<!-- -->
hr = pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);//Set the main type of audio
}
if (SUCCEEDED(hr))
{<!-- -->
hr = pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);//Set subtype PCM
}
if (SUCCEEDED(hr))
{<!-- -->
hr = pReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,NULL, pPartialType);//Set this media type on the source reader
}
SafeRelease( & amp;pCFilter->pUncompressedAudioType);
if (SUCCEEDED(hr))
{<!-- -->
hr = pReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, & amp;pCFilter->pUncompressedAudioType);//Get the complete audio media type
}
PROPVARIANT var;
if (SUCCEEDED(hr))
{<!-- -->
PropVariantInit( & amp;var);
hr=pReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, & var);//Get the audio time length, 100 nanosecond unit
}
    if (SUCCEEDED(hr))
    {<!-- -->
pCFilter->DUR=(LONGLONG)var.uhVal.QuadPart;
PropVariantClear( & amp;var);
    }

SafeRelease( & amp;pReader);SafeRelease( & amp;pPartialType);
MFShutdown();//Close the media base
CoUninitialize();//Close the COM library
if (hr!=S_OK)
{<!-- -->
MessageBox(0,L"Failed to obtain information",0,MB_OK);return 0;
}
SetEvent(pCFilter->hInit);//Send the "information acquisition completed" signal
return 1;
}

HRESULT STDMETHODCALLTYPE CFilter::CheckCapabilities(DWORD *pCapabilities)//Check whether it has the specified search function
{<!-- -->
if(pCapabilities==NULL)return E_POINTER;
if(*pCapabilities == (AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetDuration))
return S_OK;
else if(*pCapabilities & amp; AM_SEEKING_CanSeekAbsolute) //The absolute position can be found
{<!-- -->
return S_FALSE;
}
else if(*pCapabilities & amp; AM_SEEKING_CanGetDuration)//You can get the duration
{<!-- -->
return S_FALSE;
}
else return E_FAIL;
}

HRESULT STDMETHODCALLTYPE CFilter::ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
{<!-- -->
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE CFilter::GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest)
{<!-- -->
return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE CFilter::GetCapabilities(DWORD *pCapabilities)
{<!-- -->
*pCapabilities=AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetDuration;
return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetCurrentPosition(LONGLONG *pCurrent)
{<!-- -->
*pCurrent=CUR;return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetDuration(LONGLONG *pDuration)
{<!-- -->
DWORD dw=WaitForSingleObject(hInit,0);
if(dw!=WAIT_OBJECT_0)return E_NOTIMPL;
*pDuration=DUR;
return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetPositions(LONGLONG *pCurrent, LONGLONG *pStop)
{<!-- -->
DWORD dw=WaitForSingleObject(hInit,0);
if(dw==WAIT_OBJECT_0)
{<!-- -->
*pCurrent=CUR;return S_OK;
}
else return S_FALSE;
}

HRESULT STDMETHODCALLTYPE CFilter::GetPreroll(LONGLONG *pllPreroll)
{<!-- -->
*pllPreroll=0;
return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetRate(double *pdRate)
{<!-- -->
*pdRate=1.0;return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetStopPosition(LONGLONG *pStop)
{<!-- -->
*pStop=DUR-AResetPos;
return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetTimeFormat(GUID *pFormat)
{<!-- -->
if(pFormat==NULL)return E_POINTER;
*pFormat=TIME_FORMAT_MEDIA_TIME;return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::IsFormatSupported(const GUID *pFormat)
{<!-- -->
if(TIME_FORMAT_MEDIA_TIME==*pFormat)return S_OK;
else return S_FALSE;
}

HRESULT STDMETHODCALLTYPE CFilter::IsUsingTimeFormat(const GUID *pFormat)
{<!-- -->
if(*pFormat==TIME_FORMAT_MEDIA_TIME)return S_OK;
else return S_FALSE;
}

HRESULT STDMETHODCALLTYPE CFilter::QueryPreferredFormat(GUID *pFormat)
{<!-- -->
if(pFormat==NULL)return E_POINTER;
*pFormat=TIME_FORMAT_MEDIA_TIME;return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
{<!-- -->
DWORD dw=WaitForSingleObject(hInit,0);
if((dw==WAIT_OBJECT_0) & amp; & amp; (dwCurrentFlags & amp; AM_SEEKING_AbsolutePositioning))
{<!-- -->
AResetPos=*pCurrent;*pStop=DUR-*pCurrent;
SetEvent(hAReset); //Send the "audio change playback position" signal
return S_OK;
}
else
{<!-- -->
return S_FALSE;
}
}

HRESULT STDMETHODCALLTYPE CFilter::SetRate(double dRate)
{<!-- -->
if(dRate==1.0)return S_OK;
else return S_FALSE;
}

HRESULT STDMETHODCALLTYPE CFilter::SetTimeFormat(const GUID *pFormat)
{<!-- -->
if(*pFormat==TIME_FORMAT_MEDIA_TIME)return S_OK;
else return S_FALSE;
}

Pin header file: CPin.h

#ifndef PIN_FILE
#definePIN_FILE

#include "AudioReader.h"
#include "CFilter.h"

class CPin : public CSourceStream
{<!-- -->
friend class CFilter;
public:
    CPin(HRESULT *phr, CSource *pParent, LPCWSTR pPinName);
    ~CPin();
HRESULT GetMediaType(CMediaType *pmt);
HRESULT DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pRequest);//Determine the buffer size
STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
HRESULT FillBuffer(IMediaSample *pms);
HRESULT OnThreadDestroy(void);
CFilter* pCFilter;//Filter pointer
IMFSourceReader* pReader;//source reader interface
BOOL B_Pasue;//TRUE, paused state; FALSE, running or stopped state
protected:
DWORD ThreadProc(void);
HRESULT DoBufferProcessingLoop(void);
};


#endif //PIN_FILE

Pin source file: CPin.cpp

#include "CPin.h"

CPin::CPin(HRESULT *phr, CSource *pParent, LPCWSTR pPinName) : CSourceStream(NAME("Out"), phr, pParent, pPinName)
{<!-- -->
pCFilter=(CFilter*)pParent;
pReader = NULL;B_Pasue=FALSE;
}

CPin::~CPin()
{<!-- -->

}

HRESULT CPin::GetMediaType(CMediaType *pmt)
{<!-- -->
DWORD dw=WaitForSingleObject(pCFilter->hInit,2000);//Wait up to 2 seconds
if(dw!=WAIT_OBJECT_0) return E_UNEXPECTED;//If there is no "information acquisition completed" signal, an error is returned
AM_MEDIA_TYPE* pMt=NULL;
pCFilter->pUncompressedAudioType->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION,(void**) & amp;pMt);//Convert the media type represented by IMFMediaType into the AM_MEDIA_TYPE structure
pmt->Set(*pMt);
pCFilter->pUncompressedAudioType->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION,pMt);//Release the memory allocated by GetRepresentation
return S_OK;
}

HRESULT CPin::DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pRequest)
{<!-- -->
DWORD dw=WaitForSingleObject(pCFilter->hInit,2000);//Wait up to 2 seconds
if(dw!=WAIT_OBJECT_0) return E_FAIL;//If there is no "information acquisition completed" signal, the function fails
HRESULT hr;
   pRequest->cBuffers = 1;//1 buffer
    pRequest->cbBuffer = 1000000; //Buffer size 1M
    ALLOCATOR_PROPERTIES Actual;
    hr = pAlloc->SetProperties(pRequest, & amp;Actual);
    if(FAILED(hr))return hr;
    if(Actual.cbBuffer < pRequest->cbBuffer)//Is this allocator inappropriate?
    {<!-- -->
        return E_FAIL;
    }
    return NOERROR;
}

STDMETHODIMP CPin::Notify(IBaseFilter * pSender, Quality q)
{<!-- -->
return NOERROR;
}

HRESULT CPin::FillBuffer(IMediaSample *pms)
{<!-- -->
HRESULT hr;
    BYTE *pBuffer;
    pms->GetPointer( & amp;pBuffer);//Get the sample buffer pointer
    long BufferLen = pms->GetSize();//Get the sample buffer size

DWORD dw=WaitForSingleObject(pCFilter->hAReset,0);
if(dw==WAIT_OBJECT_0)//If there is an "audio change playback position" signal
{<!-- -->
hr=DeliverBeginFlush();
Sleep(1);
hr=DeliverEndFlush();
hr=DeliverNewSegment(0,pCFilter->DUR-pCFilter->AResetPos,1.0);
PROPVARIANT pv;
PropVariantInit( & amp;pv);
pv.vt=20;
pv.hVal.QuadPart=pCFilter->AResetPos;
hr=pReader->SetCurrentPosition(GUID_NULL, pv);//Change the source reader reading position
PropVariantClear( & amp;pv);
pms->SetDiscontinuity(TRUE);//Set stream interruption
}

DWORD index,flags;LONGLONG time;
IMFSample* pIMFSample=NULL;IMFMediaBuffer* pIMFMediaBuffer=NULL;
AganRead:
hr=pReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM,0, & amp;index, & amp;flags, & amp;stime, & amp;pIMFSample);//Read audio sample
if(MF_SOURCE_READERF_ENDOFSTREAM == flags)return S_FALSE;//If the end of the stream is reached, return S_FALSE
if(pIMFSample==NULL)
{<!-- -->
Sleep(1);goto AganRead;//If reading fails, read again
}
LONGLONG Cur, Dur, End;
hr=pIMFSample->GetSampleTime( & amp;Cur);//Get sample display time
pCFilter->CUR=Cur;//Get the current audio time here
hr=pIMFSample->GetSampleDuration( & amp;Dur);//Get sample duration
End=Cur + Dur;//Calculate the sample end time
Cur-=pCFilter->AResetPos;End-=pCFilter->AResetPos;//After using the IMediaSeeking interface to adjust the playback position, AResetPos may not be 0, and the timestamp value needs to be calculated.
DWORD Lt;
hr=pIMFSample->GetTotalLength( & amp;Lt);//Get the effective length of the sample
hr=pIMFSample->GetBufferByIndex(0, & amp;pIMFMediaBuffer);//Get the buffer interface
BYTE* pSB=NULL;
hr=pIMFMediaBuffer->Lock( & amp;pSB,NULL,NULL);//Lock buffer
if(Lt<=(DWORD)BufferLen)//Prevent data copying when the data length is greater than the sample buffer size
CopyMemory(pBuffer, pSB, Lt);//Copy data
pms->SetTime( & amp;Cur, & amp;End);//Set timestamp
pms->SetActualDataLength(Lt);//Set the effective data length
pms->SetSyncPoint(TRUE);//Set the sample as a synchronization point
hr=pIMFMediaBuffer->Unlock();//Unlock the buffer
SafeRelease( & amp;pIMFMediaBuffer);SafeRelease( & amp;pIMFSample);//Release interface
    return S_OK;
}

HRESULT CPin::OnThreadDestroy(void)
{<!-- -->
SafeRelease( & amp;pReader);//Release the source reader interface
MFShutdown();//Close the media base
return NOERROR;
}

DWORD CPin::ThreadProc()
{<!-- -->
WaitForSingleObject(pCFilter->hInit,INFINITE);//Waiting for the "information acquisition completed" signal
HRESULT hr;
    hr = MFStartup(MF_VERSION);
    if (hr != S_OK)
{<!-- -->
MessageBox(NULL,L"Failed to initialize media base",NULL,MB_OK);
return 1;
}
hr = MFCreateSourceReaderFromURL(pCFilter->m_pFileName, NULL, & amp;pReader);
if (hr != S_OK)
{<!-- -->
MessageBox(NULL,L"Failed to create source reader",NULL,MB_OK);
MFShutdown();//Close the media base
CoUninitialize();//Close the COM library
return 1;
}
if (SUCCEEDED(hr))
{<!-- -->
hr = pReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,NULL, pCFilter->pUncompressedAudioType);//Set this media type on the source reader
}
if(FAILED(hr))
{<!-- -->
MessageBox(NULL,L"Failed to initialize audio media type",NULL,MB_OK);return 1;
}

    Command com;
    do
{<!-- -->
com = GetRequest();
if (com != CMD_INIT)
{<!-- -->
DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command")));
Reply((DWORD) E_UNEXPECTED);
}
    } while (com != CMD_INIT);

    DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing")));

    hr = OnThreadCreate();
    if (FAILED(hr))
{<!-- -->
        DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread.")));
        OnThreadDestroy();
Reply(hr);
        return 1;
    }
    Reply(NOERROR);

B_Pasue=TRUE;

    Command cmd;
    do
{<!-- -->
cmd = GetRequest();
switch(cmd)
{<!-- -->
case CMD_EXIT:
Reply(NOERROR);
break;
case CMD_RUN:
DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE?")));
\t\t
case CMD_PAUSE:
if(B_Pasue)
{<!-- -->
B_Pasue=FALSE;
}
else
{<!-- -->
B_Pasue=TRUE;
}
Reply(NOERROR);
DoBufferProcessingLoop();
break;
case CMD_STOP:
B_Pasue=FALSE;
Reply(NOERROR);
break;
default:
DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd));
Reply((DWORD) E_NOTIMPL);
break;
}
    } while (cmd != CMD_EXIT);
    hr = OnThreadDestroy();
    if (FAILED(hr))
{<!-- -->
        DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread.")));
        return 1;
    }
    DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting")));
    return 0;
}

HRESULT CPin::DoBufferProcessingLoop(void)
{<!-- -->
    Command com;
    OnThreadStartPlay();
    do
{<!-- -->
while (!CheckRequest( & amp;com))
{<!-- -->
if(B_Pasue)
{<!-- -->
continue; //If it is in pause state, the sample buffer will not be obtained, samples will not be filled and samples will be sent.
}
IMediaSample *pSample;
HRESULT hr = GetDeliveryBuffer( & amp;pSample,NULL,NULL,0);
if (FAILED(hr))
{<!-- -->
                Sleep(1);
continue;
}
hr = FillBuffer(pSample);
if (hr == S_OK)
{<!-- -->
hr = Deliver(pSample);
                pSample->Release();
                if(hr != S_OK)
                {<!-- -->
                  DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned x; stopping"), hr));
                  return S_OK;
                }
}
else if (hr == S_FALSE)
{<!-- -->
pSample->Release();
DeliverEndOfStream();
return S_OK;
}
else
{<!-- -->
                pSample->Release();
DbgLog((LOG_ERROR, 1, TEXT("Error lX from FillBuffer!!!"), hr));
                DeliverEndOfStream();
                m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0);
                return hr;
}
}//while
if (com == CMD_RUN || com == CMD_PAUSE)
{<!-- -->
Reply(NOERROR);
}
else if (com != CMD_STOP)
{<!-- -->
Reply((DWORD) E_UNEXPECTED);
DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!")));
}
} while (com != CMD_STOP);
    return S_FALSE;
}

Download the DLL produced by the code in this article