Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/strmbase/pin.c
8724 views
1
/*
2
* Generic Implementation of IPin Interface
3
*
4
* Copyright 2003 Robert Shearman
5
* Copyright 2010 Aric Stewart, CodeWeavers
6
*
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
11
*
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
16
*
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20
*/
21
22
#define COBJMACROS
23
#include "wine/strmbase.h"
24
#include "wine/debug.h"
25
26
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
27
28
static const IMemInputPinVtbl MemInputPin_Vtbl;
29
30
typedef HRESULT (*SendPinFunc)( IPin *to, LPVOID arg );
31
32
struct enum_media_types
33
{
34
IEnumMediaTypes IEnumMediaTypes_iface;
35
LONG refcount;
36
37
unsigned int index, count;
38
struct strmbase_pin *pin;
39
};
40
41
static const IEnumMediaTypesVtbl enum_media_types_vtbl;
42
43
static HRESULT enum_media_types_create(struct strmbase_pin *pin, IEnumMediaTypes **out)
44
{
45
struct enum_media_types *object;
46
AM_MEDIA_TYPE mt;
47
48
if (!out)
49
return E_POINTER;
50
51
if (!(object = calloc(1, sizeof(*object))))
52
{
53
*out = NULL;
54
return E_OUTOFMEMORY;
55
}
56
57
object->IEnumMediaTypes_iface.lpVtbl = &enum_media_types_vtbl;
58
object->refcount = 1;
59
object->pin = pin;
60
IPin_AddRef(&pin->IPin_iface);
61
62
if (pin->ops->pin_get_media_type)
63
{
64
while (pin->ops->pin_get_media_type(pin, object->count, &mt) == S_OK)
65
{
66
FreeMediaType(&mt);
67
++object->count;
68
}
69
}
70
71
TRACE("Created enumerator %p.\n", object);
72
*out = &object->IEnumMediaTypes_iface;
73
74
return S_OK;
75
}
76
77
static struct enum_media_types *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
78
{
79
return CONTAINING_RECORD(iface, struct enum_media_types, IEnumMediaTypes_iface);
80
}
81
82
static HRESULT WINAPI enum_media_types_QueryInterface(IEnumMediaTypes *iface, REFIID iid, void **out)
83
{
84
TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
85
86
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumMediaTypes))
87
{
88
IEnumMediaTypes_AddRef(iface);
89
*out = iface;
90
return S_OK;
91
}
92
93
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
94
*out = NULL;
95
return E_NOINTERFACE;
96
}
97
98
static ULONG WINAPI enum_media_types_AddRef(IEnumMediaTypes *iface)
99
{
100
struct enum_media_types *enummt = impl_from_IEnumMediaTypes(iface);
101
ULONG refcount = InterlockedIncrement(&enummt->refcount);
102
TRACE("%p increasing refcount to %lu.\n", enummt, refcount);
103
return refcount;
104
}
105
106
static ULONG WINAPI enum_media_types_Release(IEnumMediaTypes *iface)
107
{
108
struct enum_media_types *enummt = impl_from_IEnumMediaTypes(iface);
109
ULONG refcount = InterlockedDecrement(&enummt->refcount);
110
111
TRACE("%p decreasing refcount to %lu.\n", enummt, refcount);
112
if (!refcount)
113
{
114
IPin_Release(&enummt->pin->IPin_iface);
115
free(enummt);
116
}
117
return refcount;
118
}
119
120
static HRESULT WINAPI enum_media_types_Next(IEnumMediaTypes *iface, ULONG count,
121
AM_MEDIA_TYPE **mts, ULONG *ret_count)
122
{
123
struct enum_media_types *enummt = impl_from_IEnumMediaTypes(iface);
124
AM_MEDIA_TYPE mt;
125
unsigned int i;
126
HRESULT hr;
127
128
TRACE("enummt %p, count %lu, mts %p, ret_count %p.\n", enummt, count, mts, ret_count);
129
130
if (!enummt->pin->ops->pin_get_media_type)
131
{
132
if (ret_count)
133
*ret_count = 0;
134
return count ? S_FALSE : S_OK;
135
}
136
137
for (i = 0; i < count; ++i)
138
{
139
hr = enummt->pin->ops->pin_get_media_type(enummt->pin, enummt->index + i, &mt);
140
if (hr == S_OK)
141
{
142
if ((mts[i] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
143
*mts[i] = mt;
144
else
145
hr = E_OUTOFMEMORY;
146
}
147
if (FAILED(hr))
148
{
149
while (i--)
150
DeleteMediaType(mts[i]);
151
*ret_count = 0;
152
return E_OUTOFMEMORY;
153
}
154
else if (hr != S_OK)
155
break;
156
157
if (TRACE_ON(quartz))
158
{
159
TRACE("Returning media type %u:\n", enummt->index + i);
160
strmbase_dump_media_type(mts[i]);
161
}
162
}
163
164
if (count != 1 || ret_count)
165
*ret_count = i;
166
enummt->index += i;
167
return i == count ? S_OK : S_FALSE;
168
}
169
170
static HRESULT WINAPI enum_media_types_Skip(IEnumMediaTypes *iface, ULONG count)
171
{
172
struct enum_media_types *enummt = impl_from_IEnumMediaTypes(iface);
173
174
TRACE("enummt %p, count %lu.\n", enummt, count);
175
176
enummt->index += count;
177
178
return enummt->index > enummt->count ? S_FALSE : S_OK;
179
}
180
181
static HRESULT WINAPI enum_media_types_Reset(IEnumMediaTypes *iface)
182
{
183
struct enum_media_types *enummt = impl_from_IEnumMediaTypes(iface);
184
AM_MEDIA_TYPE mt;
185
186
TRACE("enummt %p.\n", enummt);
187
188
enummt->count = 0;
189
if (enummt->pin->ops->pin_get_media_type)
190
{
191
while (enummt->pin->ops->pin_get_media_type(enummt->pin, enummt->count, &mt) == S_OK)
192
{
193
FreeMediaType(&mt);
194
++enummt->count;
195
}
196
}
197
198
enummt->index = 0;
199
200
return S_OK;
201
}
202
203
static HRESULT WINAPI enum_media_types_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **out)
204
{
205
struct enum_media_types *enummt = impl_from_IEnumMediaTypes(iface);
206
HRESULT hr;
207
208
TRACE("enummt %p, out %p.\n", enummt, out);
209
210
if (FAILED(hr = enum_media_types_create(enummt->pin, out)))
211
return hr;
212
return IEnumMediaTypes_Skip(*out, enummt->index);
213
}
214
215
static const IEnumMediaTypesVtbl enum_media_types_vtbl =
216
{
217
enum_media_types_QueryInterface,
218
enum_media_types_AddRef,
219
enum_media_types_Release,
220
enum_media_types_Next,
221
enum_media_types_Skip,
222
enum_media_types_Reset,
223
enum_media_types_Clone,
224
};
225
226
static inline struct strmbase_pin *impl_from_IPin(IPin *iface)
227
{
228
return CONTAINING_RECORD(iface, struct strmbase_pin, IPin_iface);
229
}
230
231
/** Helper function, there are a lot of places where the error code is inherited
232
* The following rules apply:
233
*
234
* Return the first received error code (E_NOTIMPL is ignored)
235
* If no errors occur: return the first received non-error-code that isn't S_OK
236
*/
237
static HRESULT updatehres( HRESULT original, HRESULT new )
238
{
239
if (FAILED( original ) || new == E_NOTIMPL)
240
return original;
241
242
if (FAILED( new ) || original == S_OK)
243
return new;
244
245
return original;
246
}
247
248
/** Sends a message from a pin further to other, similar pins
249
* fnMiddle is called on each pin found further on the stream.
250
* fnEnd (can be NULL) is called when the message can't be sent any further (this is a renderer or source)
251
*
252
* If the pin given is an input pin, the message will be sent downstream to other input pins
253
* If the pin given is an output pin, the message will be sent upstream to other output pins
254
*/
255
static HRESULT SendFurther(struct strmbase_sink *sink, SendPinFunc func, void *arg)
256
{
257
struct strmbase_pin *pin;
258
HRESULT hr = S_OK;
259
unsigned int i;
260
261
for (i = 0; (pin = sink->pin.filter->ops->filter_get_pin(sink->pin.filter, i)); ++i)
262
{
263
if (pin->dir == PINDIR_OUTPUT && pin->peer)
264
hr = updatehres(hr, func(pin->peer, arg));
265
}
266
267
return hr;
268
}
269
270
static HRESULT WINAPI pin_QueryInterface(IPin *iface, REFIID iid, void **out)
271
{
272
struct strmbase_pin *pin = impl_from_IPin(iface);
273
HRESULT hr;
274
275
TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
276
277
*out = NULL;
278
279
if (pin->ops->pin_query_interface && SUCCEEDED(hr = pin->ops->pin_query_interface(pin, iid, out)))
280
return hr;
281
282
if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IPin))
283
*out = iface;
284
else
285
{
286
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
287
return E_NOINTERFACE;
288
}
289
290
IUnknown_AddRef((IUnknown *)*out);
291
return S_OK;
292
}
293
294
static ULONG WINAPI pin_AddRef(IPin *iface)
295
{
296
struct strmbase_pin *pin = impl_from_IPin(iface);
297
return IBaseFilter_AddRef(&pin->filter->IBaseFilter_iface);
298
}
299
300
static ULONG WINAPI pin_Release(IPin *iface)
301
{
302
struct strmbase_pin *pin = impl_from_IPin(iface);
303
return IBaseFilter_Release(&pin->filter->IBaseFilter_iface);
304
}
305
306
static HRESULT WINAPI pin_ConnectedTo(IPin * iface, IPin ** ppPin)
307
{
308
struct strmbase_pin *This = impl_from_IPin(iface);
309
HRESULT hr;
310
311
TRACE("pin %p %s:%s, peer %p.\n", This, debugstr_w(This->filter->name), debugstr_w(This->name), ppPin);
312
313
EnterCriticalSection(&This->filter->filter_cs);
314
{
315
if (This->peer)
316
{
317
*ppPin = This->peer;
318
IPin_AddRef(*ppPin);
319
hr = S_OK;
320
}
321
else
322
{
323
hr = VFW_E_NOT_CONNECTED;
324
*ppPin = NULL;
325
}
326
}
327
LeaveCriticalSection(&This->filter->filter_cs);
328
329
return hr;
330
}
331
332
static HRESULT WINAPI pin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
333
{
334
struct strmbase_pin *This = impl_from_IPin(iface);
335
HRESULT hr;
336
337
TRACE("pin %p %s:%s, pmt %p.\n", This, debugstr_w(This->filter->name), debugstr_w(This->name), pmt);
338
339
EnterCriticalSection(&This->filter->filter_cs);
340
{
341
if (This->peer)
342
{
343
CopyMediaType(pmt, &This->mt);
344
strmbase_dump_media_type(pmt);
345
hr = S_OK;
346
}
347
else
348
{
349
ZeroMemory(pmt, sizeof(*pmt));
350
hr = VFW_E_NOT_CONNECTED;
351
}
352
}
353
LeaveCriticalSection(&This->filter->filter_cs);
354
355
return hr;
356
}
357
358
static HRESULT WINAPI pin_QueryPinInfo(IPin *iface, PIN_INFO *info)
359
{
360
struct strmbase_pin *pin = impl_from_IPin(iface);
361
362
TRACE("pin %p %s:%s, info %p.\n", pin, debugstr_w(pin->filter->name), debugstr_w(pin->name), info);
363
364
info->dir = pin->dir;
365
IBaseFilter_AddRef(info->pFilter = &pin->filter->IBaseFilter_iface);
366
lstrcpyW(info->achName, pin->name);
367
368
return S_OK;
369
}
370
371
static HRESULT WINAPI pin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
372
{
373
struct strmbase_pin *pin = impl_from_IPin(iface);
374
375
TRACE("pin %p %s:%s, dir %p.\n", pin, debugstr_w(pin->filter->name), debugstr_w(pin->name), dir);
376
377
*dir = pin->dir;
378
379
return S_OK;
380
}
381
382
static HRESULT WINAPI pin_QueryId(IPin *iface, WCHAR **id)
383
{
384
struct strmbase_pin *pin = impl_from_IPin(iface);
385
386
TRACE("pin %p %s:%s, id %p.\n", pin, debugstr_w(pin->filter->name), debugstr_w(pin->name), id);
387
388
if (!(*id = CoTaskMemAlloc((lstrlenW(pin->id) + 1) * sizeof(WCHAR))))
389
return E_OUTOFMEMORY;
390
391
lstrcpyW(*id, pin->id);
392
393
return S_OK;
394
}
395
396
static BOOL query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
397
{
398
if (pin->ops->pin_query_accept && pin->ops->pin_query_accept(pin, mt) != S_OK)
399
return FALSE;
400
return TRUE;
401
}
402
403
static HRESULT WINAPI pin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt)
404
{
405
struct strmbase_pin *pin = impl_from_IPin(iface);
406
407
TRACE("pin %p %s:%s, mt %p.\n", pin, debugstr_w(pin->filter->name), debugstr_w(pin->name), mt);
408
strmbase_dump_media_type(mt);
409
410
return query_accept(pin, mt) ? S_OK : S_FALSE;
411
}
412
413
static HRESULT WINAPI pin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **enum_media_types)
414
{
415
struct strmbase_pin *pin = impl_from_IPin(iface);
416
AM_MEDIA_TYPE mt;
417
HRESULT hr;
418
419
TRACE("pin %p %s:%s, enum_media_types %p.\n", pin, debugstr_w(pin->filter->name),
420
debugstr_w(pin->name), enum_media_types);
421
422
if (pin->ops->pin_get_media_type)
423
{
424
if (FAILED(hr = pin->ops->pin_get_media_type(pin, 0, &mt)))
425
return hr;
426
if (hr == S_OK)
427
FreeMediaType(&mt);
428
}
429
430
return enum_media_types_create(pin, enum_media_types);
431
}
432
433
static HRESULT WINAPI pin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *count)
434
{
435
struct strmbase_pin *pin = impl_from_IPin(iface);
436
437
TRACE("pin %p %s:%s, pins %p, count %p.\n", pin, debugstr_w(pin->filter->name),
438
debugstr_w(pin->name), pins, count);
439
440
return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
441
}
442
443
/*** OutputPin implementation ***/
444
445
static inline struct strmbase_source *impl_source_from_IPin( IPin *iface )
446
{
447
return CONTAINING_RECORD(iface, struct strmbase_source, pin.IPin_iface);
448
}
449
450
static BOOL compare_media_types(const AM_MEDIA_TYPE *req_mt, const AM_MEDIA_TYPE *pin_mt)
451
{
452
if (!req_mt)
453
return TRUE;
454
455
if (!IsEqualGUID(&req_mt->majortype, &pin_mt->majortype)
456
&& !IsEqualGUID(&req_mt->majortype, &GUID_NULL))
457
return FALSE;
458
459
if (!IsEqualGUID(&req_mt->subtype, &pin_mt->subtype)
460
&& !IsEqualGUID(&req_mt->subtype, &GUID_NULL))
461
return FALSE;
462
463
if (!IsEqualGUID(&req_mt->formattype, &pin_mt->formattype)
464
&& !IsEqualGUID(&req_mt->formattype, &GUID_NULL))
465
return FALSE;
466
467
return TRUE;
468
}
469
470
static HRESULT WINAPI source_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
471
{
472
struct strmbase_source *pin = impl_source_from_IPin(iface);
473
AM_MEDIA_TYPE candidate, *candidate_ptr;
474
IEnumMediaTypes *enummt;
475
PIN_DIRECTION dir;
476
unsigned int i;
477
ULONG count;
478
HRESULT hr;
479
480
TRACE("pin %p %s:%s, peer %p, mt %p.\n", pin, debugstr_w(pin->pin.filter->name),
481
debugstr_w(pin->pin.name), peer, mt);
482
strmbase_dump_media_type(mt);
483
484
if (!peer)
485
return E_POINTER;
486
487
IPin_QueryDirection(peer, &dir);
488
if (dir != PINDIR_INPUT)
489
{
490
WARN("Attempt to connect to another source pin, returning VFW_E_INVALID_DIRECTION.\n");
491
return VFW_E_INVALID_DIRECTION;
492
}
493
494
EnterCriticalSection(&pin->pin.filter->filter_cs);
495
496
if (pin->pin.peer)
497
{
498
LeaveCriticalSection(&pin->pin.filter->filter_cs);
499
WARN("Pin is already connected, returning VFW_E_ALREADY_CONNECTED.\n");
500
return VFW_E_ALREADY_CONNECTED;
501
}
502
503
if (pin->pin.filter->state != State_Stopped)
504
{
505
LeaveCriticalSection(&pin->pin.filter->filter_cs);
506
WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
507
return VFW_E_NOT_STOPPED;
508
}
509
510
/* We don't check the subtype here. The rationale (as given by the DirectX
511
* documentation) is that the format type is supposed to provide at least
512
* as much information as the subtype. */
513
if (mt && !IsEqualGUID(&mt->majortype, &GUID_NULL)
514
&& !IsEqualGUID(&mt->formattype, &GUID_NULL))
515
{
516
hr = pin->pFuncsTable->pfnAttemptConnection(pin, peer, mt);
517
LeaveCriticalSection(&pin->pin.filter->filter_cs);
518
return hr;
519
}
520
521
if (SUCCEEDED(IPin_EnumMediaTypes(peer, &enummt)))
522
{
523
while (IEnumMediaTypes_Next(enummt, 1, &candidate_ptr, &count) == S_OK)
524
{
525
if (compare_media_types(mt, candidate_ptr)
526
&& pin->pFuncsTable->pfnAttemptConnection(pin, peer, candidate_ptr) == S_OK)
527
{
528
LeaveCriticalSection(&pin->pin.filter->filter_cs);
529
DeleteMediaType(candidate_ptr);
530
IEnumMediaTypes_Release(enummt);
531
return S_OK;
532
}
533
DeleteMediaType(candidate_ptr);
534
}
535
536
IEnumMediaTypes_Release(enummt);
537
}
538
539
if (pin->pFuncsTable->base.pin_get_media_type)
540
{
541
for (i = 0; pin->pFuncsTable->base.pin_get_media_type(&pin->pin, i, &candidate) == S_OK; ++i)
542
{
543
strmbase_dump_media_type(&candidate);
544
if (compare_media_types(mt, &candidate)
545
&& pin->pFuncsTable->pfnAttemptConnection(pin, peer, &candidate) == S_OK)
546
{
547
LeaveCriticalSection(&pin->pin.filter->filter_cs);
548
FreeMediaType(&candidate);
549
return S_OK;
550
}
551
FreeMediaType(&candidate);
552
}
553
}
554
555
LeaveCriticalSection(&pin->pin.filter->filter_cs);
556
557
return VFW_E_NO_ACCEPTABLE_TYPES;
558
}
559
560
static HRESULT WINAPI source_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
561
{
562
struct strmbase_source *pin = impl_source_from_IPin(iface);
563
564
WARN("pin %p %s:%s, peer %p, mt %p, unexpected call.\n", pin,
565
debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name), peer, mt);
566
567
return E_UNEXPECTED;
568
}
569
570
static HRESULT WINAPI source_Disconnect(IPin *iface)
571
{
572
HRESULT hr;
573
struct strmbase_source *This = impl_source_from_IPin(iface);
574
575
TRACE("pin %p %s:%s.\n", This, debugstr_w(This->pin.filter->name), debugstr_w(This->pin.name));
576
577
EnterCriticalSection(&This->pin.filter->filter_cs);
578
{
579
if (This->pin.filter->state != State_Stopped)
580
{
581
LeaveCriticalSection(&This->pin.filter->filter_cs);
582
WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
583
return VFW_E_NOT_STOPPED;
584
}
585
586
if (This->pFuncsTable->source_disconnect)
587
This->pFuncsTable->source_disconnect(This);
588
589
if (This->pMemInputPin)
590
{
591
IMemInputPin_Release(This->pMemInputPin);
592
This->pMemInputPin = NULL;
593
}
594
595
if (This->pAllocator)
596
{
597
IMemAllocator_Release(This->pAllocator);
598
This->pAllocator = NULL;
599
}
600
601
if (This->pin.peer)
602
{
603
IPin_Release(This->pin.peer);
604
This->pin.peer = NULL;
605
FreeMediaType(&This->pin.mt);
606
ZeroMemory(&This->pin.mt, sizeof(This->pin.mt));
607
hr = S_OK;
608
}
609
else
610
hr = S_FALSE;
611
}
612
LeaveCriticalSection(&This->pin.filter->filter_cs);
613
614
return hr;
615
}
616
617
static HRESULT WINAPI source_EndOfStream(IPin *iface)
618
{
619
struct strmbase_source *pin = impl_source_from_IPin(iface);
620
621
WARN("pin %p %s:%s, unexpected call.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
622
623
/* not supposed to do anything in an output pin */
624
625
return E_UNEXPECTED;
626
}
627
628
static HRESULT WINAPI source_BeginFlush(IPin *iface)
629
{
630
struct strmbase_source *pin = impl_source_from_IPin(iface);
631
632
WARN("pin %p %s:%s, unexpected call.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
633
634
/* not supposed to do anything in an output pin */
635
636
return E_UNEXPECTED;
637
}
638
639
static HRESULT WINAPI source_EndFlush(IPin *iface)
640
{
641
struct strmbase_source *pin = impl_source_from_IPin(iface);
642
643
WARN("pin %p %s:%s, unexpected call.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
644
645
/* not supposed to do anything in an output pin */
646
647
return E_UNEXPECTED;
648
}
649
650
static HRESULT WINAPI source_NewSegment(IPin * iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
651
{
652
struct strmbase_source *pin = impl_source_from_IPin(iface);
653
654
TRACE("pin %p %s:%s, start %s, stop %s, rate %.16e.\n", pin, debugstr_w(pin->pin.filter->name),
655
debugstr_w(pin->pin.name), debugstr_time(start), debugstr_time(stop), rate);
656
657
return S_OK;
658
}
659
660
static const IPinVtbl source_vtbl =
661
{
662
pin_QueryInterface,
663
pin_AddRef,
664
pin_Release,
665
source_Connect,
666
source_ReceiveConnection,
667
source_Disconnect,
668
pin_ConnectedTo,
669
pin_ConnectionMediaType,
670
pin_QueryPinInfo,
671
pin_QueryDirection,
672
pin_QueryId,
673
pin_QueryAccept,
674
pin_EnumMediaTypes,
675
pin_QueryInternalConnections,
676
source_EndOfStream,
677
source_BeginFlush,
678
source_EndFlush,
679
source_NewSegment,
680
};
681
682
HRESULT WINAPI BaseOutputPinImpl_DecideAllocator(struct strmbase_source *This,
683
IMemInputPin *pPin, IMemAllocator **pAlloc)
684
{
685
HRESULT hr;
686
687
hr = IMemInputPin_GetAllocator(pPin, pAlloc);
688
689
if (hr == VFW_E_NO_ALLOCATOR)
690
hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL,
691
CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (void **)pAlloc);
692
693
if (SUCCEEDED(hr))
694
{
695
ALLOCATOR_PROPERTIES rProps;
696
ZeroMemory(&rProps, sizeof(ALLOCATOR_PROPERTIES));
697
698
IMemInputPin_GetAllocatorRequirements(pPin, &rProps);
699
hr = This->pFuncsTable->pfnDecideBufferSize(This, *pAlloc, &rProps);
700
}
701
702
if (SUCCEEDED(hr))
703
hr = IMemInputPin_NotifyAllocator(pPin, *pAlloc, FALSE);
704
705
return hr;
706
}
707
708
/*** The Construct functions ***/
709
710
/* Function called as a helper to IPin_Connect */
711
/* specific AM_MEDIA_TYPE - it cannot be NULL */
712
HRESULT WINAPI BaseOutputPinImpl_AttemptConnection(struct strmbase_source *This,
713
IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
714
{
715
HRESULT hr;
716
IMemAllocator * pMemAlloc = NULL;
717
718
TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
719
720
if (!query_accept(&This->pin, pmt))
721
return VFW_E_TYPE_NOT_ACCEPTED;
722
723
This->pin.peer = pReceivePin;
724
IPin_AddRef(pReceivePin);
725
CopyMediaType(&This->pin.mt, pmt);
726
727
hr = IPin_ReceiveConnection(pReceivePin, &This->pin.IPin_iface, pmt);
728
729
/* get the IMemInputPin interface we will use to deliver samples to the
730
* connected pin */
731
if (SUCCEEDED(hr))
732
{
733
This->pMemInputPin = NULL;
734
hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
735
736
if (SUCCEEDED(hr))
737
{
738
hr = This->pFuncsTable->pfnDecideAllocator(This, This->pMemInputPin, &pMemAlloc);
739
if (SUCCEEDED(hr))
740
This->pAllocator = pMemAlloc;
741
else if (pMemAlloc)
742
IMemAllocator_Release(pMemAlloc);
743
}
744
745
/* break connection if we couldn't get the allocator */
746
if (FAILED(hr))
747
{
748
if (This->pMemInputPin)
749
IMemInputPin_Release(This->pMemInputPin);
750
This->pMemInputPin = NULL;
751
752
IPin_Disconnect(pReceivePin);
753
}
754
}
755
756
if (FAILED(hr))
757
{
758
IPin_Release(This->pin.peer);
759
This->pin.peer = NULL;
760
FreeMediaType(&This->pin.mt);
761
}
762
763
TRACE("Returning %#lx.\n", hr);
764
return hr;
765
}
766
767
void strmbase_source_init(struct strmbase_source *pin, struct strmbase_filter *filter,
768
const WCHAR *name, const struct strmbase_source_ops *func_table)
769
{
770
memset(pin, 0, sizeof(*pin));
771
pin->pin.IPin_iface.lpVtbl = &source_vtbl;
772
pin->pin.filter = filter;
773
pin->pin.dir = PINDIR_OUTPUT;
774
lstrcpyW(pin->pin.name, name);
775
lstrcpyW(pin->pin.id, name);
776
pin->pin.ops = &func_table->base;
777
pin->pFuncsTable = func_table;
778
}
779
780
void strmbase_source_cleanup(struct strmbase_source *pin)
781
{
782
FreeMediaType(&pin->pin.mt);
783
if (pin->pAllocator)
784
IMemAllocator_Release(pin->pAllocator);
785
pin->pAllocator = NULL;
786
}
787
788
static struct strmbase_sink *impl_sink_from_IPin(IPin *iface)
789
{
790
return CONTAINING_RECORD(iface, struct strmbase_sink, pin.IPin_iface);
791
}
792
793
static HRESULT WINAPI sink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
794
{
795
struct strmbase_sink *pin = impl_sink_from_IPin(iface);
796
797
WARN("pin %p %s:%s, peer %p, mt %p, unexpected call.\n", pin, debugstr_w(pin->pin.name),
798
debugstr_w(pin->pin.filter->name), peer, mt);
799
800
return E_UNEXPECTED;
801
}
802
803
804
static HRESULT WINAPI sink_ReceiveConnection(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
805
{
806
struct strmbase_sink *This = impl_sink_from_IPin(iface);
807
PIN_DIRECTION pindirReceive;
808
HRESULT hr = S_OK;
809
810
TRACE("pin %p %s:%s, peer %p, mt %p.\n", This, debugstr_w(This->pin.filter->name),
811
debugstr_w(This->pin.name), pReceivePin, pmt);
812
strmbase_dump_media_type(pmt);
813
814
if (!pmt)
815
return E_POINTER;
816
817
EnterCriticalSection(&This->pin.filter->filter_cs);
818
{
819
if (This->pin.filter->state != State_Stopped)
820
{
821
LeaveCriticalSection(&This->pin.filter->filter_cs);
822
WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
823
return VFW_E_NOT_STOPPED;
824
}
825
826
if (This->pin.peer)
827
hr = VFW_E_ALREADY_CONNECTED;
828
829
if (SUCCEEDED(hr) && !query_accept(&This->pin, pmt))
830
hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto
831
* VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
832
833
if (SUCCEEDED(hr))
834
{
835
IPin_QueryDirection(pReceivePin, &pindirReceive);
836
837
if (pindirReceive != PINDIR_OUTPUT)
838
{
839
ERR("Can't connect from non-output pin\n");
840
hr = VFW_E_INVALID_DIRECTION;
841
}
842
}
843
844
if (SUCCEEDED(hr) && This->pFuncsTable->sink_connect)
845
hr = This->pFuncsTable->sink_connect(This, pReceivePin, pmt);
846
847
if (SUCCEEDED(hr))
848
{
849
CopyMediaType(&This->pin.mt, pmt);
850
This->pin.peer = pReceivePin;
851
IPin_AddRef(pReceivePin);
852
}
853
}
854
LeaveCriticalSection(&This->pin.filter->filter_cs);
855
856
return hr;
857
}
858
859
static HRESULT WINAPI sink_Disconnect(IPin *iface)
860
{
861
struct strmbase_sink *pin = impl_sink_from_IPin(iface);
862
HRESULT hr;
863
864
TRACE("pin %p %s:%s.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
865
866
EnterCriticalSection(&pin->pin.filter->filter_cs);
867
868
if (pin->pin.filter->state != State_Stopped)
869
{
870
LeaveCriticalSection(&pin->pin.filter->filter_cs);
871
WARN("Filter is not stopped; returning VFW_E_NOT_STOPPED.\n");
872
return VFW_E_NOT_STOPPED;
873
}
874
875
if (pin->pin.peer)
876
{
877
if (pin->pFuncsTable->sink_disconnect)
878
pin->pFuncsTable->sink_disconnect(pin);
879
880
if (pin->pAllocator)
881
{
882
IMemAllocator_Release(pin->pAllocator);
883
pin->pAllocator = NULL;
884
}
885
886
IPin_Release(pin->pin.peer);
887
pin->pin.peer = NULL;
888
FreeMediaType(&pin->pin.mt);
889
memset(&pin->pin.mt, 0, sizeof(AM_MEDIA_TYPE));
890
hr = S_OK;
891
}
892
else
893
hr = S_FALSE;
894
895
LeaveCriticalSection(&pin->pin.filter->filter_cs);
896
897
return hr;
898
}
899
900
static HRESULT deliver_endofstream(IPin* pin, LPVOID unused)
901
{
902
return IPin_EndOfStream( pin );
903
}
904
905
static HRESULT WINAPI sink_EndOfStream(IPin *iface)
906
{
907
struct strmbase_sink *pin = impl_sink_from_IPin(iface);
908
HRESULT hr = S_OK;
909
910
TRACE("pin %p %s:%s.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
911
912
if (pin->pFuncsTable->sink_eos)
913
{
914
EnterCriticalSection(&pin->pin.filter->stream_cs);
915
hr = pin->pFuncsTable->sink_eos(pin);
916
LeaveCriticalSection(&pin->pin.filter->stream_cs);
917
return hr;
918
}
919
920
EnterCriticalSection(&pin->pin.filter->filter_cs);
921
if (pin->flushing)
922
hr = S_FALSE;
923
LeaveCriticalSection(&pin->pin.filter->filter_cs);
924
925
if (hr == S_OK)
926
hr = SendFurther(pin, deliver_endofstream, NULL);
927
return hr;
928
}
929
930
static HRESULT deliver_beginflush(IPin* pin, LPVOID unused)
931
{
932
return IPin_BeginFlush( pin );
933
}
934
935
static HRESULT WINAPI sink_BeginFlush(IPin *iface)
936
{
937
struct strmbase_sink *pin = impl_sink_from_IPin(iface);
938
HRESULT hr;
939
940
TRACE("pin %p %s:%s.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
941
942
EnterCriticalSection(&pin->pin.filter->filter_cs);
943
944
pin->flushing = TRUE;
945
946
if (pin->pFuncsTable->sink_begin_flush)
947
hr = pin->pFuncsTable->sink_begin_flush(pin);
948
else
949
hr = SendFurther(pin, deliver_beginflush, NULL);
950
951
LeaveCriticalSection(&pin->pin.filter->filter_cs);
952
953
return hr;
954
}
955
956
static HRESULT deliver_endflush(IPin* pin, LPVOID unused)
957
{
958
return IPin_EndFlush( pin );
959
}
960
961
static HRESULT WINAPI sink_EndFlush(IPin * iface)
962
{
963
struct strmbase_sink *pin = impl_sink_from_IPin(iface);
964
HRESULT hr;
965
966
TRACE("pin %p %s:%s.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
967
968
EnterCriticalSection(&pin->pin.filter->filter_cs);
969
970
pin->flushing = FALSE;
971
972
if (pin->pFuncsTable->sink_end_flush)
973
hr = pin->pFuncsTable->sink_end_flush(pin);
974
else
975
hr = SendFurther(pin, deliver_endflush, NULL);
976
977
LeaveCriticalSection(&pin->pin.filter->filter_cs);
978
979
return hr;
980
}
981
982
typedef struct newsegmentargs
983
{
984
REFERENCE_TIME tStart, tStop;
985
double rate;
986
} newsegmentargs;
987
988
static HRESULT deliver_newsegment(IPin *pin, LPVOID data)
989
{
990
newsegmentargs *args = data;
991
return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate);
992
}
993
994
static HRESULT WINAPI sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
995
{
996
struct strmbase_sink *pin = impl_sink_from_IPin(iface);
997
newsegmentargs args;
998
999
TRACE("pin %p %s:%s, start %s, stop %s, rate %.16e.\n", pin, debugstr_w(pin->pin.filter->name),
1000
debugstr_w(pin->pin.name), debugstr_time(start), debugstr_time(stop), rate);
1001
1002
if (pin->pFuncsTable->sink_new_segment)
1003
return pin->pFuncsTable->sink_new_segment(pin, start, stop, rate);
1004
1005
args.tStart = start;
1006
args.tStop = stop;
1007
args.rate = rate;
1008
1009
return SendFurther(pin, deliver_newsegment, &args);
1010
}
1011
1012
static const IPinVtbl sink_vtbl =
1013
{
1014
pin_QueryInterface,
1015
pin_AddRef,
1016
pin_Release,
1017
sink_Connect,
1018
sink_ReceiveConnection,
1019
sink_Disconnect,
1020
pin_ConnectedTo,
1021
pin_ConnectionMediaType,
1022
pin_QueryPinInfo,
1023
pin_QueryDirection,
1024
pin_QueryId,
1025
pin_QueryAccept,
1026
pin_EnumMediaTypes,
1027
pin_QueryInternalConnections,
1028
sink_EndOfStream,
1029
sink_BeginFlush,
1030
sink_EndFlush,
1031
sink_NewSegment,
1032
};
1033
1034
/*** IMemInputPin implementation ***/
1035
1036
static inline struct strmbase_sink *impl_from_IMemInputPin(IMemInputPin *iface)
1037
{
1038
return CONTAINING_RECORD(iface, struct strmbase_sink, IMemInputPin_iface);
1039
}
1040
1041
static HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv)
1042
{
1043
struct strmbase_sink *This = impl_from_IMemInputPin(iface);
1044
1045
return IPin_QueryInterface(&This->pin.IPin_iface, riid, ppv);
1046
}
1047
1048
static ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface)
1049
{
1050
struct strmbase_sink *This = impl_from_IMemInputPin(iface);
1051
1052
return IPin_AddRef(&This->pin.IPin_iface);
1053
}
1054
1055
static ULONG WINAPI MemInputPin_Release(IMemInputPin * iface)
1056
{
1057
struct strmbase_sink *This = impl_from_IMemInputPin(iface);
1058
1059
return IPin_Release(&This->pin.IPin_iface);
1060
}
1061
1062
static HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator)
1063
{
1064
struct strmbase_sink *This = impl_from_IMemInputPin(iface);
1065
1066
TRACE("pin %p %s:%s, allocator %p.\n", This, debugstr_w(This->pin.filter->name),
1067
debugstr_w(This->pin.name), ppAllocator);
1068
1069
*ppAllocator = This->pAllocator;
1070
if (*ppAllocator)
1071
IMemAllocator_AddRef(*ppAllocator);
1072
1073
return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR;
1074
}
1075
1076
static HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly)
1077
{
1078
struct strmbase_sink *This = impl_from_IMemInputPin(iface);
1079
1080
TRACE("pin %p %s:%s, allocator %p, read_only %d.\n", This, debugstr_w(This->pin.filter->name),
1081
debugstr_w(This->pin.name), pAllocator, bReadOnly);
1082
1083
if (bReadOnly)
1084
FIXME("Read only flag not handled yet!\n");
1085
1086
/* FIXME: Should we release the allocator on disconnection? */
1087
if (!pAllocator)
1088
{
1089
WARN("Null allocator\n");
1090
return E_POINTER;
1091
}
1092
1093
if (This->preferred_allocator && pAllocator != This->preferred_allocator)
1094
return E_FAIL;
1095
1096
if (This->pAllocator)
1097
IMemAllocator_Release(This->pAllocator);
1098
This->pAllocator = pAllocator;
1099
if (This->pAllocator)
1100
IMemAllocator_AddRef(This->pAllocator);
1101
1102
return S_OK;
1103
}
1104
1105
static HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
1106
{
1107
struct strmbase_sink *pin = impl_from_IMemInputPin(iface);
1108
1109
TRACE("pin %p %s:%s, props %p.\n", pin, debugstr_w(pin->pin.filter->name),
1110
debugstr_w(pin->pin.name), props);
1111
1112
/* override this method if you have any specific requirements */
1113
1114
return E_NOTIMPL;
1115
}
1116
1117
static HRESULT WINAPI MemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
1118
{
1119
struct strmbase_sink *pin = impl_from_IMemInputPin(iface);
1120
HRESULT hr = S_FALSE;
1121
1122
TRACE("pin %p %s:%s, sample %p.\n", pin, debugstr_w(pin->pin.filter->name),
1123
debugstr_w(pin->pin.name), sample);
1124
1125
if (pin->pFuncsTable->pfnReceive)
1126
{
1127
EnterCriticalSection(&pin->pin.filter->stream_cs);
1128
hr = pin->pFuncsTable->pfnReceive(pin, sample);
1129
LeaveCriticalSection(&pin->pin.filter->stream_cs);
1130
}
1131
return hr;
1132
}
1133
1134
static HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, LONG nSamples, LONG *nSamplesProcessed)
1135
{
1136
HRESULT hr = S_OK;
1137
1138
for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
1139
{
1140
hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
1141
if (hr != S_OK)
1142
break;
1143
}
1144
1145
return hr;
1146
}
1147
1148
static HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface)
1149
{
1150
struct strmbase_sink *pin = impl_from_IMemInputPin(iface);
1151
1152
TRACE("pin %p %s:%s.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
1153
1154
return S_OK;
1155
}
1156
1157
static const IMemInputPinVtbl MemInputPin_Vtbl =
1158
{
1159
MemInputPin_QueryInterface,
1160
MemInputPin_AddRef,
1161
MemInputPin_Release,
1162
MemInputPin_GetAllocator,
1163
MemInputPin_NotifyAllocator,
1164
MemInputPin_GetAllocatorRequirements,
1165
MemInputPin_Receive,
1166
MemInputPin_ReceiveMultiple,
1167
MemInputPin_ReceiveCanBlock
1168
};
1169
1170
void strmbase_sink_init(struct strmbase_sink *pin, struct strmbase_filter *filter,
1171
const WCHAR *name, const struct strmbase_sink_ops *func_table, IMemAllocator *allocator)
1172
{
1173
memset(pin, 0, sizeof(*pin));
1174
pin->pin.IPin_iface.lpVtbl = &sink_vtbl;
1175
pin->pin.filter = filter;
1176
pin->pin.dir = PINDIR_INPUT;
1177
lstrcpyW(pin->pin.name, name);
1178
lstrcpyW(pin->pin.id, name);
1179
pin->pin.ops = &func_table->base;
1180
pin->pFuncsTable = func_table;
1181
pin->pAllocator = pin->preferred_allocator = allocator;
1182
if (pin->preferred_allocator)
1183
IMemAllocator_AddRef(pin->preferred_allocator);
1184
pin->IMemInputPin_iface.lpVtbl = &MemInputPin_Vtbl;
1185
}
1186
1187
void strmbase_sink_cleanup(struct strmbase_sink *pin)
1188
{
1189
FreeMediaType(&pin->pin.mt);
1190
if (pin->pAllocator)
1191
IMemAllocator_Release(pin->pAllocator);
1192
pin->pAllocator = NULL;
1193
pin->pin.IPin_iface.lpVtbl = NULL;
1194
}
1195
1196