blob: 5affe6083b0380684dca316b13fcac470100c7d1 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id: dshowclasses.cpp 4062 2012-04-19 06:36:57Z ming $ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include <pjmedia-videodev/config.h>
21
22
23#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
24
25
26#include <assert.h>
27#include <streams.h>
28
29typedef void (*input_callback)(void *user_data, IMediaSample *pMediaSample);
30
31const GUID CLSID_NullRenderer = {0xF9168C5E, 0xCEB2, 0x4FAA, {0xB6, 0xBF,
32 0x32, 0x9B, 0xF3, 0x9F, 0xA1, 0xE4}};
33
34const GUID CLSID_SourceFilter = {0xF9168C5E, 0xCEB2, 0x4FAA, {0xB6, 0xBF,
35 0x32, 0x9B, 0xF3, 0x9F, 0xA1, 0xE5}};
36
37class NullRenderer: public CBaseRenderer
38{
39public:
40 NullRenderer(HRESULT *pHr);
41 virtual ~NullRenderer();
42
43 virtual HRESULT CheckMediaType(const CMediaType *pmt);
44 virtual HRESULT DoRenderSample(IMediaSample *pMediaSample);
45
46 input_callback input_cb;
47 void *user_data;
48};
49
50class OutputPin: public CBaseOutputPin
51{
52public:
53 OutputPin(CBaseFilter *pFilter, CCritSec *pLock, HRESULT *pHr);
54 ~OutputPin();
55
56 HRESULT Push(void *buf, long size);
57
58 virtual HRESULT CheckMediaType(const CMediaType *pmt);
59 virtual HRESULT DecideBufferSize(IMemAllocator *pAlloc,
60 ALLOCATOR_PROPERTIES *ppropInputRequest);
61
62 CMediaType mediaType;
63 long bufSize;
64};
65
66class SourceFilter: public CBaseFilter
67{
68public:
69 SourceFilter();
70 ~SourceFilter();
71
72 int GetPinCount();
73 CBasePin* GetPin(int n);
74
75protected:
76 CCritSec lock;
77 OutputPin* outPin;
78};
79
80OutputPin::OutputPin(CBaseFilter *pFilter, CCritSec *pLock, HRESULT *pHr):
81 CBaseOutputPin("OutputPin", pFilter, pLock, pHr, L"OutputPin")
82{
83}
84
85OutputPin::~OutputPin()
86{
87}
88
89HRESULT OutputPin::CheckMediaType(const CMediaType *pmt)
90{
91 return S_OK;
92}
93
94HRESULT OutputPin::DecideBufferSize(IMemAllocator *pAlloc,
95 ALLOCATOR_PROPERTIES *ppropInputRequest)
96{
97 ALLOCATOR_PROPERTIES properties;
98
99 ppropInputRequest->cbBuffer = bufSize;
100 ppropInputRequest->cBuffers = 1;
101
102 /* First set the buffer descriptions we're interested in */
103 pAlloc->SetProperties(ppropInputRequest, &properties);
104
105 return S_OK;
106}
107
108HRESULT OutputPin::Push(void *buf, long size)
109{
110 HRESULT hr;
111 IMediaSample *pSample;
112 VIDEOINFOHEADER *vi;
113 AM_MEDIA_TYPE *pmt;
114 BYTE *dst_buf;
115
116 /**
117 * Hold the critical section here as the pin might get disconnected
118 * during the Deliver() method call.
119 */
120 m_pLock->Lock();
121
122 hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0);
123 if (FAILED(hr))
124 goto on_error;
125
126 pSample->GetMediaType(&pmt);
127 if (pmt) {
128 mediaType.Set(*pmt);
129 bufSize = pmt->lSampleSize;
130 }
131
132 pSample->GetPointer(&dst_buf);
133 vi = (VIDEOINFOHEADER *)mediaType.pbFormat;
134 if (vi->rcSource.right == vi->bmiHeader.biWidth) {
135 assert(pSample->GetSize() >= size);
136 memcpy(dst_buf, buf, size);
137 } else {
138 unsigned i, bpp;
139 unsigned dststride, srcstride;
140 BYTE *src_buf = (BYTE *)buf;
141
142 bpp = size / abs(vi->bmiHeader.biHeight) / vi->rcSource.right;
143 dststride = vi->bmiHeader.biWidth * bpp;
144 srcstride = vi->rcSource.right * bpp;
145 for (i = abs(vi->bmiHeader.biHeight); i > 0; i--) {
146 memcpy(dst_buf, src_buf, srcstride);
147 dst_buf += dststride;
148 src_buf += srcstride;
149 }
150 }
151 pSample->SetActualDataLength(size);
152
153 hr = Deliver(pSample);
154
155 pSample->Release();
156
157on_error:
158 m_pLock->Unlock();
159 return hr;
160}
161
162SourceFilter::SourceFilter(): CBaseFilter("SourceFilter", NULL, &lock,
163 CLSID_SourceFilter)
164{
165 HRESULT hr;
166 outPin = new OutputPin(this, &lock, &hr);
167}
168
169SourceFilter::~SourceFilter()
170{
171}
172
173int SourceFilter::GetPinCount()
174{
175 return 1;
176}
177
178CBasePin* SourceFilter::GetPin(int n)
179{
180 return outPin;
181}
182
183NullRenderer::NullRenderer(HRESULT *pHr): CBaseRenderer(CLSID_NullRenderer,
184 "NullRenderer",
185 NULL, pHr)
186{
187 input_cb = NULL;
188}
189
190NullRenderer::~NullRenderer()
191{
192}
193
194HRESULT NullRenderer::CheckMediaType(const CMediaType *pmt)
195{
196 return S_OK;
197}
198
199HRESULT NullRenderer::DoRenderSample(IMediaSample *pMediaSample)
200{
201 if (input_cb)
202 input_cb(user_data, pMediaSample);
203
204 return S_OK;
205}
206
207extern "C" IBaseFilter* NullRenderer_Create(input_callback input_cb,
208 void *user_data)
209{
210 HRESULT hr;
211 NullRenderer *renderer = new NullRenderer(&hr);
212 renderer->AddRef();
213 renderer->input_cb = input_cb;
214 renderer->user_data = user_data;
215
216 return (CBaseFilter *)renderer;
217}
218
219extern "C" IBaseFilter* SourceFilter_Create(SourceFilter **pSrc)
220{
221 SourceFilter *src = new SourceFilter();
222 src->AddRef();
223 *pSrc = src;
224
225 return (CBaseFilter *)src;
226}
227
228extern "C" HRESULT SourceFilter_Deliver(SourceFilter *src,
229 void *buf, long size)
230{
231 return ((OutputPin *)src->GetPin(0))->Push(buf, size);
232}
233
234extern "C" void SourceFilter_SetMediaType(SourceFilter *src,
235 AM_MEDIA_TYPE *pmt)
236{
237 ((OutputPin *)src->GetPin(0))->mediaType.Set(*pmt);
238 ((OutputPin *)src->GetPin(0))->bufSize = pmt->lSampleSize;
239}
240
241
242#endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */