class CBlankAudioPin :
public CSourceStream,
public CSourceSeeking
{
friend class CBlankStreams;
REFERENCE_TIME m_rtStartTime;
REFERENCE_TIME m_rtEndTime;
WAVEFORMATEX m_wf;
DWORD m_dwBufferSize;
CCritSec m_SeekLock;
protected:
HRESULT ChangeStart( );
HRESULT ChangeStop( );
HRESULT ChangeRate( );
public:
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
return CSourceStream::QueryInterface(riid,ppv);
};
STDMETHODIMP_(ULONG) AddRef()
{
return CSourceStream::AddRef();
};
STDMETHODIMP_(ULONG) Release()
{
return CSourceStream::Release();
};
CBlankAudioPin(HRESULT* pHr, CSource* pSource);
~CBlankAudioPin();
protected:
HRESULT OnThreadCreate(void);
HRESULT OnThreadDestroy(void);
HRESULT OnThreadStartPlay(void);
protected:
HRESULT DoBufferProcessingLoop(void);
HRESULT CheckMediaType(const CMediaType *pMediaType);
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
HRESULT GetMediaType(CMediaType *pMediaType);
HRESULT FillBuffer(IMediaSample *pSample);
HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest);
STDMETHODIMP ConnectionMediaType(AM_MEDIA_TYPE*);
STDMETHODIMP NonDelegatingQueryInterface( REFIID riid, void ** ppv );
protected:
HRESULT UpdateAudioHeader();
};
class CBlankStreams:
public CSource
{
CBlankAudioPin* m_pAudioPin;
public:
CBlankStreams(HRESULT* pHr);
~CBlankStreams(void);
public:
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
public:
CBasePin *GetPin(int n)
{
if (n == 0)
return m_pAudioPin;
else if (n == 1)
return m_pVideoPin;
else
return NULL;
}
int GetPinCount(void)
{
return 2;
}
STDMETHODIMP NonDelegatingQueryInterface(const IID& riid, void** ppv);
public:
DECLARE_IUNKNOWN;
};
#define DEFAULT_DURATION 10 * UNITS
CBlankAudioPin::CBlankAudioPin(HRESULT* pHr, CSource* pSource):
CSourceStream(TEXT("Output stream"), pHr, pSource, L"Output audio stream"),
CSourceSeeking(TEXT("Output stream"), (IPin*)this, pHr, &m_SeekLock),
m_iCountFrame(0),
m_rtStartTime(0),
m_rtEndTime(0),
m_dwBufferSize(512)
{
ZeroMemory(&m_wf, sizeof(m_wf));
UpdateAudioHeader();
m_rtDuration = DEFAULT_DURATION;
m_rtStop = m_rtDuration;
// no seeking to absolute pos's and no seeking backwards!
//
m_dwSeekingCaps = AM_SEEKING_CanSeekForwards | AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration | AM_SEEKING_CanSeekAbsolute;
}
CBlankAudioPin::~CBlankAudioPin()
{
}
STDMETHODIMP CBlankAudioPin::Notify(IBaseFilter* pFilter, Quality q)
{
return S_OK;
}
HRESULT CBlankAudioPin::ChangeRate()
{
return NOERROR;
}
HRESULT CBlankAudioPin::ChangeStop()
{
return NOERROR;
}
HRESULT CBlankAudioPin::ChangeStart()
{
m_iCountFrame = 0;
if (ThreadExists())
{
// next time round the loop the worker thread will
// pick up the position change.
// We need to flush all the existing data - we must do that here
// as our thread will probably be blocked in GetBuffer otherwise
DeliverBeginFlush();
// make sure we have stopped pushing
Stop();
// complete the flush
DeliverEndFlush();
// restart
Run();
}
return NOERROR;
}
HRESULT CBlankAudioPin::UpdateAudioHeader()
{
m_wf.cbSize = 0;//sizeof(WAVEFORMATEX);
m_wf.nChannels = 2;
m_wf.wBitsPerSample = 16;
m_wf.nBlockAlign = (m_wf.nChannels*m_wf.wBitsPerSample)/8;
m_wf.wFormatTag = WAVE_FORMAT_PCM;
m_wf.nSamplesPerSec = 44100;
m_wf.nAvgBytesPerSec = (m_wf.nChannels*m_wf.nSamplesPerSec*m_wf.wBitsPerSample)/8;
return S_OK;
}
HRESULT CBlankAudioPin::OnThreadCreate(void)
{
return CSourceStream::OnThreadCreate();
}
HRESULT CBlankAudioPin::OnThreadDestroy(void)
{
return CSourceStream::OnThreadDestroy();
}
HRESULT CBlankAudioPin::OnThreadStartPlay(void)
{
DeliverNewSegment( m_rtStartTime, m_rtEndTime, 1.0 );
return CSourceStream::OnThreadStartPlay();
}
HRESULT CBlankAudioPin::DoBufferProcessingLoop(void)
{
m_iCountFrame = 0;
m_rtEndTime = 0;
return CSourceStream::DoBufferProcessingLoop();
}
STDMETHODIMP CBlankAudioPin::ConnectionMediaType(AM_MEDIA_TYPE*)
{
return S_OK;
}
HRESULT CBlankAudioPin::CheckMediaType(const CMediaType *pMediaType)
{
CheckPointer(pMediaType,E_POINTER);
if( *(pMediaType->FormatType())!= FORMAT_WaveFormatEx )
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
// we only want fixed size Audio
//
if( *(pMediaType->Type()) != MEDIATYPE_Audio )
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
if( *(pMediaType->Subtype()) != MEDIASUBTYPE_PCM)
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pMediaType->pbFormat;
if (!pwfx)
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
if (pwfx->wBitsPerSample != m_wf.wBitsPerSample)
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
if (pwfx->nAvgBytesPerSec != m_wf.nAvgBytesPerSec)
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
if (pwfx->nChannels != m_wf.nChannels)
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
if (pwfx->nSamplesPerSec != m_wf.nSamplesPerSec)
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
return S_OK;
}
HRESULT CBlankAudioPin::GetMediaType(int iPosition, CMediaType *pMediaType)
{
CheckPointer(pMediaType,E_POINTER);
if (iPosition < 0)
{
return E_INVALIDARG;
}
// Have we run off the end of types
if( iPosition > 0 )
{
return VFW_S_NO_MORE_ITEMS;
}
return GetMediaType(pMediaType);
}
HRESULT CBlankAudioPin::GetMediaType(CMediaType *pMediaType)
{
pMediaType ->InitMediaType();
pMediaType->SetType(&MEDIATYPE_Audio);
pMediaType->SetFormatType(&FORMAT_WaveFormatEx);
pMediaType->SetFormat( (BYTE*) &m_wf, sizeof( m_wf ) );
pMediaType->SetSubtype(&MEDIASUBTYPE_PCM);
pMediaType->SetSampleSize(m_dwBufferSize);
return NOERROR;
}
HRESULT CBlankAudioPin::FillBuffer(IMediaSample *pSample)
{
CAutoLock Lock( &m_SeekLock );
double dSampleByte = (double)m_wf.nAvgBytesPerSec / (double)(m_dwBufferSize);
if (!dSampleByte) dSampleByte = 0.00000001;
m_rtStartTime = m_rtEndTime;//Frame2Time( m_iCountFrame, gScale, dSampleByte);
m_rtEndTime += (LONGLONG)((UNITS / dSampleByte));
// return S_FALSE if we've hit EOS. Parent class will send EOS for us
//
if( m_rtStartTime > m_rtStop )
{
return S_FALSE;
}
SHORT* pBuffer = NULL;
pSample -> GetPointer((BYTE**)&pBuffer);
int iSize = pSample -> GetSize() / 2;
static int iLastLevel = 0;
//creating low level wave
for (int i = 0; i < iSize; i++)
{
*(pBuffer + i) = (short)(5.0 * sin(0.2 * (double)(i + iLastLevel) * 2.0 * 3.14 / (180.0)));
}
iLastLevel += (iSize);
if (iLastLevel < 0)
{
iLastLevel = 0;
}
// set the timestamp
//
pSample->SetTime( &m_rtStartTime, &m_rtEndTime);
// set the sync point
//
pSample -> SetActualDataLength(m_dwBufferSize);
pSample -> SetSyncPoint(TRUE);
m_iCountFrame++;
return S_OK;
}
HRESULT CBlankAudioPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties)
{
HRESULT hr = NOERROR;
CheckPointer(pAlloc,E_POINTER);
CheckPointer(pProperties,E_POINTER);
pProperties->cBuffers = 1;
if (pProperties->cbAlign == 0)
pProperties->cbAlign = 1;
// Get input pin's allocator size and use that
pProperties->cbBuffer = m_dwBufferSize;
// Ask the allocator to reserve us some sample memory, NOTE the function
// can succeed (that is return NOERROR) but still not have allocated the
// memory that we requested, so we must check we got whatever we wanted
ALLOCATOR_PROPERTIES Actual;
hr = pAlloc->SetProperties(pProperties,&Actual);
if(FAILED(hr))
{
return hr;
}
if(pProperties->cBuffers > Actual.cBuffers ||
pProperties->cbBuffer > Actual.cbBuffer)
{
return E_FAIL;
}
return NOERROR;
}
STDMETHODIMP CBlankAudioPin::NonDelegatingQueryInterface( REFIID riid, void ** ppv )
{
if( riid == IID_IMediaSeeking )
{
return CSourceSeeking::NonDelegatingQueryInterface( riid, ppv );
}
return CSourceStream::NonDelegatingQueryInterface(riid, ppv);
}
CBlankStreams::CBlankStreams(HRESULT* pHr):
CSource(g_wszNameFilter, NULL, CLSID_CoBlankStreams)
{
m_pAudioPin = new CBlankAudioPin(pHr, this);
}
CBlankStreams::~CBlankStreams(void)
{
if (m_paStreams)
{
if (m_paStreams[0]) delete m_paStreams[0];
delete [] m_paStreams;
}
}
CUnknown * WINAPI CBlankStreams::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CUnknown* pNewObject = new CBlankStreams(pHr);
if (!pNewObject) *pHr = E_OUTOFMEMORY;
return pNewObject;
}
STDMETHODIMP CBlankStreams::NonDelegatingQueryInterface(const IID& riid, void** ppv)
{
return CSource::NonDelegatingQueryInterface(riid, ppv);
}
Direct Show & IStream ?
пишу простенький проигрыватель аудио-файлов, возникла такая проблема: необходимо проиграть не определенный файл, а некоторые данные загруженные в память (например ресурс).
Дело в том что AddSourceFilter из IGraphBuilder требует имени файла, а файла-то нет. :о)
Как решить эту проблему? заранее благодарю. :о)
Поищи фильтры сторонних разработчиков. либо напиши сам SourceFilter
Вот пример сорс фильтра для генерации звука теперь ты можешь сюда подставить чтения из памяти
спасибо. :о) я уже нашел ответ. фильтр почти готов. :о)