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 #include "wine/strmbase.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(qedit);
35
36 static const WCHAR vendor_name[] = { 'W', 'i', 'n', 'e', 0 };
37 static const WCHAR pin_in_name[] = { 'I', 'n', 0 };
38 static const WCHAR pin_out_name[] = { 'O', 'u', 't', 0 };
39
40 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype, BOOL past);
41
42 /* Single media type enumerator */
43 typedef struct _ME_Impl {
44 IEnumMediaTypes IEnumMediaTypes_iface;
45 LONG refCount;
46 BOOL past;
47 AM_MEDIA_TYPE mtype;
48 } ME_Impl;
49
50
51 /* IEnumMediaTypes interface implementation */
52
impl_from_IEnumMediaTypes(IEnumMediaTypes * iface)53 static inline ME_Impl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
54 {
55 return CONTAINING_RECORD(iface, ME_Impl, IEnumMediaTypes_iface);
56 }
57
Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes * iface,REFIID riid,void ** ret_iface)58 static HRESULT WINAPI Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes *iface, REFIID riid,
59 void **ret_iface)
60 {
61 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
62
63 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ret_iface);
64
65 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumMediaTypes)) {
66 *ret_iface = iface;
67 IEnumMediaTypes_AddRef(iface);
68 return S_OK;
69 }
70 *ret_iface = NULL;
71 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ret_iface);
72 return E_NOINTERFACE;
73 }
74
Single_IEnumMediaTypes_AddRef(IEnumMediaTypes * iface)75 static ULONG WINAPI Single_IEnumMediaTypes_AddRef(IEnumMediaTypes *iface)
76 {
77 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
78 ULONG refCount = InterlockedIncrement(&This->refCount);
79
80 TRACE("(%p) new ref = %u\n", This, refCount);
81 return refCount;
82 }
83
Single_IEnumMediaTypes_Release(IEnumMediaTypes * iface)84 static ULONG WINAPI Single_IEnumMediaTypes_Release(IEnumMediaTypes *iface)
85 {
86 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
87 ULONG refCount = InterlockedDecrement(&This->refCount);
88
89 TRACE("(%p) new ref = %u\n", This, refCount);
90 if (refCount == 0)
91 {
92 CoTaskMemFree(This->mtype.pbFormat);
93 CoTaskMemFree(This);
94 }
95 return refCount;
96 }
97
98 /* IEnumMediaTypes */
Single_IEnumMediaTypes_Next(IEnumMediaTypes * iface,ULONG nTypes,AM_MEDIA_TYPE ** types,ULONG * fetched)99 static HRESULT WINAPI Single_IEnumMediaTypes_Next(IEnumMediaTypes *iface, ULONG nTypes,
100 AM_MEDIA_TYPE **types, ULONG *fetched)
101 {
102 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
103 ULONG count = 0;
104
105 TRACE("(%p)->(%u, %p, %p)\n", This, nTypes, types, fetched);
106 if (!nTypes)
107 return E_INVALIDARG;
108 if (!types || ((nTypes != 1) && !fetched))
109 return E_POINTER;
110 if (!This->past && !IsEqualGUID(&This->mtype.majortype,&GUID_NULL)) {
111 AM_MEDIA_TYPE *mtype = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
112 *mtype = This->mtype;
113 if (mtype->cbFormat) {
114 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
115 CopyMemory(mtype->pbFormat, This->mtype.pbFormat, mtype->cbFormat);
116 }
117 *types = mtype;
118 This->past = TRUE;
119 count = 1;
120 }
121 if (fetched)
122 *fetched = count;
123 return (count == nTypes) ? S_OK : S_FALSE;
124 }
125
Single_IEnumMediaTypes_Skip(IEnumMediaTypes * iface,ULONG nTypes)126 static HRESULT WINAPI Single_IEnumMediaTypes_Skip(IEnumMediaTypes *iface, ULONG nTypes)
127 {
128 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
129
130 TRACE("(%p)->(%u)\n", This, nTypes);
131 if (nTypes)
132 This->past = TRUE;
133 return This->past ? S_FALSE : S_OK;
134 }
135
Single_IEnumMediaTypes_Reset(IEnumMediaTypes * iface)136 static HRESULT WINAPI Single_IEnumMediaTypes_Reset(IEnumMediaTypes *iface)
137 {
138 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
139
140 TRACE("(%p)->()\n", This);
141 This->past = FALSE;
142 return S_OK;
143 }
144
Single_IEnumMediaTypes_Clone(IEnumMediaTypes * iface,IEnumMediaTypes ** me)145 static HRESULT WINAPI Single_IEnumMediaTypes_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **me)
146 {
147 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
148
149 TRACE("(%p)->(%p)\n", This, me);
150 if (!me)
151 return E_POINTER;
152 *me = mediaenum_create(&This->mtype, This->past);
153 if (!*me)
154 return E_OUTOFMEMORY;
155 return S_OK;
156 }
157
158
159 /* Virtual tables and constructor */
160
161 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable =
162 {
163 Single_IEnumMediaTypes_QueryInterface,
164 Single_IEnumMediaTypes_AddRef,
165 Single_IEnumMediaTypes_Release,
166 Single_IEnumMediaTypes_Next,
167 Single_IEnumMediaTypes_Skip,
168 Single_IEnumMediaTypes_Reset,
169 Single_IEnumMediaTypes_Clone,
170 };
171
mediaenum_create(const AM_MEDIA_TYPE * mtype,BOOL past)172 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype, BOOL past)
173 {
174 ME_Impl *obj = CoTaskMemAlloc(sizeof(ME_Impl));
175
176 if (!obj)
177 return NULL;
178 ZeroMemory(obj, sizeof(*obj));
179 obj->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypes_VTable;
180 obj->refCount = 1;
181 obj->past = past;
182 if (mtype) {
183 obj->mtype = *mtype;
184 obj->mtype.pUnk = NULL;
185 if (mtype->cbFormat) {
186 obj->mtype.pbFormat = CoTaskMemAlloc(mtype->cbFormat);
187 CopyMemory(obj->mtype.pbFormat, mtype->pbFormat, mtype->cbFormat);
188 }
189 else
190 obj->mtype.pbFormat = NULL;
191 }
192 else
193 obj->mtype.majortype = GUID_NULL;
194
195 return &obj->IEnumMediaTypes_iface;
196 }
197
198
199 /* Sample Grabber pin implementation */
200 typedef struct _SG_Pin {
201 IPin IPin_iface;
202 PIN_DIRECTION dir;
203 WCHAR const *name;
204 struct _SG_Impl *sg;
205 IPin *pair;
206 } SG_Pin;
207
impl_from_IPin(IPin * iface)208 static inline SG_Pin *impl_from_IPin(IPin *iface)
209 {
210 return CONTAINING_RECORD(iface, SG_Pin, IPin_iface);
211 }
212
213 /* Sample Grabber filter implementation */
214 typedef struct _SG_Impl {
215 IUnknown IUnknown_inner;
216 BaseFilter filter;
217 ISampleGrabber ISampleGrabber_iface;
218 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
219 IUnknown* seekthru_unk;
220 IUnknown *outer_unk;
221 AM_MEDIA_TYPE mtype;
222 SG_Pin pin_in;
223 SG_Pin pin_out;
224 IMemInputPin IMemInputPin_iface;
225 IMemAllocator *allocator;
226 IMemInputPin *memOutput;
227 ISampleGrabberCB *grabberIface;
228 LONG grabberMethod;
229 LONG oneShot;
230 LONG bufferLen;
231 void* bufferData;
232 } SG_Impl;
233
234 enum {
235 OneShot_None,
236 OneShot_Wait,
237 OneShot_Past,
238 };
239
impl_from_IUnknown(IUnknown * iface)240 static inline SG_Impl *impl_from_IUnknown(IUnknown *iface)
241 {
242 return CONTAINING_RECORD(iface, SG_Impl, IUnknown_inner);
243 }
244
impl_from_BaseFilter(BaseFilter * iface)245 static inline SG_Impl *impl_from_BaseFilter(BaseFilter *iface)
246 {
247 return CONTAINING_RECORD(iface, SG_Impl, filter);
248 }
249
impl_from_IBaseFilter(IBaseFilter * iface)250 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
251 {
252 return CONTAINING_RECORD(iface, SG_Impl, filter.IBaseFilter_iface);
253 }
254
impl_from_ISampleGrabber(ISampleGrabber * iface)255 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
256 {
257 return CONTAINING_RECORD(iface, SG_Impl, ISampleGrabber_iface);
258 }
259
impl_from_IMemInputPin(IMemInputPin * iface)260 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface)
261 {
262 return CONTAINING_RECORD(iface, SG_Impl, IMemInputPin_iface);
263 }
264
265
266 /* Cleanup at end of life */
SampleGrabber_cleanup(SG_Impl * This)267 static void SampleGrabber_cleanup(SG_Impl *This)
268 {
269 TRACE("(%p)\n", This);
270 if (This->filter.filterInfo.pGraph)
271 WARN("(%p) still joined to filter graph %p\n", This, This->filter.filterInfo.pGraph);
272 if (This->allocator)
273 IMemAllocator_Release(This->allocator);
274 if (This->memOutput)
275 IMemInputPin_Release(This->memOutput);
276 if (This->grabberIface)
277 ISampleGrabberCB_Release(This->grabberIface);
278 CoTaskMemFree(This->mtype.pbFormat);
279 CoTaskMemFree(This->bufferData);
280 if(This->seekthru_unk)
281 IUnknown_Release(This->seekthru_unk);
282 }
283
284 /* SampleGrabber inner IUnknown */
SampleGrabber_QueryInterface(IUnknown * iface,REFIID riid,void ** ppv)285 static HRESULT WINAPI SampleGrabber_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
286 {
287 SG_Impl *This = impl_from_IUnknown(iface);
288
289 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
290
291 *ppv = NULL;
292 if (IsEqualIID(riid, &IID_IUnknown))
293 *ppv = &This->IUnknown_inner;
294 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IMediaFilter) ||
295 IsEqualIID(riid, &IID_IBaseFilter))
296 *ppv = &This->filter.IBaseFilter_iface;
297 else if (IsEqualIID(riid, &IID_ISampleGrabber))
298 *ppv = &This->ISampleGrabber_iface;
299 else if (IsEqualIID(riid, &IID_IMediaPosition))
300 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
301 else if (IsEqualIID(riid, &IID_IMediaSeeking))
302 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
303 else
304 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
305
306 if (!*ppv)
307 return E_NOINTERFACE;
308
309 IUnknown_AddRef((IUnknown*)*ppv);
310 return S_OK;
311 }
312
SampleGrabber_AddRef(IUnknown * iface)313 static ULONG WINAPI SampleGrabber_AddRef(IUnknown *iface)
314 {
315 SG_Impl *This = impl_from_IUnknown(iface);
316 ULONG ref = BaseFilterImpl_AddRef(&This->filter.IBaseFilter_iface);
317
318 TRACE("(%p) ref=%d\n", This, ref);
319
320 return ref;
321 }
322
SampleGrabber_Release(IUnknown * iface)323 static ULONG WINAPI SampleGrabber_Release(IUnknown *iface)
324 {
325 SG_Impl *This = impl_from_IUnknown(iface);
326 ULONG ref = BaseFilterImpl_Release(&This->filter.IBaseFilter_iface);
327
328 TRACE("(%p) ref=%d\n", This, ref);
329
330 if (ref == 0)
331 {
332 SampleGrabber_cleanup(This);
333 CoTaskMemFree(This);
334 }
335 return ref;
336 }
337
338 static const IUnknownVtbl samplegrabber_vtbl =
339 {
340 SampleGrabber_QueryInterface,
341 SampleGrabber_AddRef,
342 SampleGrabber_Release,
343 };
344
SampleGrabber_GetPin(BaseFilter * iface,int pos)345 static IPin *WINAPI SampleGrabber_GetPin(BaseFilter *iface, int pos)
346 {
347 SG_Impl *This = impl_from_BaseFilter(iface);
348 IPin *pin;
349
350 if (pos == 0)
351 pin = &This->pin_in.IPin_iface;
352 else if (pos == 1)
353 pin = &This->pin_out.IPin_iface;
354 else
355 return NULL;
356
357 IPin_AddRef(pin);
358 return pin;
359 }
360
SampleGrabber_GetPinCount(BaseFilter * iface)361 static LONG WINAPI SampleGrabber_GetPinCount(BaseFilter *iface)
362 {
363 return 2;
364 }
365
366 static const BaseFilterFuncTable basefunc_vtbl = {
367 SampleGrabber_GetPin,
368 SampleGrabber_GetPinCount
369 };
370
371 /* Helper that buffers data and/or calls installed sample callbacks */
SampleGrabber_callback(SG_Impl * This,IMediaSample * sample)372 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
373 {
374 double time = 0.0;
375 REFERENCE_TIME tStart, tEnd;
376 if (This->bufferLen >= 0) {
377 BYTE *data = 0;
378 LONG size = IMediaSample_GetActualDataLength(sample);
379 if (size >= 0 && SUCCEEDED(IMediaSample_GetPointer(sample, &data))) {
380 if (!data)
381 size = 0;
382 EnterCriticalSection(&This->filter.csFilter);
383 if (This->bufferLen != size) {
384 CoTaskMemFree(This->bufferData);
385 This->bufferData = size ? CoTaskMemAlloc(size) : NULL;
386 This->bufferLen = size;
387 }
388 if (size)
389 CopyMemory(This->bufferData, data, size);
390 LeaveCriticalSection(&This->filter.csFilter);
391 }
392 }
393 if (!This->grabberIface)
394 return;
395 if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
396 time = 1e-7 * tStart;
397 switch (This->grabberMethod) {
398 case 0:
399 {
400 ULONG ref = IMediaSample_AddRef(sample);
401 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
402 ref = IMediaSample_Release(sample) + 1 - ref;
403 if (ref)
404 {
405 ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref);
406 /* ugly as hell but some apps are sooo buggy */
407 while (ref--)
408 IMediaSample_Release(sample);
409 }
410 }
411 break;
412 case 1:
413 {
414 BYTE *data = 0;
415 LONG size = IMediaSample_GetActualDataLength(sample);
416 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
417 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
418 }
419 break;
420 case -1:
421 break;
422 default:
423 FIXME("unsupported method %d\n", This->grabberMethod);
424 /* do not bother us again */
425 This->grabberMethod = -1;
426 }
427 }
428
429
430 /* SampleGrabber implementation of IBaseFilter interface */
431
432 /* IUnknown */
433 static HRESULT WINAPI
SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter * iface,REFIID riid,void ** ppv)434 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)
435 {
436 SG_Impl *This = impl_from_IBaseFilter(iface);
437 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
438 }
439
440 /* IUnknown */
441 static ULONG WINAPI
SampleGrabber_IBaseFilter_AddRef(IBaseFilter * iface)442 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
443 {
444 SG_Impl *This = impl_from_IBaseFilter(iface);
445 return IUnknown_AddRef(This->outer_unk);
446 }
447
448 /* IUnknown */
449 static ULONG WINAPI
SampleGrabber_IBaseFilter_Release(IBaseFilter * iface)450 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
451 {
452 SG_Impl *This = impl_from_IBaseFilter(iface);
453 return IUnknown_Release(This->outer_unk);
454 }
455
456 /* IMediaFilter */
457 static HRESULT WINAPI
SampleGrabber_IBaseFilter_Stop(IBaseFilter * iface)458 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
459 {
460 SG_Impl *This = impl_from_IBaseFilter(iface);
461 TRACE("(%p)\n", This);
462 This->filter.state = State_Stopped;
463 return S_OK;
464 }
465
466 /* IMediaFilter */
467 static HRESULT WINAPI
SampleGrabber_IBaseFilter_Pause(IBaseFilter * iface)468 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
469 {
470 SG_Impl *This = impl_from_IBaseFilter(iface);
471 TRACE("(%p)\n", This);
472 This->filter.state = State_Paused;
473 return S_OK;
474 }
475
476 /* IMediaFilter */
477 static HRESULT WINAPI
SampleGrabber_IBaseFilter_Run(IBaseFilter * iface,REFERENCE_TIME tStart)478 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
479 {
480 SG_Impl *This = impl_from_IBaseFilter(iface);
481 TRACE("(%p)\n", This);
482 This->filter.state = State_Running;
483 return S_OK;
484 }
485
486 /* IBaseFilter */
487 static HRESULT WINAPI
SampleGrabber_IBaseFilter_FindPin(IBaseFilter * iface,LPCWSTR id,IPin ** pin)488 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
489 {
490 SG_Impl *This = impl_from_IBaseFilter(iface);
491 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin);
492 if (!id || !pin)
493 return E_POINTER;
494 if (!lstrcmpiW(id,pin_in_name))
495 {
496 *pin = &This->pin_in.IPin_iface;
497 IPin_AddRef(*pin);
498 return S_OK;
499 }
500 else if (!lstrcmpiW(id,pin_out_name))
501 {
502 *pin = &This->pin_out.IPin_iface;
503 IPin_AddRef(*pin);
504 return S_OK;
505 }
506 *pin = NULL;
507 return VFW_E_NOT_FOUND;
508 }
509
510 /* IBaseFilter */
511 static HRESULT WINAPI
SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter * iface,IFilterGraph * graph,LPCWSTR name)512 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
513 {
514 SG_Impl *This = impl_from_IBaseFilter(iface);
515
516 TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
517
518 BaseFilterImpl_JoinFilterGraph(iface, graph, name);
519 This->oneShot = OneShot_None;
520
521 return S_OK;
522 }
523
524 /* IBaseFilter */
525 static HRESULT WINAPI
SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter * iface,LPWSTR * vendor)526 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
527 {
528 TRACE("(%p)\n", vendor);
529 if (!vendor)
530 return E_POINTER;
531 *vendor = CoTaskMemAlloc(sizeof(vendor_name));
532 CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
533 return S_OK;
534 }
535
536
537 /* SampleGrabber implementation of ISampleGrabber interface */
538
539 /* IUnknown */
540 static HRESULT WINAPI
SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber * iface,REFIID riid,void ** ppv)541 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv)
542 {
543 SG_Impl *This = impl_from_ISampleGrabber(iface);
544 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
545 }
546
547 /* IUnknown */
548 static ULONG WINAPI
SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber * iface)549 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
550 {
551 SG_Impl *This = impl_from_ISampleGrabber(iface);
552 return IUnknown_AddRef(This->outer_unk);
553 }
554
555 /* IUnknown */
556 static ULONG WINAPI
SampleGrabber_ISampleGrabber_Release(ISampleGrabber * iface)557 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
558 {
559 SG_Impl *This = impl_from_ISampleGrabber(iface);
560 return IUnknown_Release(This->outer_unk);
561 }
562
563 /* ISampleGrabber */
564 static HRESULT WINAPI
SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber * iface,BOOL oneShot)565 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
566 {
567 SG_Impl *This = impl_from_ISampleGrabber(iface);
568 TRACE("(%p)->(%u)\n", This, oneShot);
569 This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
570 return S_OK;
571 }
572
573 /* ISampleGrabber */
574 static HRESULT WINAPI
SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber * iface,const AM_MEDIA_TYPE * type)575 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
576 {
577 SG_Impl *This = impl_from_ISampleGrabber(iface);
578 TRACE("(%p)->(%p)\n", This, type);
579 if (!type)
580 return E_POINTER;
581 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
582 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
583 type->lSampleSize,
584 debugstr_guid(&type->formattype), type->cbFormat);
585 CoTaskMemFree(This->mtype.pbFormat);
586 This->mtype = *type;
587 This->mtype.pUnk = NULL;
588 if (type->cbFormat) {
589 This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
590 CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat);
591 }
592 else
593 This->mtype.pbFormat = NULL;
594 return S_OK;
595 }
596
597 /* ISampleGrabber */
598 static HRESULT WINAPI
SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber * iface,AM_MEDIA_TYPE * type)599 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
600 {
601 SG_Impl *This = impl_from_ISampleGrabber(iface);
602 TRACE("(%p)->(%p)\n", This, type);
603 if (!type)
604 return E_POINTER;
605 if (!This->pin_in.pair)
606 return VFW_E_NOT_CONNECTED;
607 *type = This->mtype;
608 if (type->cbFormat) {
609 type->pbFormat = CoTaskMemAlloc(type->cbFormat);
610 CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat);
611 }
612 return S_OK;
613 }
614
615 /* ISampleGrabber */
616 static HRESULT WINAPI
SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber * iface,BOOL bufferEm)617 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
618 {
619 SG_Impl *This = impl_from_ISampleGrabber(iface);
620 TRACE("(%p)->(%u)\n", This, bufferEm);
621 EnterCriticalSection(&This->filter.csFilter);
622 if (bufferEm) {
623 if (This->bufferLen < 0)
624 This->bufferLen = 0;
625 }
626 else
627 This->bufferLen = -1;
628 LeaveCriticalSection(&This->filter.csFilter);
629 return S_OK;
630 }
631
632 /* ISampleGrabber */
633 static HRESULT WINAPI
SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber * iface,LONG * bufSize,LONG * buffer)634 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
635 {
636 SG_Impl *This = impl_from_ISampleGrabber(iface);
637 HRESULT ret = S_OK;
638 TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer);
639 if (!bufSize)
640 return E_POINTER;
641 EnterCriticalSection(&This->filter.csFilter);
642 if (!This->pin_in.pair)
643 ret = VFW_E_NOT_CONNECTED;
644 else if (This->bufferLen < 0)
645 ret = E_INVALIDARG;
646 else if (This->bufferLen == 0)
647 ret = VFW_E_WRONG_STATE;
648 else {
649 if (buffer) {
650 if (*bufSize >= This->bufferLen)
651 CopyMemory(buffer, This->bufferData, This->bufferLen);
652 else
653 ret = E_OUTOFMEMORY;
654 }
655 *bufSize = This->bufferLen;
656 }
657 LeaveCriticalSection(&This->filter.csFilter);
658 return ret;
659 }
660
661 /* ISampleGrabber */
662 static HRESULT WINAPI
SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber * iface,IMediaSample ** sample)663 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
664 {
665 /* MS doesn't implement it either, no one should call it */
666 WARN("(%p): not implemented\n", sample);
667 return E_NOTIMPL;
668 }
669
670 /* ISampleGrabber */
671 static HRESULT WINAPI
SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber * iface,ISampleGrabberCB * cb,LONG whichMethod)672 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
673 {
674 SG_Impl *This = impl_from_ISampleGrabber(iface);
675 TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
676 if (This->grabberIface)
677 ISampleGrabberCB_Release(This->grabberIface);
678 This->grabberIface = cb;
679 This->grabberMethod = whichMethod;
680 if (cb)
681 ISampleGrabberCB_AddRef(cb);
682 return S_OK;
683 }
684
685
686 /* SampleGrabber implementation of IMemInputPin interface */
687
688 /* IUnknown */
689 static HRESULT WINAPI
SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin * iface,REFIID riid,void ** ppv)690 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv)
691 {
692 SG_Impl *This = impl_from_IMemInputPin(iface);
693 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
694 }
695
696 /* IUnknown */
697 static ULONG WINAPI
SampleGrabber_IMemInputPin_AddRef(IMemInputPin * iface)698 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
699 {
700 SG_Impl *This = impl_from_IMemInputPin(iface);
701 return IUnknown_AddRef(This->outer_unk);
702 }
703
704 /* IUnknown */
705 static ULONG WINAPI
SampleGrabber_IMemInputPin_Release(IMemInputPin * iface)706 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
707 {
708 SG_Impl *This = impl_from_IMemInputPin(iface);
709 return IUnknown_Release(This->outer_unk);
710 }
711
712 /* IMemInputPin */
713 static HRESULT WINAPI
SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin * iface,IMemAllocator ** allocator)714 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
715 {
716 SG_Impl *This = impl_from_IMemInputPin(iface);
717 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
718 if (!allocator)
719 return E_POINTER;
720 *allocator = This->allocator;
721 if (!*allocator)
722 return VFW_E_NO_ALLOCATOR;
723 IMemAllocator_AddRef(*allocator);
724 return S_OK;
725 }
726
727 /* IMemInputPin */
728 static HRESULT WINAPI
SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin * iface,IMemAllocator * allocator,BOOL readOnly)729 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
730 {
731 SG_Impl *This = impl_from_IMemInputPin(iface);
732 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
733 if (This->allocator == allocator)
734 return S_OK;
735 if (This->allocator)
736 IMemAllocator_Release(This->allocator);
737 This->allocator = allocator;
738 if (allocator)
739 IMemAllocator_AddRef(allocator);
740 return S_OK;
741 }
742
743 /* IMemInputPin */
744 static HRESULT WINAPI
SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin * iface,ALLOCATOR_PROPERTIES * props)745 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
746 {
747 SG_Impl *This = impl_from_IMemInputPin(iface);
748 FIXME("(%p)->(%p): semi-stub\n", This, props);
749 if (!props)
750 return E_POINTER;
751 return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL;
752 }
753
754 /* IMemInputPin */
755 static HRESULT WINAPI
SampleGrabber_IMemInputPin_Receive(IMemInputPin * iface,IMediaSample * sample)756 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
757 {
758 SG_Impl *This = impl_from_IMemInputPin(iface);
759 HRESULT hr;
760 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface);
761 if (!sample)
762 return E_POINTER;
763 if (This->oneShot == OneShot_Past)
764 return S_FALSE;
765 SampleGrabber_callback(This, sample);
766 hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK;
767 if (This->oneShot == OneShot_Wait) {
768 This->oneShot = OneShot_Past;
769 hr = S_FALSE;
770 if (This->pin_out.pair)
771 IPin_EndOfStream(This->pin_out.pair);
772 }
773 return hr;
774 }
775
776 /* IMemInputPin */
777 static HRESULT WINAPI
SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin * iface,IMediaSample ** samples,LONG nSamples,LONG * nProcessed)778 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
779 {
780 SG_Impl *This = impl_from_IMemInputPin(iface);
781 LONG idx;
782 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface);
783 if (!samples || !nProcessed)
784 return E_POINTER;
785 if ((This->filter.state != State_Running) || (This->oneShot == OneShot_Past))
786 return S_FALSE;
787 for (idx = 0; idx < nSamples; idx++)
788 SampleGrabber_callback(This, samples[idx]);
789 return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK;
790 }
791
792 /* IMemInputPin */
793 static HRESULT WINAPI
SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin * iface)794 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
795 {
796 SG_Impl *This = impl_from_IMemInputPin(iface);
797 TRACE("(%p)\n", This);
798 return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK;
799 }
800
801
802 /* SampleGrabber member pin implementation */
803
804 /* IUnknown */
805 static ULONG WINAPI
SampleGrabber_IPin_AddRef(IPin * iface)806 SampleGrabber_IPin_AddRef(IPin *iface)
807 {
808 SG_Pin *This = impl_from_IPin(iface);
809 return ISampleGrabber_AddRef(&This->sg->ISampleGrabber_iface);
810 }
811
812 /* IUnknown */
813 static ULONG WINAPI
SampleGrabber_IPin_Release(IPin * iface)814 SampleGrabber_IPin_Release(IPin *iface)
815 {
816 SG_Pin *This = impl_from_IPin(iface);
817 return ISampleGrabber_Release(&This->sg->ISampleGrabber_iface);
818 }
819
820 /* IUnknown */
821 static HRESULT WINAPI
SampleGrabber_IPin_QueryInterface(IPin * iface,REFIID riid,void ** ppv)822 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
823 {
824 SG_Pin *This = impl_from_IPin(iface);
825 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
826
827 *ppv = NULL;
828 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
829 *ppv = iface;
830 else if (IsEqualIID(riid, &IID_IMemInputPin))
831 *ppv = &This->sg->IMemInputPin_iface;
832 else if (IsEqualIID(riid, &IID_IMediaSeeking))
833 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
834 else if (IsEqualIID(riid, &IID_IMediaPosition))
835 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
836 else {
837 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
838 return E_NOINTERFACE;
839 }
840
841 IUnknown_AddRef((IUnknown*)*ppv);
842 return S_OK;
843 }
844
845 /* IPin - input pin */
846 static HRESULT WINAPI
SampleGrabber_In_IPin_Connect(IPin * iface,IPin * receiver,const AM_MEDIA_TYPE * mtype)847 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype)
848 {
849 WARN("(%p, %p): unexpected\n", receiver, mtype);
850 return E_UNEXPECTED;
851 }
852
853 /* IPin - output pin */
854 static HRESULT WINAPI
SampleGrabber_Out_IPin_Connect(IPin * iface,IPin * receiver,const AM_MEDIA_TYPE * type)855 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type)
856 {
857 SG_Pin *This = impl_from_IPin(iface);
858 HRESULT hr;
859
860 TRACE("(%p)->(%p, %p)\n", This, receiver, type);
861 if (!receiver)
862 return E_POINTER;
863 if (This->pair)
864 return VFW_E_ALREADY_CONNECTED;
865 if (This->sg->filter.state != State_Stopped)
866 return VFW_E_NOT_STOPPED;
867 if (type) {
868 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
869 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
870 type->lSampleSize,
871 debugstr_guid(&type->formattype), type->cbFormat);
872 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
873 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
874 return VFW_E_TYPE_NOT_ACCEPTED;
875 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
876 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
877 return VFW_E_TYPE_NOT_ACCEPTED;
878 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
879 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
880 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
881 return VFW_E_TYPE_NOT_ACCEPTED;
882 }
883 else
884 type = &This->sg->mtype;
885 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
886 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
887 !type->pbFormat)
888 return VFW_E_TYPE_NOT_ACCEPTED;
889 hr = IPin_ReceiveConnection(receiver, &This->IPin_iface, type);
890 if (FAILED(hr))
891 return hr;
892 This->pair = receiver;
893 if (This->sg->memOutput) {
894 IMemInputPin_Release(This->sg->memOutput);
895 This->sg->memOutput = NULL;
896 }
897 IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput));
898 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput);
899 return S_OK;
900 }
901
902 /* IPin - input pin */
903 static HRESULT WINAPI
SampleGrabber_In_IPin_ReceiveConnection(IPin * iface,IPin * connector,const AM_MEDIA_TYPE * type)904 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type)
905 {
906 SG_Pin *This = impl_from_IPin(iface);
907
908 TRACE("(%p)->(%p, %p)\n", This, connector, type);
909 if (!connector)
910 return E_POINTER;
911 if (This->pair)
912 return VFW_E_ALREADY_CONNECTED;
913 if (This->sg->filter.state != State_Stopped)
914 return VFW_E_NOT_STOPPED;
915 if (type) {
916 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
917 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
918 type->lSampleSize,
919 debugstr_guid(&type->formattype), type->cbFormat);
920 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
921 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
922 !type->pbFormat)
923 return VFW_E_INVALIDMEDIATYPE;
924 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
925 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
926 return VFW_E_TYPE_NOT_ACCEPTED;
927 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
928 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
929 return VFW_E_TYPE_NOT_ACCEPTED;
930 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
931 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
932 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
933 return VFW_E_TYPE_NOT_ACCEPTED;
934 CoTaskMemFree(This->sg->mtype.pbFormat);
935 This->sg->mtype = *type;
936 This->sg->mtype.pUnk = NULL;
937 if (type->cbFormat) {
938 This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
939 CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat);
940 }
941 else
942 This->sg->mtype.pbFormat = NULL;
943 }
944 This->pair = connector;
945 TRACE("(%p) Accepted IPin %p\n", This, connector);
946 return S_OK;
947 }
948
949 /* IPin - output pin */
950 static HRESULT WINAPI
SampleGrabber_Out_IPin_ReceiveConnection(IPin * iface,IPin * connector,const AM_MEDIA_TYPE * mtype)951 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype)
952 {
953 WARN("(%p, %p): unexpected\n", connector, mtype);
954 return E_UNEXPECTED;
955 }
956
957 /* IPin - input pin */
958 static HRESULT WINAPI
SampleGrabber_In_IPin_Disconnect(IPin * iface)959 SampleGrabber_In_IPin_Disconnect(IPin *iface)
960 {
961 SG_Pin *This = impl_from_IPin(iface);
962
963 TRACE("(%p)->() pair = %p\n", This, This->pair);
964 if (This->sg->filter.state != State_Stopped)
965 return VFW_E_NOT_STOPPED;
966 if (This->pair) {
967 This->pair = NULL;
968 return S_OK;
969 }
970 return S_FALSE;
971 }
972
973 /* IPin - output pin */
974 static HRESULT WINAPI
SampleGrabber_Out_IPin_Disconnect(IPin * iface)975 SampleGrabber_Out_IPin_Disconnect(IPin *iface)
976 {
977 SG_Pin *This = impl_from_IPin(iface);
978
979 TRACE("(%p)->() pair = %p\n", This, This->pair);
980 if (This->sg->filter.state != State_Stopped)
981 return VFW_E_NOT_STOPPED;
982 if (This->pair) {
983 This->pair = NULL;
984 if (This->sg->memOutput) {
985 IMemInputPin_Release(This->sg->memOutput);
986 This->sg->memOutput = NULL;
987 }
988 return S_OK;
989 }
990 return S_FALSE;
991 }
992
993 /* IPin */
994 static HRESULT WINAPI
SampleGrabber_IPin_ConnectedTo(IPin * iface,IPin ** pin)995 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin)
996 {
997 SG_Pin *This = impl_from_IPin(iface);
998
999 TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair);
1000 if (!pin)
1001 return E_POINTER;
1002 *pin = This->pair;
1003 if (*pin) {
1004 IPin_AddRef(*pin);
1005 return S_OK;
1006 }
1007 return VFW_E_NOT_CONNECTED;
1008 }
1009
1010 /* IPin */
1011 static HRESULT WINAPI
SampleGrabber_IPin_ConnectionMediaType(IPin * iface,AM_MEDIA_TYPE * mtype)1012 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype)
1013 {
1014 SG_Pin *This = impl_from_IPin(iface);
1015
1016 TRACE("(%p)->(%p)\n", This, mtype);
1017 if (!mtype)
1018 return E_POINTER;
1019 if (!This->pair)
1020 return VFW_E_NOT_CONNECTED;
1021 *mtype = This->sg->mtype;
1022 if (mtype->cbFormat) {
1023 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
1024 CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat);
1025 }
1026 return S_OK;
1027 }
1028
1029 /* IPin */
1030 static HRESULT WINAPI
SampleGrabber_IPin_QueryPinInfo(IPin * iface,PIN_INFO * info)1031 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info)
1032 {
1033 SG_Pin *This = impl_from_IPin(iface);
1034
1035 TRACE("(%p)->(%p)\n", This, info);
1036 if (!info)
1037 return E_POINTER;
1038 info->pFilter = &This->sg->filter.IBaseFilter_iface;
1039 IBaseFilter_AddRef(info->pFilter);
1040 info->dir = This->dir;
1041 lstrcpynW(info->achName,This->name,MAX_PIN_NAME);
1042 return S_OK;
1043 }
1044
1045 /* IPin */
1046 static HRESULT WINAPI
SampleGrabber_IPin_QueryDirection(IPin * iface,PIN_DIRECTION * dir)1047 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1048 {
1049 SG_Pin *This = impl_from_IPin(iface);
1050
1051 TRACE("(%p)->(%p)\n", This, dir);
1052 if (!dir)
1053 return E_POINTER;
1054 *dir = This->dir;
1055 return S_OK;
1056 }
1057
1058 /* IPin */
1059 static HRESULT WINAPI
SampleGrabber_IPin_QueryId(IPin * iface,LPWSTR * id)1060 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id)
1061 {
1062 SG_Pin *This = impl_from_IPin(iface);
1063
1064 int len;
1065 TRACE("(%p)->(%p)\n", This, id);
1066 if (!id)
1067 return E_POINTER;
1068 len = sizeof(WCHAR)*(1+lstrlenW(This->name));
1069 *id = CoTaskMemAlloc(len);
1070 CopyMemory(*id, This->name, len);
1071 return S_OK;
1072 }
1073
1074 /* IPin */
1075 static HRESULT WINAPI
SampleGrabber_IPin_QueryAccept(IPin * iface,const AM_MEDIA_TYPE * mtype)1076 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype)
1077 {
1078 TRACE("(%p)\n", mtype);
1079 return S_OK;
1080 }
1081
1082 /* IPin */
1083 static HRESULT WINAPI
SampleGrabber_IPin_EnumMediaTypes(IPin * iface,IEnumMediaTypes ** mtypes)1084 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes)
1085 {
1086 SG_Pin *This = impl_from_IPin(iface);
1087
1088 TRACE("(%p)->(%p)\n", This, mtypes);
1089 if (!mtypes)
1090 return E_POINTER;
1091 *mtypes = mediaenum_create(This->sg->pin_in.pair ? &This->sg->mtype : NULL, FALSE);
1092 return *mtypes ? S_OK : E_OUTOFMEMORY;
1093 }
1094
1095 /* IPin - input pin */
1096 static HRESULT WINAPI
SampleGrabber_In_IPin_QueryInternalConnections(IPin * iface,IPin ** pins,ULONG * nPins)1097 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1098 {
1099 SG_Pin *This = impl_from_IPin(iface);
1100
1101 TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0));
1102 if (!nPins)
1103 return E_POINTER;
1104 if (*nPins) {
1105 if (!pins)
1106 return E_POINTER;
1107 IPin_AddRef(&This->sg->pin_out.IPin_iface);
1108 *pins = &This->sg->pin_out.IPin_iface;
1109 *nPins = 1;
1110 return S_OK;
1111 }
1112 *nPins = 1;
1113 return S_FALSE;
1114 }
1115
1116 /* IPin - output pin */
1117 static HRESULT WINAPI
SampleGrabber_Out_IPin_QueryInternalConnections(IPin * iface,IPin ** pins,ULONG * nPins)1118 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1119 {
1120 WARN("(%p, %p): unexpected\n", pins, nPins);
1121 if (nPins)
1122 *nPins = 0;
1123 return E_NOTIMPL;
1124 }
1125
1126 /* IPin */
1127 static HRESULT WINAPI
SampleGrabber_IPin_EndOfStream(IPin * iface)1128 SampleGrabber_IPin_EndOfStream(IPin *iface)
1129 {
1130 FIXME(": stub\n");
1131 return S_OK;
1132 }
1133
1134 /* IPin */
1135 static HRESULT WINAPI
SampleGrabber_IPin_BeginFlush(IPin * iface)1136 SampleGrabber_IPin_BeginFlush(IPin *iface)
1137 {
1138 FIXME(": stub\n");
1139 return S_OK;
1140 }
1141
1142 /* IPin */
1143 static HRESULT WINAPI
SampleGrabber_IPin_EndFlush(IPin * iface)1144 SampleGrabber_IPin_EndFlush(IPin *iface)
1145 {
1146 FIXME(": stub\n");
1147 return S_OK;
1148 }
1149
1150 /* IPin */
1151 static HRESULT WINAPI
SampleGrabber_IPin_NewSegment(IPin * iface,REFERENCE_TIME tStart,REFERENCE_TIME tStop,double rate)1152 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate)
1153 {
1154 FIXME(": stub\n");
1155 return S_OK;
1156 }
1157
1158
1159 /* SampleGrabber vtables and constructor */
1160
1161 static const IBaseFilterVtbl IBaseFilter_VTable =
1162 {
1163 SampleGrabber_IBaseFilter_QueryInterface,
1164 SampleGrabber_IBaseFilter_AddRef,
1165 SampleGrabber_IBaseFilter_Release,
1166 BaseFilterImpl_GetClassID,
1167 SampleGrabber_IBaseFilter_Stop,
1168 SampleGrabber_IBaseFilter_Pause,
1169 SampleGrabber_IBaseFilter_Run,
1170 BaseFilterImpl_GetState,
1171 BaseFilterImpl_SetSyncSource,
1172 BaseFilterImpl_GetSyncSource,
1173 BaseFilterImpl_EnumPins,
1174 SampleGrabber_IBaseFilter_FindPin,
1175 BaseFilterImpl_QueryFilterInfo,
1176 SampleGrabber_IBaseFilter_JoinFilterGraph,
1177 SampleGrabber_IBaseFilter_QueryVendorInfo,
1178 };
1179
1180 static const ISampleGrabberVtbl ISampleGrabber_VTable =
1181 {
1182 SampleGrabber_ISampleGrabber_QueryInterface,
1183 SampleGrabber_ISampleGrabber_AddRef,
1184 SampleGrabber_ISampleGrabber_Release,
1185 SampleGrabber_ISampleGrabber_SetOneShot,
1186 SampleGrabber_ISampleGrabber_SetMediaType,
1187 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
1188 SampleGrabber_ISampleGrabber_SetBufferSamples,
1189 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
1190 SampleGrabber_ISampleGrabber_GetCurrentSample,
1191 SampleGrabber_ISampleGrabber_SetCallback,
1192 };
1193
1194 static const IMemInputPinVtbl IMemInputPin_VTable =
1195 {
1196 SampleGrabber_IMemInputPin_QueryInterface,
1197 SampleGrabber_IMemInputPin_AddRef,
1198 SampleGrabber_IMemInputPin_Release,
1199 SampleGrabber_IMemInputPin_GetAllocator,
1200 SampleGrabber_IMemInputPin_NotifyAllocator,
1201 SampleGrabber_IMemInputPin_GetAllocatorRequirements,
1202 SampleGrabber_IMemInputPin_Receive,
1203 SampleGrabber_IMemInputPin_ReceiveMultiple,
1204 SampleGrabber_IMemInputPin_ReceiveCanBlock,
1205 };
1206
1207 static const IPinVtbl IPin_In_VTable =
1208 {
1209 SampleGrabber_IPin_QueryInterface,
1210 SampleGrabber_IPin_AddRef,
1211 SampleGrabber_IPin_Release,
1212 SampleGrabber_In_IPin_Connect,
1213 SampleGrabber_In_IPin_ReceiveConnection,
1214 SampleGrabber_In_IPin_Disconnect,
1215 SampleGrabber_IPin_ConnectedTo,
1216 SampleGrabber_IPin_ConnectionMediaType,
1217 SampleGrabber_IPin_QueryPinInfo,
1218 SampleGrabber_IPin_QueryDirection,
1219 SampleGrabber_IPin_QueryId,
1220 SampleGrabber_IPin_QueryAccept,
1221 SampleGrabber_IPin_EnumMediaTypes,
1222 SampleGrabber_In_IPin_QueryInternalConnections,
1223 SampleGrabber_IPin_EndOfStream,
1224 SampleGrabber_IPin_BeginFlush,
1225 SampleGrabber_IPin_EndFlush,
1226 SampleGrabber_IPin_NewSegment,
1227 };
1228
1229 static const IPinVtbl IPin_Out_VTable =
1230 {
1231 SampleGrabber_IPin_QueryInterface,
1232 SampleGrabber_IPin_AddRef,
1233 SampleGrabber_IPin_Release,
1234 SampleGrabber_Out_IPin_Connect,
1235 SampleGrabber_Out_IPin_ReceiveConnection,
1236 SampleGrabber_Out_IPin_Disconnect,
1237 SampleGrabber_IPin_ConnectedTo,
1238 SampleGrabber_IPin_ConnectionMediaType,
1239 SampleGrabber_IPin_QueryPinInfo,
1240 SampleGrabber_IPin_QueryDirection,
1241 SampleGrabber_IPin_QueryId,
1242 SampleGrabber_IPin_QueryAccept,
1243 SampleGrabber_IPin_EnumMediaTypes,
1244 SampleGrabber_Out_IPin_QueryInternalConnections,
1245 SampleGrabber_IPin_EndOfStream,
1246 SampleGrabber_IPin_BeginFlush,
1247 SampleGrabber_IPin_EndFlush,
1248 SampleGrabber_IPin_NewSegment,
1249 };
1250
SampleGrabber_create(IUnknown * pUnkOuter,LPVOID * ppv)1251 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
1252 {
1253 SG_Impl* obj = NULL;
1254 ISeekingPassThru *passthru;
1255 HRESULT hr;
1256
1257 TRACE("(%p,%p)\n", pUnkOuter, ppv);
1258
1259 obj = CoTaskMemAlloc(sizeof(SG_Impl));
1260 if (NULL == obj) {
1261 *ppv = NULL;
1262 return E_OUTOFMEMORY;
1263 }
1264 ZeroMemory(obj, sizeof(SG_Impl));
1265
1266 BaseFilter_Init(&obj->filter, &IBaseFilter_VTable, &CLSID_SampleGrabber,
1267 (DWORD_PTR)(__FILE__ ": SG_Impl.csFilter"), &basefunc_vtbl);
1268 obj->IUnknown_inner.lpVtbl = &samplegrabber_vtbl;
1269 obj->ISampleGrabber_iface.lpVtbl = &ISampleGrabber_VTable;
1270 obj->IMemInputPin_iface.lpVtbl = &IMemInputPin_VTable;
1271 obj->pin_in.IPin_iface.lpVtbl = &IPin_In_VTable;
1272 obj->pin_in.dir = PINDIR_INPUT;
1273 obj->pin_in.name = pin_in_name;
1274 obj->pin_in.sg = obj;
1275 obj->pin_in.pair = NULL;
1276 obj->pin_out.IPin_iface.lpVtbl = &IPin_Out_VTable;
1277 obj->pin_out.dir = PINDIR_OUTPUT;
1278 obj->pin_out.name = pin_out_name;
1279 obj->pin_out.sg = obj;
1280 obj->pin_out.pair = NULL;
1281 obj->mtype.majortype = GUID_NULL;
1282 obj->mtype.subtype = MEDIASUBTYPE_None;
1283 obj->mtype.formattype = FORMAT_None;
1284 obj->allocator = NULL;
1285 obj->memOutput = NULL;
1286 obj->grabberIface = NULL;
1287 obj->grabberMethod = -1;
1288 obj->oneShot = OneShot_None;
1289 obj->bufferLen = -1;
1290 obj->bufferData = NULL;
1291
1292 if (pUnkOuter)
1293 obj->outer_unk = pUnkOuter;
1294 else
1295 obj->outer_unk = &obj->IUnknown_inner;
1296
1297 hr = CoCreateInstance(&CLSID_SeekingPassThru, &obj->IUnknown_inner, CLSCTX_INPROC_SERVER,
1298 &IID_IUnknown, (void**)&obj->seekthru_unk);
1299 if(hr)
1300 return hr;
1301 IUnknown_QueryInterface(obj->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
1302 ISeekingPassThru_Init(passthru, FALSE, &obj->pin_in.IPin_iface);
1303 ISeekingPassThru_Release(passthru);
1304
1305 *ppv = &obj->IUnknown_inner;
1306 return S_OK;
1307 }
1308