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