/* $Id$ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0 #include #include typedef void (*input_callback)(void *user_data, IMediaSample *pMediaSample); const GUID CLSID_NullRenderer = {0xF9168C5E, 0xCEB2, 0x4FAA, {0xB6, 0xBF, 0x32, 0x9B, 0xF3, 0x9F, 0xA1, 0xE4}}; const GUID CLSID_SourceFilter = {0xF9168C5E, 0xCEB2, 0x4FAA, {0xB6, 0xBF, 0x32, 0x9B, 0xF3, 0x9F, 0xA1, 0xE5}}; class NullRenderer: public CBaseRenderer { public: NullRenderer(HRESULT *pHr); virtual ~NullRenderer(); virtual HRESULT CheckMediaType(const CMediaType *pmt); virtual HRESULT DoRenderSample(IMediaSample *pMediaSample); input_callback input_cb; void *user_data; }; class OutputPin: public CBaseOutputPin { public: OutputPin(CBaseFilter *pFilter, CCritSec *pLock, HRESULT *pHr); ~OutputPin(); HRESULT Push(void *buf, long size); virtual HRESULT CheckMediaType(const CMediaType *pmt); virtual HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest); CMediaType mediaType; long bufSize; }; class SourceFilter: public CBaseFilter { public: SourceFilter(); ~SourceFilter(); int GetPinCount(); CBasePin* GetPin(int n); protected: CCritSec lock; OutputPin* outPin; }; OutputPin::OutputPin(CBaseFilter *pFilter, CCritSec *pLock, HRESULT *pHr): CBaseOutputPin("OutputPin", pFilter, pLock, pHr, L"OutputPin") { } OutputPin::~OutputPin() { } HRESULT OutputPin::CheckMediaType(const CMediaType *pmt) { return S_OK; } HRESULT OutputPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) { ALLOCATOR_PROPERTIES properties; ppropInputRequest->cbBuffer = bufSize; ppropInputRequest->cBuffers = 1; /* First set the buffer descriptions we're interested in */ pAlloc->SetProperties(ppropInputRequest, &properties); return S_OK; } HRESULT OutputPin::Push(void *buf, long size) { HRESULT hr; IMediaSample *pSample; VIDEOINFOHEADER *vi; AM_MEDIA_TYPE *pmt; BYTE *dst_buf; /** * Hold the critical section here as the pin might get disconnected * during the Deliver() method call. */ m_pLock->Lock(); hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0); if (FAILED(hr)) goto on_error; pSample->GetMediaType(&pmt); if (pmt) { mediaType.Set(*pmt); bufSize = pmt->lSampleSize; } pSample->GetPointer(&dst_buf); vi = (VIDEOINFOHEADER *)mediaType.pbFormat; if (vi->rcSource.right == vi->bmiHeader.biWidth) { assert(pSample->GetSize() >= size); memcpy(dst_buf, buf, size); } else { unsigned i, bpp; unsigned dststride, srcstride; BYTE *src_buf = (BYTE *)buf; bpp = size / abs(vi->bmiHeader.biHeight) / vi->rcSource.right; dststride = vi->bmiHeader.biWidth * bpp; srcstride = vi->rcSource.right * bpp; for (i = abs(vi->bmiHeader.biHeight); i > 0; i--) { memcpy(dst_buf, src_buf, srcstride); dst_buf += dststride; src_buf += srcstride; } } pSample->SetActualDataLength(size); hr = Deliver(pSample); pSample->Release(); on_error: m_pLock->Unlock(); return hr; } SourceFilter::SourceFilter(): CBaseFilter("SourceFilter", NULL, &lock, CLSID_SourceFilter) { HRESULT hr; outPin = new OutputPin(this, &lock, &hr); } SourceFilter::~SourceFilter() { } int SourceFilter::GetPinCount() { return 1; } CBasePin* SourceFilter::GetPin(int n) { return outPin; } NullRenderer::NullRenderer(HRESULT *pHr): CBaseRenderer(CLSID_NullRenderer, "NullRenderer", NULL, pHr) { input_cb = NULL; } NullRenderer::~NullRenderer() { } HRESULT NullRenderer::CheckMediaType(const CMediaType *pmt) { return S_OK; } HRESULT NullRenderer::DoRenderSample(IMediaSample *pMediaSample) { if (input_cb) input_cb(user_data, pMediaSample); return S_OK; } extern "C" IBaseFilter* NullRenderer_Create(input_callback input_cb, void *user_data) { HRESULT hr; NullRenderer *renderer = new NullRenderer(&hr); renderer->AddRef(); renderer->input_cb = input_cb; renderer->user_data = user_data; return (CBaseFilter *)renderer; } extern "C" IBaseFilter* SourceFilter_Create(SourceFilter **pSrc) { SourceFilter *src = new SourceFilter(); src->AddRef(); *pSrc = src; return (CBaseFilter *)src; } extern "C" HRESULT SourceFilter_Deliver(SourceFilter *src, void *buf, long size) { return ((OutputPin *)src->GetPin(0))->Push(buf, size); } extern "C" void SourceFilter_SetMediaType(SourceFilter *src, AM_MEDIA_TYPE *pmt) { ((OutputPin *)src->GetPin(0))->mediaType.Set(*pmt); ((OutputPin *)src->GetPin(0))->bufSize = pmt->lSampleSize; } #endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */