1 /* DirectShow Media Detector object (QEDIT.DLL)
3 * Copyright 2008 Google (Lei Zhang, Dan Hipschman)
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.
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.
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
30 #include "qedit_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(qedit
);
35 typedef struct MediaDetImpl
{
36 IUnknown IUnknown_inner
;
37 IMediaDet IMediaDet_iface
;
42 IBaseFilter
*splitter
;
49 static inline MediaDetImpl
*impl_from_IUnknown(IUnknown
*iface
)
51 return CONTAINING_RECORD(iface
, MediaDetImpl
, IUnknown_inner
);
54 static inline MediaDetImpl
*impl_from_IMediaDet(IMediaDet
*iface
)
56 return CONTAINING_RECORD(iface
, MediaDetImpl
, IMediaDet_iface
);
59 static void MD_cleanup(MediaDetImpl
*This
)
61 if (This
->cur_pin
) IPin_Release(This
->cur_pin
);
63 if (This
->source
) IBaseFilter_Release(This
->source
);
65 if (This
->splitter
) IBaseFilter_Release(This
->splitter
);
66 This
->splitter
= NULL
;
67 if (This
->graph
) IGraphBuilder_Release(This
->graph
);
71 This
->filename
= NULL
;
72 This
->num_streams
= -1;
76 static HRESULT
get_filter_info(IMoniker
*moniker
, GUID
*clsid
, VARIANT
*var
)
78 IPropertyBag
*prop_bag
;
81 if (FAILED(hr
= IMoniker_BindToStorage(moniker
, NULL
, NULL
, &IID_IPropertyBag
, (void **)&prop_bag
)))
83 ERR("Failed to get property bag, hr %#x.\n", hr
);
89 if (FAILED(hr
= IPropertyBag_Read(prop_bag
, L
"CLSID", var
, NULL
)))
91 ERR("Failed to get CLSID, hr %#x.\n", hr
);
92 IPropertyBag_Release(prop_bag
);
95 CLSIDFromString(V_BSTR(var
), clsid
);
98 if (FAILED(hr
= IPropertyBag_Read(prop_bag
, L
"FriendlyName", var
, NULL
)))
99 ERR("Failed to get name, hr %#x.\n", hr
);
101 IPropertyBag_Release(prop_bag
);
105 static HRESULT
get_pin_media_type(IPin
*pin
, AM_MEDIA_TYPE
*out
)
107 IEnumMediaTypes
*enummt
;
111 if (FAILED(hr
= IPin_EnumMediaTypes(pin
, &enummt
)))
113 hr
= IEnumMediaTypes_Next(enummt
, 1, &pmt
, NULL
);
114 IEnumMediaTypes_Release(enummt
);
116 return E_NOINTERFACE
;
123 static HRESULT
find_splitter(MediaDetImpl
*detector
)
125 IPin
*source_pin
, *splitter_pin
;
126 IEnumMoniker
*enum_moniker
;
127 IFilterMapper2
*mapper
;
128 IBaseFilter
*splitter
;
129 IEnumPins
*enum_pins
;
137 if (FAILED(hr
= IBaseFilter_EnumPins(detector
->source
, &enum_pins
)))
139 ERR("Failed to enumerate source pins, hr %#x.\n", hr
);
142 hr
= IEnumPins_Next(enum_pins
, 1, &source_pin
, NULL
);
143 IEnumPins_Release(enum_pins
);
146 ERR("Failed to get source pin, hr %#x.\n", hr
);
150 if (FAILED(hr
= get_pin_media_type(source_pin
, &mt
)))
152 ERR("Failed to get media type, hr %#x.\n", hr
);
153 IPin_Release(source_pin
);
157 type
[0] = mt
.majortype
;
158 type
[1] = mt
.subtype
;
161 if (FAILED(hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
,
162 CLSCTX_INPROC_SERVER
, &IID_IFilterMapper2
, (void **)&mapper
)))
164 IPin_Release(source_pin
);
168 hr
= IFilterMapper2_EnumMatchingFilters(mapper
, &enum_moniker
, 0, TRUE
,
169 MERIT_UNLIKELY
, FALSE
, 1, type
, NULL
, NULL
, FALSE
, TRUE
, 0, NULL
, NULL
, NULL
);
170 IFilterMapper2_Release(mapper
);
173 IPin_Release(source_pin
);
178 while (IEnumMoniker_Next(enum_moniker
, 1, &mon
, NULL
) == S_OK
)
180 hr
= get_filter_info(mon
, &clsid
, &var
);
181 IMoniker_Release(mon
);
185 hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
,
186 &IID_IBaseFilter
, (void **)&splitter
);
193 hr
= IGraphBuilder_AddFilter(detector
->graph
, splitter
, V_BSTR(&var
));
197 IBaseFilter_Release(splitter
);
201 hr
= IBaseFilter_EnumPins(splitter
, &enum_pins
);
205 hr
= IEnumPins_Next(enum_pins
, 1, &splitter_pin
, NULL
);
206 IEnumPins_Release(enum_pins
);
210 hr
= IPin_Connect(source_pin
, splitter_pin
, NULL
);
211 IPin_Release(splitter_pin
);
214 detector
->splitter
= splitter
;
219 IGraphBuilder_RemoveFilter(detector
->graph
, splitter
);
220 IBaseFilter_Release(splitter
);
223 IEnumMoniker_Release(enum_moniker
);
224 IPin_Release(source_pin
);
228 /* MediaDet inner IUnknown */
229 static HRESULT WINAPI
MediaDet_inner_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
231 MediaDetImpl
*This
= impl_from_IUnknown(iface
);
233 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
236 if (IsEqualIID(riid
, &IID_IUnknown
))
237 *ppv
= &This
->IUnknown_inner
;
238 else if (IsEqualIID(riid
, &IID_IMediaDet
))
239 *ppv
= &This
->IMediaDet_iface
;
241 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
244 return E_NOINTERFACE
;
246 IUnknown_AddRef((IUnknown
*)*ppv
);
250 static ULONG WINAPI
MediaDet_inner_AddRef(IUnknown
*iface
)
252 MediaDetImpl
*This
= impl_from_IUnknown(iface
);
253 ULONG ref
= InterlockedIncrement(&This
->ref
);
255 TRACE("(%p) new ref = %u\n", This
, ref
);
260 static ULONG WINAPI
MediaDet_inner_Release(IUnknown
*iface
)
262 MediaDetImpl
*This
= impl_from_IUnknown(iface
);
263 ULONG ref
= InterlockedDecrement(&This
->ref
);
265 TRACE("(%p) new ref = %u\n", This
, ref
);
276 static const IUnknownVtbl mediadet_vtbl
=
278 MediaDet_inner_QueryInterface
,
279 MediaDet_inner_AddRef
,
280 MediaDet_inner_Release
,
283 /* IMediaDet implementation */
284 static HRESULT WINAPI
MediaDet_QueryInterface(IMediaDet
*iface
, REFIID riid
, void **ppv
)
286 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
287 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
290 static ULONG WINAPI
MediaDet_AddRef(IMediaDet
*iface
)
292 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
293 return IUnknown_AddRef(This
->outer_unk
);
296 static ULONG WINAPI
MediaDet_Release(IMediaDet
*iface
)
298 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
299 return IUnknown_Release(This
->outer_unk
);
302 static HRESULT WINAPI
MediaDet_get_Filter(IMediaDet
*iface
, IUnknown
**filter
)
304 MediaDetImpl
*detector
= impl_from_IMediaDet(iface
);
306 TRACE("detector %p, filter %p.\n", detector
, filter
);
311 *filter
= (IUnknown
*)detector
->source
;
313 IUnknown_AddRef(*filter
);
320 static HRESULT WINAPI
MediaDet_put_Filter(IMediaDet
*iface
, IUnknown
*unk
)
322 MediaDetImpl
*detector
= impl_from_IMediaDet(iface
);
323 IGraphBuilder
*graph
;
327 TRACE("detector %p, unk %p.\n", detector
, unk
);
332 if (FAILED(hr
= IUnknown_QueryInterface(unk
, &IID_IBaseFilter
, (void **)&filter
)))
334 WARN("Object does not expose IBaseFilter.\n");
339 MD_cleanup(detector
);
341 if (FAILED(hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
,
342 CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
, (void **)&graph
)))
344 IBaseFilter_Release(filter
);
348 if (FAILED(hr
= IGraphBuilder_AddFilter(graph
, filter
, L
"Source")))
350 IGraphBuilder_Release(graph
);
351 IBaseFilter_Release(filter
);
355 detector
->graph
= graph
;
356 detector
->source
= filter
;
357 if (FAILED(find_splitter(detector
)))
359 detector
->splitter
= detector
->source
;
360 IBaseFilter_AddRef(detector
->splitter
);
363 return IMediaDet_put_CurrentStream(&detector
->IMediaDet_iface
, 0);
366 static HRESULT WINAPI
MediaDet_get_OutputStreams(IMediaDet
* iface
, LONG
*pVal
)
368 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
373 TRACE("(%p)\n", This
);
378 if (This
->num_streams
!= -1)
380 *pVal
= This
->num_streams
;
386 hr
= IBaseFilter_EnumPins(This
->splitter
, &pins
);
390 while (IEnumPins_Next(pins
, 1, &pin
, NULL
) == S_OK
)
393 hr
= IPin_QueryDirection(pin
, &dir
);
397 IEnumPins_Release(pins
);
401 if (dir
== PINDIR_OUTPUT
)
404 IEnumPins_Release(pins
);
406 This
->num_streams
= *pVal
;
410 static HRESULT WINAPI
MediaDet_get_CurrentStream(IMediaDet
* iface
, LONG
*pVal
)
412 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
413 TRACE("(%p)\n", This
);
418 *pVal
= This
->cur_stream
;
422 static HRESULT
SetCurPin(MediaDetImpl
*This
, LONG strm
)
428 assert(This
->splitter
);
429 assert(0 <= strm
&& strm
< This
->num_streams
);
433 IPin_Release(This
->cur_pin
);
434 This
->cur_pin
= NULL
;
437 hr
= IBaseFilter_EnumPins(This
->splitter
, &pins
);
441 while (IEnumPins_Next(pins
, 1, &pin
, NULL
) == S_OK
&& !This
->cur_pin
)
444 hr
= IPin_QueryDirection(pin
, &dir
);
448 IEnumPins_Release(pins
);
452 if (dir
== PINDIR_OUTPUT
&& strm
-- == 0)
457 IEnumPins_Release(pins
);
459 assert(This
->cur_pin
);
463 static HRESULT WINAPI
MediaDet_put_CurrentStream(IMediaDet
* iface
, LONG newVal
)
465 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
468 TRACE("(%p)->(%d)\n", This
, newVal
);
470 if (This
->num_streams
== -1)
473 hr
= MediaDet_get_OutputStreams(iface
, &n
);
478 if (newVal
< 0 || This
->num_streams
<= newVal
)
481 hr
= SetCurPin(This
, newVal
);
485 This
->cur_stream
= newVal
;
489 static HRESULT WINAPI
MediaDet_get_StreamType(IMediaDet
*iface
, GUID
*majortype
)
491 MediaDetImpl
*detector
= impl_from_IMediaDet(iface
);
495 TRACE("detector %p, majortype %p.\n", detector
, majortype
);
500 if (SUCCEEDED(hr
= IMediaDet_get_StreamMediaType(iface
, &mt
)))
502 *majortype
= mt
.majortype
;
509 static HRESULT WINAPI
MediaDet_get_StreamTypeB(IMediaDet
*iface
, BSTR
*bstr
)
511 MediaDetImpl
*detector
= impl_from_IMediaDet(iface
);
515 TRACE("detector %p, bstr %p.\n", detector
, bstr
);
517 if (SUCCEEDED(hr
= IMediaDet_get_StreamType(iface
, &guid
)))
519 if (!(*bstr
= SysAllocStringLen(NULL
, CHARS_IN_GUID
- 1)))
520 return E_OUTOFMEMORY
;
521 StringFromGUID2(&guid
, *bstr
, CHARS_IN_GUID
);
526 static HRESULT WINAPI
MediaDet_get_StreamLength(IMediaDet
*iface
, double *length
)
528 MediaDetImpl
*detector
= impl_from_IMediaDet(iface
);
529 IMediaSeeking
*seeking
;
532 TRACE("detector %p, length %p.\n", detector
, length
);
537 if (!detector
->cur_pin
)
540 if (SUCCEEDED(hr
= IPin_QueryInterface(detector
->cur_pin
,
541 &IID_IMediaSeeking
, (void **)&seeking
)))
545 if (SUCCEEDED(hr
= IMediaSeeking_GetDuration(seeking
, &duration
)))
547 /* Windows assumes the time format is TIME_FORMAT_MEDIA_TIME
548 and does not check it nor convert it, as tests show. */
549 *length
= (REFTIME
)duration
/ 10000000;
551 IMediaSeeking_Release(seeking
);
557 static HRESULT WINAPI
MediaDet_get_Filename(IMediaDet
* iface
, BSTR
*pVal
)
559 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
561 TRACE("(%p)\n", This
);
567 /* MSDN says it should return E_FAIL if no file is open, but tests
572 *pVal
= SysAllocString(This
->filename
);
574 return E_OUTOFMEMORY
;
579 static HRESULT WINAPI
MediaDet_put_Filename(IMediaDet
*iface
, BSTR filename
)
581 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
586 TRACE("detector %p, filename %s.\n", This
, debugstr_w(filename
));
590 WARN("MSDN says not to call this method twice\n");
594 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
595 &IID_IGraphBuilder
, (void **) &gb
);
599 if (FAILED(hr
= IGraphBuilder_AddSourceFilter(gb
, filename
, L
"Source", &bf
)))
601 IGraphBuilder_Release(gb
);
605 if (!(This
->filename
= wcsdup(filename
)))
607 IBaseFilter_Release(bf
);
608 IGraphBuilder_Release(gb
);
609 return E_OUTOFMEMORY
;
614 hr
= find_splitter(This
);
618 return MediaDet_put_CurrentStream(iface
, 0);
621 static HRESULT WINAPI
MediaDet_GetBitmapBits(IMediaDet
* iface
,
623 LONG
*pBufferSize
, char *pBuffer
,
624 LONG Width
, LONG Height
)
626 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
627 FIXME("(%p)->(%f %p %p %d %d): not implemented!\n", This
, StreamTime
, pBufferSize
, pBuffer
,
632 static HRESULT WINAPI
MediaDet_WriteBitmapBits(IMediaDet
* iface
,
633 double StreamTime
, LONG Width
,
634 LONG Height
, BSTR Filename
)
636 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
637 FIXME("(%p)->(%f %d %d %p): not implemented!\n", This
, StreamTime
, Width
, Height
, Filename
);
641 static HRESULT WINAPI
MediaDet_get_StreamMediaType(IMediaDet
* iface
,
644 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
646 TRACE("(%p)\n", This
);
654 return get_pin_media_type(This
->cur_pin
, pVal
);
657 static HRESULT WINAPI
MediaDet_GetSampleGrabber(IMediaDet
* iface
,
658 ISampleGrabber
**ppVal
)
660 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
661 FIXME("(%p)->(%p): not implemented!\n", This
, ppVal
);
665 static HRESULT WINAPI
MediaDet_get_FrameRate(IMediaDet
* iface
, double *pVal
)
667 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
672 TRACE("(%p)\n", This
);
677 hr
= MediaDet_get_StreamMediaType(iface
, &mt
);
681 if (!IsEqualGUID(&mt
.majortype
, &MEDIATYPE_Video
))
683 CoTaskMemFree(mt
.pbFormat
);
684 return VFW_E_INVALIDMEDIATYPE
;
687 vh
= (VIDEOINFOHEADER
*) mt
.pbFormat
;
688 *pVal
= 1.0e7
/ (double) vh
->AvgTimePerFrame
;
690 CoTaskMemFree(mt
.pbFormat
);
694 static HRESULT WINAPI
MediaDet_EnterBitmapGrabMode(IMediaDet
* iface
,
697 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
698 FIXME("(%p)->(%f): not implemented!\n", This
, SeekTime
);
702 static const IMediaDetVtbl IMediaDet_VTable
=
704 MediaDet_QueryInterface
,
709 MediaDet_get_OutputStreams
,
710 MediaDet_get_CurrentStream
,
711 MediaDet_put_CurrentStream
,
712 MediaDet_get_StreamType
,
713 MediaDet_get_StreamTypeB
,
714 MediaDet_get_StreamLength
,
715 MediaDet_get_Filename
,
716 MediaDet_put_Filename
,
717 MediaDet_GetBitmapBits
,
718 MediaDet_WriteBitmapBits
,
719 MediaDet_get_StreamMediaType
,
720 MediaDet_GetSampleGrabber
,
721 MediaDet_get_FrameRate
,
722 MediaDet_EnterBitmapGrabMode
,
725 HRESULT
media_detector_create(IUnknown
*pUnkOuter
, IUnknown
**ppv
)
727 MediaDetImpl
* obj
= NULL
;
729 TRACE("(%p,%p)\n", pUnkOuter
, ppv
);
731 obj
= CoTaskMemAlloc(sizeof(MediaDetImpl
));
734 return E_OUTOFMEMORY
;
736 ZeroMemory(obj
, sizeof(MediaDetImpl
));
739 obj
->IUnknown_inner
.lpVtbl
= &mediadet_vtbl
;
740 obj
->IMediaDet_iface
.lpVtbl
= &IMediaDet_VTable
;
743 obj
->splitter
= NULL
;
745 obj
->num_streams
= -1;
749 obj
->outer_unk
= pUnkOuter
;
751 obj
->outer_unk
= &obj
->IUnknown_inner
;
753 *ppv
= &obj
->IUnknown_inner
;