blob: 333d142073b62a6c1717b7648ad4311eb06c0ffb [file] [log] [blame]
/* $Id$ */
/*
* Copyright (C) 2008-2010 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 <pjmedia-videodev/config.h>
#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
#include <assert.h>
#include <streams.h>
#if PJ_DEBUG
# pragma comment(lib, "Strmbasd.lib")
#else
# pragma comment(lib, "Strmbase.lib")
#endif
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 */