Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/qedit/mediadet.c
12329 views
1
/* DirectShow Media Detector object (QEDIT.DLL)
2
*
3
* Copyright 2008 Google (Lei Zhang, Dan Hipschman)
4
*
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
9
*
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
14
*
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18
*/
19
20
#include <assert.h>
21
#include <stdarg.h>
22
23
#define COBJMACROS
24
25
#include "windef.h"
26
#include "winbase.h"
27
#include "winuser.h"
28
#include "ole2.h"
29
30
#include "qedit_private.h"
31
#include "wine/debug.h"
32
33
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
34
35
typedef struct MediaDetImpl {
36
IUnknown IUnknown_inner;
37
IMediaDet IMediaDet_iface;
38
IUnknown *outer_unk;
39
LONG ref;
40
IGraphBuilder *graph;
41
IBaseFilter *source;
42
IBaseFilter *splitter;
43
WCHAR *filename;
44
LONG num_streams;
45
LONG cur_stream;
46
IPin *cur_pin;
47
} MediaDetImpl;
48
49
static inline MediaDetImpl *impl_from_IUnknown(IUnknown *iface)
50
{
51
return CONTAINING_RECORD(iface, MediaDetImpl, IUnknown_inner);
52
}
53
54
static inline MediaDetImpl *impl_from_IMediaDet(IMediaDet *iface)
55
{
56
return CONTAINING_RECORD(iface, MediaDetImpl, IMediaDet_iface);
57
}
58
59
static void MD_cleanup(MediaDetImpl *This)
60
{
61
if (This->cur_pin) IPin_Release(This->cur_pin);
62
This->cur_pin = NULL;
63
if (This->source) IBaseFilter_Release(This->source);
64
This->source = NULL;
65
if (This->splitter) IBaseFilter_Release(This->splitter);
66
This->splitter = NULL;
67
if (This->graph) IGraphBuilder_Release(This->graph);
68
This->graph = NULL;
69
free(This->filename);
70
This->filename = NULL;
71
This->num_streams = -1;
72
This->cur_stream = 0;
73
}
74
75
static HRESULT get_filter_info(IMoniker *moniker, GUID *clsid, VARIANT *var)
76
{
77
IPropertyBag *prop_bag;
78
HRESULT hr;
79
80
if (FAILED(hr = IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag)))
81
{
82
ERR("Failed to get property bag, hr %#lx.\n", hr);
83
return hr;
84
}
85
86
VariantInit(var);
87
V_VT(var) = VT_BSTR;
88
if (FAILED(hr = IPropertyBag_Read(prop_bag, L"CLSID", var, NULL)))
89
{
90
ERR("Failed to get CLSID, hr %#lx.\n", hr);
91
IPropertyBag_Release(prop_bag);
92
return hr;
93
}
94
CLSIDFromString(V_BSTR(var), clsid);
95
VariantClear(var);
96
97
if (FAILED(hr = IPropertyBag_Read(prop_bag, L"FriendlyName", var, NULL)))
98
ERR("Failed to get name, hr %#lx.\n", hr);
99
100
IPropertyBag_Release(prop_bag);
101
return hr;
102
}
103
104
static HRESULT get_pin_media_type(IPin *pin, AM_MEDIA_TYPE *out)
105
{
106
IEnumMediaTypes *enummt;
107
AM_MEDIA_TYPE *pmt;
108
HRESULT hr;
109
110
if (FAILED(hr = IPin_EnumMediaTypes(pin, &enummt)))
111
return hr;
112
hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL);
113
IEnumMediaTypes_Release(enummt);
114
if (hr != S_OK)
115
return E_NOINTERFACE;
116
117
*out = *pmt;
118
CoTaskMemFree(pmt);
119
return S_OK;
120
}
121
122
static HRESULT find_splitter(MediaDetImpl *detector)
123
{
124
IPin *source_pin, *splitter_pin;
125
IEnumMoniker *enum_moniker;
126
IFilterMapper2 *mapper;
127
IBaseFilter *splitter;
128
IEnumPins *enum_pins;
129
AM_MEDIA_TYPE mt;
130
IMoniker *mon;
131
GUID type[2];
132
VARIANT var;
133
HRESULT hr;
134
GUID clsid;
135
136
if (FAILED(hr = IBaseFilter_EnumPins(detector->source, &enum_pins)))
137
{
138
ERR("Failed to enumerate source pins, hr %#lx.\n", hr);
139
return hr;
140
}
141
hr = IEnumPins_Next(enum_pins, 1, &source_pin, NULL);
142
IEnumPins_Release(enum_pins);
143
if (hr != S_OK)
144
{
145
ERR("Failed to get source pin, hr %#lx.\n", hr);
146
return hr;
147
}
148
149
if (FAILED(hr = get_pin_media_type(source_pin, &mt)))
150
{
151
ERR("Failed to get media type, hr %#lx.\n", hr);
152
IPin_Release(source_pin);
153
return hr;
154
}
155
156
type[0] = mt.majortype;
157
type[1] = mt.subtype;
158
FreeMediaType(&mt);
159
160
if (FAILED(hr = CoCreateInstance(&CLSID_FilterMapper2, NULL,
161
CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (void **)&mapper)))
162
{
163
IPin_Release(source_pin);
164
return hr;
165
}
166
167
hr = IFilterMapper2_EnumMatchingFilters(mapper, &enum_moniker, 0, TRUE,
168
MERIT_UNLIKELY, FALSE, 1, type, NULL, NULL, FALSE, TRUE, 0, NULL, NULL, NULL);
169
IFilterMapper2_Release(mapper);
170
if (FAILED(hr))
171
{
172
IPin_Release(source_pin);
173
return hr;
174
}
175
176
hr = E_NOINTERFACE;
177
while (IEnumMoniker_Next(enum_moniker, 1, &mon, NULL) == S_OK)
178
{
179
hr = get_filter_info(mon, &clsid, &var);
180
IMoniker_Release(mon);
181
if (FAILED(hr))
182
continue;
183
184
hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER,
185
&IID_IBaseFilter, (void **)&splitter);
186
if (FAILED(hr))
187
{
188
VariantClear(&var);
189
continue;
190
}
191
192
hr = IGraphBuilder_AddFilter(detector->graph, splitter, V_BSTR(&var));
193
VariantClear(&var);
194
if (FAILED(hr))
195
{
196
IBaseFilter_Release(splitter);
197
continue;
198
}
199
200
hr = IBaseFilter_EnumPins(splitter, &enum_pins);
201
if (FAILED(hr))
202
goto next;
203
204
hr = IEnumPins_Next(enum_pins, 1, &splitter_pin, NULL);
205
IEnumPins_Release(enum_pins);
206
if (hr != S_OK)
207
goto next;
208
209
hr = IPin_Connect(source_pin, splitter_pin, NULL);
210
IPin_Release(splitter_pin);
211
if (SUCCEEDED(hr))
212
{
213
detector->splitter = splitter;
214
break;
215
}
216
217
next:
218
IGraphBuilder_RemoveFilter(detector->graph, splitter);
219
IBaseFilter_Release(splitter);
220
}
221
222
IEnumMoniker_Release(enum_moniker);
223
IPin_Release(source_pin);
224
return hr;
225
}
226
227
/* MediaDet inner IUnknown */
228
static HRESULT WINAPI MediaDet_inner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
229
{
230
MediaDetImpl *This = impl_from_IUnknown(iface);
231
232
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
233
234
*ppv = NULL;
235
if (IsEqualIID(riid, &IID_IUnknown))
236
*ppv = &This->IUnknown_inner;
237
else if (IsEqualIID(riid, &IID_IMediaDet))
238
*ppv = &This->IMediaDet_iface;
239
else
240
WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
241
242
if (!*ppv)
243
return E_NOINTERFACE;
244
245
IUnknown_AddRef((IUnknown*)*ppv);
246
return S_OK;
247
}
248
249
static ULONG WINAPI MediaDet_inner_AddRef(IUnknown *iface)
250
{
251
MediaDetImpl *detector = impl_from_IUnknown(iface);
252
ULONG refcount = InterlockedIncrement(&detector->ref);
253
254
TRACE("%p increasing refcount to %lu.\n", detector, refcount);
255
256
return refcount;
257
}
258
259
static ULONG WINAPI MediaDet_inner_Release(IUnknown *iface)
260
{
261
MediaDetImpl *detector = impl_from_IUnknown(iface);
262
ULONG refcount = InterlockedDecrement(&detector->ref);
263
264
TRACE("%p decreasing refcount to %lu.\n", detector, refcount);
265
266
if (!refcount)
267
{
268
MD_cleanup(detector);
269
CoTaskMemFree(detector);
270
}
271
272
return refcount;
273
}
274
275
static const IUnknownVtbl mediadet_vtbl =
276
{
277
MediaDet_inner_QueryInterface,
278
MediaDet_inner_AddRef,
279
MediaDet_inner_Release,
280
};
281
282
/* IMediaDet implementation */
283
static HRESULT WINAPI MediaDet_QueryInterface(IMediaDet *iface, REFIID riid, void **ppv)
284
{
285
MediaDetImpl *This = impl_from_IMediaDet(iface);
286
return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
287
}
288
289
static ULONG WINAPI MediaDet_AddRef(IMediaDet *iface)
290
{
291
MediaDetImpl *This = impl_from_IMediaDet(iface);
292
return IUnknown_AddRef(This->outer_unk);
293
}
294
295
static ULONG WINAPI MediaDet_Release(IMediaDet *iface)
296
{
297
MediaDetImpl *This = impl_from_IMediaDet(iface);
298
return IUnknown_Release(This->outer_unk);
299
}
300
301
static HRESULT WINAPI MediaDet_get_Filter(IMediaDet *iface, IUnknown **filter)
302
{
303
MediaDetImpl *detector = impl_from_IMediaDet(iface);
304
305
TRACE("detector %p, filter %p.\n", detector, filter);
306
307
if (!filter)
308
return E_POINTER;
309
310
*filter = (IUnknown *)detector->source;
311
if (*filter)
312
IUnknown_AddRef(*filter);
313
else
314
return S_FALSE;
315
316
return S_OK;
317
}
318
319
static HRESULT WINAPI MediaDet_put_Filter(IMediaDet *iface, IUnknown *unk)
320
{
321
MediaDetImpl *detector = impl_from_IMediaDet(iface);
322
IGraphBuilder *graph;
323
IBaseFilter *filter;
324
HRESULT hr;
325
326
TRACE("detector %p, unk %p.\n", detector, unk);
327
328
if (!unk)
329
return E_POINTER;
330
331
if (FAILED(hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter)))
332
{
333
WARN("Object does not expose IBaseFilter.\n");
334
return hr;
335
}
336
337
if (detector->graph)
338
MD_cleanup(detector);
339
340
if (FAILED(hr = CoCreateInstance(&CLSID_FilterGraph, NULL,
341
CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&graph)))
342
{
343
IBaseFilter_Release(filter);
344
return hr;
345
}
346
347
if (FAILED(hr = IGraphBuilder_AddFilter(graph, filter, L"Source")))
348
{
349
IGraphBuilder_Release(graph);
350
IBaseFilter_Release(filter);
351
return hr;
352
}
353
354
detector->graph = graph;
355
detector->source = filter;
356
if (FAILED(find_splitter(detector)))
357
{
358
detector->splitter = detector->source;
359
IBaseFilter_AddRef(detector->splitter);
360
}
361
362
return IMediaDet_put_CurrentStream(&detector->IMediaDet_iface, 0);
363
}
364
365
static HRESULT WINAPI MediaDet_get_OutputStreams(IMediaDet* iface, LONG *pVal)
366
{
367
MediaDetImpl *This = impl_from_IMediaDet(iface);
368
IEnumPins *pins;
369
IPin *pin;
370
HRESULT hr;
371
372
TRACE("(%p)\n", This);
373
374
if (!This->splitter)
375
return E_INVALIDARG;
376
377
if (This->num_streams != -1)
378
{
379
*pVal = This->num_streams;
380
return S_OK;
381
}
382
383
*pVal = 0;
384
385
hr = IBaseFilter_EnumPins(This->splitter, &pins);
386
if (FAILED(hr))
387
return hr;
388
389
while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK)
390
{
391
PIN_DIRECTION dir;
392
hr = IPin_QueryDirection(pin, &dir);
393
IPin_Release(pin);
394
if (FAILED(hr))
395
{
396
IEnumPins_Release(pins);
397
return hr;
398
}
399
400
if (dir == PINDIR_OUTPUT)
401
++*pVal;
402
}
403
IEnumPins_Release(pins);
404
405
This->num_streams = *pVal;
406
return S_OK;
407
}
408
409
static HRESULT WINAPI MediaDet_get_CurrentStream(IMediaDet* iface, LONG *pVal)
410
{
411
MediaDetImpl *This = impl_from_IMediaDet(iface);
412
TRACE("(%p)\n", This);
413
414
if (!pVal)
415
return E_POINTER;
416
417
*pVal = This->cur_stream;
418
return S_OK;
419
}
420
421
static HRESULT SetCurPin(MediaDetImpl *This, LONG strm)
422
{
423
IEnumPins *pins;
424
IPin *pin;
425
HRESULT hr;
426
427
assert(This->splitter);
428
assert(0 <= strm && strm < This->num_streams);
429
430
if (This->cur_pin)
431
{
432
IPin_Release(This->cur_pin);
433
This->cur_pin = NULL;
434
}
435
436
hr = IBaseFilter_EnumPins(This->splitter, &pins);
437
if (FAILED(hr))
438
return hr;
439
440
while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK && !This->cur_pin)
441
{
442
PIN_DIRECTION dir;
443
hr = IPin_QueryDirection(pin, &dir);
444
if (FAILED(hr))
445
{
446
IPin_Release(pin);
447
IEnumPins_Release(pins);
448
return hr;
449
}
450
451
if (dir == PINDIR_OUTPUT && strm-- == 0)
452
This->cur_pin = pin;
453
else
454
IPin_Release(pin);
455
}
456
IEnumPins_Release(pins);
457
458
assert(This->cur_pin);
459
return S_OK;
460
}
461
462
static HRESULT WINAPI MediaDet_put_CurrentStream(IMediaDet* iface, LONG newVal)
463
{
464
MediaDetImpl *This = impl_from_IMediaDet(iface);
465
HRESULT hr;
466
467
TRACE("detector %p, index %ld.\n", This, newVal);
468
469
if (This->num_streams == -1)
470
{
471
LONG n;
472
hr = MediaDet_get_OutputStreams(iface, &n);
473
if (FAILED(hr))
474
return hr;
475
}
476
477
if (newVal < 0 || This->num_streams <= newVal)
478
return E_INVALIDARG;
479
480
hr = SetCurPin(This, newVal);
481
if (FAILED(hr))
482
return hr;
483
484
This->cur_stream = newVal;
485
return S_OK;
486
}
487
488
static HRESULT WINAPI MediaDet_get_StreamType(IMediaDet *iface, GUID *majortype)
489
{
490
MediaDetImpl *detector = impl_from_IMediaDet(iface);
491
AM_MEDIA_TYPE mt;
492
HRESULT hr;
493
494
TRACE("detector %p, majortype %p.\n", detector, majortype);
495
496
if (!majortype)
497
return E_POINTER;
498
499
if (SUCCEEDED(hr = IMediaDet_get_StreamMediaType(iface, &mt)))
500
{
501
*majortype = mt.majortype;
502
FreeMediaType(&mt);
503
}
504
505
return hr;
506
}
507
508
static HRESULT WINAPI MediaDet_get_StreamTypeB(IMediaDet *iface, BSTR *bstr)
509
{
510
MediaDetImpl *detector = impl_from_IMediaDet(iface);
511
HRESULT hr;
512
GUID guid;
513
514
TRACE("detector %p, bstr %p.\n", detector, bstr);
515
516
if (SUCCEEDED(hr = IMediaDet_get_StreamType(iface, &guid)))
517
{
518
if (!(*bstr = SysAllocStringLen(NULL, CHARS_IN_GUID - 1)))
519
return E_OUTOFMEMORY;
520
StringFromGUID2(&guid, *bstr, CHARS_IN_GUID);
521
}
522
return hr;
523
}
524
525
static HRESULT WINAPI MediaDet_get_StreamLength(IMediaDet *iface, double *length)
526
{
527
MediaDetImpl *detector = impl_from_IMediaDet(iface);
528
IMediaSeeking *seeking;
529
HRESULT hr;
530
531
TRACE("detector %p, length %p.\n", detector, length);
532
533
if (!length)
534
return E_POINTER;
535
536
if (!detector->cur_pin)
537
return E_INVALIDARG;
538
539
if (SUCCEEDED(hr = IPin_QueryInterface(detector->cur_pin,
540
&IID_IMediaSeeking, (void **)&seeking)))
541
{
542
LONGLONG duration;
543
544
if (SUCCEEDED(hr = IMediaSeeking_GetDuration(seeking, &duration)))
545
{
546
/* Windows assumes the time format is TIME_FORMAT_MEDIA_TIME
547
and does not check it nor convert it, as tests show. */
548
*length = (REFTIME)duration / 10000000;
549
}
550
IMediaSeeking_Release(seeking);
551
}
552
553
return hr;
554
}
555
556
static HRESULT WINAPI MediaDet_get_Filename(IMediaDet* iface, BSTR *pVal)
557
{
558
MediaDetImpl *This = impl_from_IMediaDet(iface);
559
560
TRACE("(%p)\n", This);
561
562
if (!pVal)
563
return E_POINTER;
564
565
*pVal = NULL;
566
/* MSDN says it should return E_FAIL if no file is open, but tests
567
show otherwise. */
568
if (!This->filename)
569
return S_OK;
570
571
*pVal = SysAllocString(This->filename);
572
if (!*pVal)
573
return E_OUTOFMEMORY;
574
575
return S_OK;
576
}
577
578
static HRESULT WINAPI MediaDet_put_Filename(IMediaDet *iface, BSTR filename)
579
{
580
MediaDetImpl *This = impl_from_IMediaDet(iface);
581
IGraphBuilder *gb;
582
IBaseFilter *bf;
583
HRESULT hr;
584
585
TRACE("detector %p, filename %s.\n", This, debugstr_w(filename));
586
587
if (This->graph)
588
{
589
WARN("MSDN says not to call this method twice\n");
590
MD_cleanup(This);
591
}
592
593
hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
594
&IID_IGraphBuilder, (void **) &gb);
595
if (FAILED(hr))
596
return hr;
597
598
if (FAILED(hr = IGraphBuilder_AddSourceFilter(gb, filename, L"Source", &bf)))
599
{
600
IGraphBuilder_Release(gb);
601
return hr;
602
}
603
604
if (!(This->filename = wcsdup(filename)))
605
{
606
IBaseFilter_Release(bf);
607
IGraphBuilder_Release(gb);
608
return E_OUTOFMEMORY;
609
}
610
611
This->graph = gb;
612
This->source = bf;
613
hr = find_splitter(This);
614
if (FAILED(hr))
615
return hr;
616
617
return MediaDet_put_CurrentStream(iface, 0);
618
}
619
620
static HRESULT WINAPI MediaDet_GetBitmapBits(IMediaDet* iface,
621
double StreamTime,
622
LONG *pBufferSize, char *pBuffer,
623
LONG Width, LONG Height)
624
{
625
MediaDetImpl *This = impl_from_IMediaDet(iface);
626
FIXME("(%p)->(%.16e %p %p %ld %ld): not implemented!\n", This, StreamTime, pBufferSize, pBuffer,
627
Width, Height);
628
return E_NOTIMPL;
629
}
630
631
static HRESULT WINAPI MediaDet_WriteBitmapBits(IMediaDet* iface,
632
double StreamTime, LONG Width,
633
LONG Height, BSTR Filename)
634
{
635
MediaDetImpl *This = impl_from_IMediaDet(iface);
636
FIXME("(%p)->(%.16e %ld %ld %p): not implemented!\n", This, StreamTime, Width, Height, Filename);
637
return E_NOTIMPL;
638
}
639
640
static HRESULT WINAPI MediaDet_get_StreamMediaType(IMediaDet* iface,
641
AM_MEDIA_TYPE *pVal)
642
{
643
MediaDetImpl *This = impl_from_IMediaDet(iface);
644
645
TRACE("(%p)\n", This);
646
647
if (!pVal)
648
return E_POINTER;
649
650
if (!This->cur_pin)
651
return E_INVALIDARG;
652
653
return get_pin_media_type(This->cur_pin, pVal);
654
}
655
656
static HRESULT WINAPI MediaDet_GetSampleGrabber(IMediaDet* iface,
657
ISampleGrabber **ppVal)
658
{
659
MediaDetImpl *This = impl_from_IMediaDet(iface);
660
FIXME("(%p)->(%p): not implemented!\n", This, ppVal);
661
return E_NOTIMPL;
662
}
663
664
static HRESULT WINAPI MediaDet_get_FrameRate(IMediaDet* iface, double *pVal)
665
{
666
MediaDetImpl *This = impl_from_IMediaDet(iface);
667
AM_MEDIA_TYPE mt;
668
VIDEOINFOHEADER *vh;
669
HRESULT hr;
670
671
TRACE("(%p)\n", This);
672
673
if (!pVal)
674
return E_POINTER;
675
676
hr = MediaDet_get_StreamMediaType(iface, &mt);
677
if (FAILED(hr))
678
return hr;
679
680
if (!IsEqualGUID(&mt.majortype, &MEDIATYPE_Video))
681
{
682
CoTaskMemFree(mt.pbFormat);
683
return VFW_E_INVALIDMEDIATYPE;
684
}
685
686
vh = (VIDEOINFOHEADER *) mt.pbFormat;
687
*pVal = 1.0e7 / (double) vh->AvgTimePerFrame;
688
689
CoTaskMemFree(mt.pbFormat);
690
return S_OK;
691
}
692
693
static HRESULT WINAPI MediaDet_EnterBitmapGrabMode(IMediaDet* iface,
694
double SeekTime)
695
{
696
MediaDetImpl *This = impl_from_IMediaDet(iface);
697
FIXME("(%p)->(%f): not implemented!\n", This, SeekTime);
698
return E_NOTIMPL;
699
}
700
701
static const IMediaDetVtbl IMediaDet_VTable =
702
{
703
MediaDet_QueryInterface,
704
MediaDet_AddRef,
705
MediaDet_Release,
706
MediaDet_get_Filter,
707
MediaDet_put_Filter,
708
MediaDet_get_OutputStreams,
709
MediaDet_get_CurrentStream,
710
MediaDet_put_CurrentStream,
711
MediaDet_get_StreamType,
712
MediaDet_get_StreamTypeB,
713
MediaDet_get_StreamLength,
714
MediaDet_get_Filename,
715
MediaDet_put_Filename,
716
MediaDet_GetBitmapBits,
717
MediaDet_WriteBitmapBits,
718
MediaDet_get_StreamMediaType,
719
MediaDet_GetSampleGrabber,
720
MediaDet_get_FrameRate,
721
MediaDet_EnterBitmapGrabMode,
722
};
723
724
HRESULT media_detector_create(IUnknown *pUnkOuter, IUnknown **ppv)
725
{
726
MediaDetImpl* obj = NULL;
727
728
TRACE("(%p,%p)\n", pUnkOuter, ppv);
729
730
obj = CoTaskMemAlloc(sizeof(MediaDetImpl));
731
if (NULL == obj) {
732
*ppv = NULL;
733
return E_OUTOFMEMORY;
734
}
735
ZeroMemory(obj, sizeof(MediaDetImpl));
736
737
obj->ref = 1;
738
obj->IUnknown_inner.lpVtbl = &mediadet_vtbl;
739
obj->IMediaDet_iface.lpVtbl = &IMediaDet_VTable;
740
obj->graph = NULL;
741
obj->source = NULL;
742
obj->splitter = NULL;
743
obj->cur_pin = NULL;
744
obj->num_streams = -1;
745
obj->cur_stream = 0;
746
747
if (pUnkOuter)
748
obj->outer_unk = pUnkOuter;
749
else
750
obj->outer_unk = &obj->IUnknown_inner;
751
752
*ppv = &obj->IUnknown_inner;
753
return S_OK;
754
}
755
756