- Merge from trunk up to r45543
[reactos.git] / dll / directx / qedit / samplegrabber.c
1 /* DirectShow Sample Grabber object (QEDIT.DLL)
2 *
3 * Copyright 2009 Paul Chitescu
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <assert.h>
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29
30 #include "qedit_private.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(qedit);
34
35 static WCHAR const vendor_name[] = { 'W', 'i', 'n', 'e', 0 };
36
37 /* Sample Grabber filter implementation */
38 typedef struct _SG_Impl {
39 const IBaseFilterVtbl* IBaseFilter_Vtbl;
40 const ISampleGrabberVtbl* ISampleGrabber_Vtbl;
41 /* TODO: IMediaPosition, IMediaSeeking, IQualityControl */
42 LONG refCount;
43 FILTER_INFO info;
44 FILTER_STATE state;
45 IMemAllocator *allocator;
46 IReferenceClock *refClock;
47 } SG_Impl;
48
49 /* Get the SampleGrabber implementation This pointer from various interface pointers */
50 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
51 {
52 return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, IBaseFilter_Vtbl));
53 }
54
55 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
56 {
57 return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, ISampleGrabber_Vtbl));
58 }
59
60
61 /* Cleanup at end of life */
62 static void SampleGrabber_cleanup(SG_Impl *This)
63 {
64 TRACE("(%p)\n", This);
65 if (This->info.pGraph)
66 WARN("(%p) still joined to filter graph %p\n", This, This->info.pGraph);
67 if (This->allocator)
68 IMemAllocator_Release(This->allocator);
69 if (This->refClock)
70 IReferenceClock_Release(This->refClock);
71 }
72
73 /* Common helper AddRef called from all interfaces */
74 static ULONG SampleGrabber_addref(SG_Impl *This)
75 {
76 ULONG refCount = InterlockedIncrement(&This->refCount);
77 TRACE("(%p) new ref = %u\n", This, refCount);
78 return refCount;
79 }
80
81 /* Common helper Release called from all interfaces */
82 static ULONG SampleGrabber_release(SG_Impl *This)
83 {
84 ULONG refCount = InterlockedDecrement(&This->refCount);
85 TRACE("(%p) new ref = %u\n", This, refCount);
86 if (refCount == 0)
87 {
88 SampleGrabber_cleanup(This);
89 CoTaskMemFree(This);
90 return 0;
91 }
92 return refCount;
93 }
94
95 /* Common helper QueryInterface called from all interfaces */
96 static HRESULT SampleGrabber_query(SG_Impl *This, REFIID riid, void **ppvObject)
97 {
98 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
99
100 if (IsEqualIID(riid, &IID_IUnknown) ||
101 IsEqualIID(riid, &IID_IPersist) ||
102 IsEqualIID(riid, &IID_IMediaFilter) ||
103 IsEqualIID(riid, &IID_IBaseFilter)) {
104 SampleGrabber_addref(This);
105 *ppvObject = &(This->IBaseFilter_Vtbl);
106 return S_OK;
107 }
108 else if (IsEqualIID(riid, &IID_ISampleGrabber)) {
109 SampleGrabber_addref(This);
110 *ppvObject = &(This->ISampleGrabber_Vtbl);
111 return S_OK;
112 }
113 else if (IsEqualIID(riid, &IID_IMemInputPin))
114 FIXME("IMemInputPin not implemented\n");
115 else if (IsEqualIID(riid, &IID_IMediaPosition))
116 FIXME("IMediaPosition not implemented\n");
117 else if (IsEqualIID(riid, &IID_IMediaSeeking))
118 FIXME("IMediaSeeking not implemented\n");
119 else if (IsEqualIID(riid, &IID_IQualityControl))
120 FIXME("IQualityControl not implemented\n");
121 *ppvObject = NULL;
122 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
123 return E_NOINTERFACE;
124 }
125
126
127 /* SampleGrabber implementation of IBaseFilter interface */
128
129 /* IUnknown */
130 static HRESULT WINAPI
131 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppvObject)
132 {
133 return SampleGrabber_query(impl_from_IBaseFilter(iface), riid, ppvObject);
134 }
135
136 /* IUnknown */
137 static ULONG WINAPI
138 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
139 {
140 return SampleGrabber_addref(impl_from_IBaseFilter(iface));
141 }
142
143 /* IUnknown */
144 static ULONG WINAPI
145 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
146 {
147 return SampleGrabber_release(impl_from_IBaseFilter(iface));
148 }
149
150 /* IPersist */
151 static HRESULT WINAPI
152 SampleGrabber_IBaseFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID)
153 {
154 TRACE("(%p)\n", pClassID);
155 if (!pClassID)
156 return E_POINTER;
157 *pClassID = CLSID_SampleGrabber;
158 return S_OK;
159 }
160
161 /* IMediaFilter */
162 static HRESULT WINAPI
163 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
164 {
165 SG_Impl *This = impl_from_IBaseFilter(iface);
166 TRACE("(%p)\n", This);
167 This->state = State_Stopped;
168 return S_OK;
169 }
170
171 /* IMediaFilter */
172 static HRESULT WINAPI
173 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
174 {
175 SG_Impl *This = impl_from_IBaseFilter(iface);
176 TRACE("(%p)\n", This);
177 This->state = State_Paused;
178 return S_OK;
179 }
180
181 /* IMediaFilter */
182 static HRESULT WINAPI
183 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
184 {
185 SG_Impl *This = impl_from_IBaseFilter(iface);
186 TRACE("(%p)\n", This);
187 This->state = State_Running;
188 return S_OK;
189 }
190
191 /* IMediaFilter */
192 static HRESULT WINAPI
193 SampleGrabber_IBaseFilter_GetState(IBaseFilter *iface, DWORD msTout, FILTER_STATE *state)
194 {
195 SG_Impl *This = impl_from_IBaseFilter(iface);
196 TRACE("(%p)->(%u, %p)\n", This, msTout, state);
197 if (!state)
198 return E_POINTER;
199 *state = This->state;
200 return S_OK;
201 }
202
203 /* IMediaFilter */
204 static HRESULT WINAPI
205 SampleGrabber_IBaseFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
206 {
207 SG_Impl *This = impl_from_IBaseFilter(iface);
208 TRACE("(%p)->(%p)\n", This, clock);
209 if (clock != This->refClock)
210 {
211 if (clock)
212 IReferenceClock_AddRef(clock);
213 if (This->refClock)
214 IReferenceClock_Release(This->refClock);
215 This->refClock = clock;
216 }
217 return S_OK;
218 }
219
220 /* IMediaFilter */
221 static HRESULT WINAPI
222 SampleGrabber_IBaseFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock)
223 {
224 SG_Impl *This = impl_from_IBaseFilter(iface);
225 TRACE("(%p)->(%p)\n", This, clock);
226 if (!clock)
227 return E_POINTER;
228 if (This->refClock)
229 IReferenceClock_AddRef(This->refClock);
230 *clock = This->refClock;
231 return S_OK;
232 }
233
234 /* IBaseFilter */
235 static HRESULT WINAPI
236 SampleGrabber_IBaseFilter_EnumPins(IBaseFilter *iface, IEnumPins **pins)
237 {
238 SG_Impl *This = impl_from_IBaseFilter(iface);
239 FIXME("(%p)->(%p): stub\n", This, pins);
240 if (!pins)
241 return E_POINTER;
242 return E_OUTOFMEMORY;
243 }
244
245 /* IBaseFilter */
246 static HRESULT WINAPI
247 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
248 {
249 SG_Impl *This = impl_from_IBaseFilter(iface);
250 FIXME("(%p)->(%s, %p): stub\n", This, debugstr_w(id), pin);
251 if (!id || !pin)
252 return E_POINTER;
253 *pin = NULL;
254 return VFW_E_NOT_FOUND;
255 }
256
257 /* IBaseFilter */
258 static HRESULT WINAPI
259 SampleGrabber_IBaseFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info)
260 {
261 SG_Impl *This = impl_from_IBaseFilter(iface);
262 TRACE("(%p)->(%p)\n", This, info);
263 if (!info)
264 return E_POINTER;
265 if (This->info.pGraph)
266 IFilterGraph_AddRef(This->info.pGraph);
267 *info = This->info;
268 return S_OK;
269 }
270
271 /* IBaseFilter */
272 static HRESULT WINAPI
273 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
274 {
275 SG_Impl *This = impl_from_IBaseFilter(iface);
276 TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
277 This->info.pGraph = graph;
278 if (name)
279 lstrcpynW(This->info.achName,name,MAX_FILTER_NAME);
280 return S_OK;
281 }
282
283 /* IBaseFilter */
284 static HRESULT WINAPI
285 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
286 {
287 TRACE("(%p)\n", vendor);
288 if (!vendor)
289 return E_POINTER;
290 *vendor = CoTaskMemAlloc(sizeof(vendor_name));
291 CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
292 return S_OK;
293 }
294
295
296 /* SampleGrabber implementation of ISampleGrabber interface */
297
298 /* IUnknown */
299 static HRESULT WINAPI
300 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppvObject)
301 {
302 return SampleGrabber_query(impl_from_ISampleGrabber(iface), riid, ppvObject);
303 }
304
305 /* IUnknown */
306 static ULONG WINAPI
307 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
308 {
309 return SampleGrabber_addref(impl_from_ISampleGrabber(iface));
310 }
311
312 /* IUnknown */
313 static ULONG WINAPI
314 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
315 {
316 return SampleGrabber_release(impl_from_ISampleGrabber(iface));
317 }
318
319 /* ISampleGrabber */
320 static HRESULT WINAPI
321 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
322 {
323 SG_Impl *This = impl_from_ISampleGrabber(iface);
324 FIXME("(%p)->(%u): stub\n", This, oneShot);
325 return E_NOTIMPL;
326 }
327
328 /* ISampleGrabber */
329 static HRESULT WINAPI
330 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
331 {
332 SG_Impl *This = impl_from_ISampleGrabber(iface);
333 FIXME("(%p)->(%p): stub\n", This, type);
334 if (!type)
335 return E_POINTER;
336 return E_NOTIMPL;
337 }
338
339 /* ISampleGrabber */
340 static HRESULT WINAPI
341 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
342 {
343 SG_Impl *This = impl_from_ISampleGrabber(iface);
344 FIXME("(%p)->(%p): stub\n", This, type);
345 if (!type)
346 return E_POINTER;
347 return E_NOTIMPL;
348 }
349
350 /* ISampleGrabber */
351 static HRESULT WINAPI
352 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
353 {
354 TRACE("(%u)\n", bufferEm);
355 if (bufferEm) {
356 FIXME("buffering not implemented\n");
357 return E_NOTIMPL;
358 }
359 return S_OK;
360 }
361
362 /* ISampleGrabber */
363 static HRESULT WINAPI
364 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
365 {
366 FIXME("(%p, %p): stub\n", bufSize, buffer);
367 if (!bufSize)
368 return E_POINTER;
369 return E_INVALIDARG;
370 }
371
372 /* ISampleGrabber */
373 static HRESULT WINAPI
374 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
375 {
376 /* MS doesn't implement it either, noone should call it */
377 WARN("(%p): not implemented\n", sample);
378 return E_NOTIMPL;
379 }
380
381 /* ISampleGrabber */
382 static HRESULT WINAPI
383 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
384 {
385 SG_Impl *This = impl_from_ISampleGrabber(iface);
386 FIXME("(%p)->(%p, %u): stub\n", This, cb, whichMethod);
387 return E_NOTIMPL;
388 }
389
390
391 /* SampleGrabber vtables and constructor */
392
393 static const IBaseFilterVtbl IBaseFilter_VTable =
394 {
395 SampleGrabber_IBaseFilter_QueryInterface,
396 SampleGrabber_IBaseFilter_AddRef,
397 SampleGrabber_IBaseFilter_Release,
398 SampleGrabber_IBaseFilter_GetClassID,
399 SampleGrabber_IBaseFilter_Stop,
400 SampleGrabber_IBaseFilter_Pause,
401 SampleGrabber_IBaseFilter_Run,
402 SampleGrabber_IBaseFilter_GetState,
403 SampleGrabber_IBaseFilter_SetSyncSource,
404 SampleGrabber_IBaseFilter_GetSyncSource,
405 SampleGrabber_IBaseFilter_EnumPins,
406 SampleGrabber_IBaseFilter_FindPin,
407 SampleGrabber_IBaseFilter_QueryFilterInfo,
408 SampleGrabber_IBaseFilter_JoinFilterGraph,
409 SampleGrabber_IBaseFilter_QueryVendorInfo,
410 };
411
412 static const ISampleGrabberVtbl ISampleGrabber_VTable =
413 {
414 SampleGrabber_ISampleGrabber_QueryInterface,
415 SampleGrabber_ISampleGrabber_AddRef,
416 SampleGrabber_ISampleGrabber_Release,
417 SampleGrabber_ISampleGrabber_SetOneShot,
418 SampleGrabber_ISampleGrabber_SetMediaType,
419 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
420 SampleGrabber_ISampleGrabber_SetBufferSamples,
421 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
422 SampleGrabber_ISampleGrabber_GetCurrentSample,
423 SampleGrabber_ISampleGrabber_SetCallback,
424 };
425
426 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
427 {
428 SG_Impl* obj = NULL;
429
430 TRACE("(%p,%p)\n", ppv, pUnkOuter);
431
432 if (pUnkOuter)
433 return CLASS_E_NOAGGREGATION;
434
435 obj = CoTaskMemAlloc(sizeof(SG_Impl));
436 if (NULL == obj) {
437 *ppv = NULL;
438 return E_OUTOFMEMORY;
439 }
440 ZeroMemory(obj, sizeof(SG_Impl));
441
442 obj->refCount = 1;
443 obj->IBaseFilter_Vtbl = &IBaseFilter_VTable;
444 obj->ISampleGrabber_Vtbl = &ISampleGrabber_VTable;
445 obj->info.achName[0] = 0;
446 obj->info.pGraph = NULL;
447 obj->state = State_Stopped;
448 obj->allocator = NULL;
449 obj->refClock = NULL;
450 *ppv = obj;
451
452 return S_OK;
453 }