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