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
);
70 This
->filename
= NULL
;
71 This
->num_streams
= -1;
75 static HRESULT
get_filter_info(IMoniker
*moniker
, GUID
*clsid
, VARIANT
*var
)
77 IPropertyBag
*prop_bag
;
80 if (FAILED(hr
= IMoniker_BindToStorage(moniker
, NULL
, NULL
, &IID_IPropertyBag
, (void **)&prop_bag
)))
82 ERR("Failed to get property bag, hr %#x.\n", hr
);
88 if (FAILED(hr
= IPropertyBag_Read(prop_bag
, L
"CLSID", var
, NULL
)))
90 ERR("Failed to get CLSID, hr %#x.\n", hr
);
91 IPropertyBag_Release(prop_bag
);
94 CLSIDFromString(V_BSTR(var
), clsid
);
97 if (FAILED(hr
= IPropertyBag_Read(prop_bag
, L
"FriendlyName", var
, NULL
)))
98 ERR("Failed to get name, hr %#x.\n", hr
);
100 IPropertyBag_Release(prop_bag
);
104 static HRESULT
get_pin_media_type(IPin
*pin
, AM_MEDIA_TYPE
*out
)
106 IEnumMediaTypes
*enummt
;
110 if (FAILED(hr
= IPin_EnumMediaTypes(pin
, &enummt
)))
112 hr
= IEnumMediaTypes_Next(enummt
, 1, &pmt
, NULL
);
113 IEnumMediaTypes_Release(enummt
);
115 return E_NOINTERFACE
;
122 static HRESULT
find_splitter(MediaDetImpl
*detector
)
124 IPin
*source_pin
, *splitter_pin
;
125 IEnumMoniker
*enum_moniker
;
126 IFilterMapper2
*mapper
;
127 IBaseFilter
*splitter
;
128 IEnumPins
*enum_pins
;
136 if (FAILED(hr
= IBaseFilter_EnumPins(detector
->source
, &enum_pins
)))
138 ERR("Failed to enumerate source pins, hr %#x.\n", hr
);
141 hr
= IEnumPins_Next(enum_pins
, 1, &source_pin
, NULL
);
142 IEnumPins_Release(enum_pins
);
145 ERR("Failed to get source pin, hr %#x.\n", hr
);
149 if (FAILED(hr
= get_pin_media_type(source_pin
, &mt
)))
151 ERR("Failed to get media type, hr %#x.\n", hr
);
152 IPin_Release(source_pin
);
156 type
[0] = mt
.majortype
;
157 type
[1] = mt
.subtype
;
160 if (FAILED(hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
,
161 CLSCTX_INPROC_SERVER
, &IID_IFilterMapper2
, (void **)&mapper
)))
163 IPin_Release(source_pin
);
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
);
172 IPin_Release(source_pin
);
177 while (IEnumMoniker_Next(enum_moniker
, 1, &mon
, NULL
) == S_OK
)
179 hr
= get_filter_info(mon
, &clsid
, &var
);
180 IMoniker_Release(mon
);
184 hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
,
185 &IID_IBaseFilter
, (void **)&splitter
);
192 hr
= IGraphBuilder_AddFilter(detector
->graph
, splitter
, V_BSTR(&var
));
196 IBaseFilter_Release(splitter
);
200 hr
= IBaseFilter_EnumPins(splitter
, &enum_pins
);
204 hr
= IEnumPins_Next(enum_pins
, 1, &splitter_pin
, NULL
);
205 IEnumPins_Release(enum_pins
);
209 hr
= IPin_Connect(source_pin
, splitter_pin
, NULL
);
210 IPin_Release(splitter_pin
);
213 detector
->splitter
= splitter
;
218 IGraphBuilder_RemoveFilter(detector
->graph
, splitter
);
219 IBaseFilter_Release(splitter
);
222 IEnumMoniker_Release(enum_moniker
);
223 IPin_Release(source_pin
);
227 /* MediaDet inner IUnknown */
228 static HRESULT WINAPI
MediaDet_inner_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
230 MediaDetImpl
*This
= impl_from_IUnknown(iface
);
232 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
235 if (IsEqualIID(riid
, &IID_IUnknown
))
236 *ppv
= &This
->IUnknown_inner
;
237 else if (IsEqualIID(riid
, &IID_IMediaDet
))
238 *ppv
= &This
->IMediaDet_iface
;
240 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
243 return E_NOINTERFACE
;
245 IUnknown_AddRef((IUnknown
*)*ppv
);
249 static ULONG WINAPI
MediaDet_inner_AddRef(IUnknown
*iface
)
251 MediaDetImpl
*This
= impl_from_IUnknown(iface
);
252 ULONG ref
= InterlockedIncrement(&This
->ref
);
254 TRACE("(%p) new ref = %u\n", This
, ref
);
259 static ULONG WINAPI
MediaDet_inner_Release(IUnknown
*iface
)
261 MediaDetImpl
*This
= impl_from_IUnknown(iface
);
262 ULONG ref
= InterlockedDecrement(&This
->ref
);
264 TRACE("(%p) new ref = %u\n", This
, ref
);
275 static const IUnknownVtbl mediadet_vtbl
=
277 MediaDet_inner_QueryInterface
,
278 MediaDet_inner_AddRef
,
279 MediaDet_inner_Release
,
282 /* IMediaDet implementation */
283 static HRESULT WINAPI
MediaDet_QueryInterface(IMediaDet
*iface
, REFIID riid
, void **ppv
)
285 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
286 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
289 static ULONG WINAPI
MediaDet_AddRef(IMediaDet
*iface
)
291 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
292 return IUnknown_AddRef(This
->outer_unk
);
295 static ULONG WINAPI
MediaDet_Release(IMediaDet
*iface
)
297 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
298 return IUnknown_Release(This
->outer_unk
);
301 static HRESULT WINAPI
MediaDet_get_Filter(IMediaDet
*iface
, IUnknown
**filter
)
303 MediaDetImpl
*detector
= impl_from_IMediaDet(iface
);
305 TRACE("detector %p, filter %p.\n", detector
, filter
);
310 *filter
= (IUnknown
*)detector
->source
;
312 IUnknown_AddRef(*filter
);
319 static HRESULT WINAPI
MediaDet_put_Filter(IMediaDet
*iface
, IUnknown
*unk
)
321 MediaDetImpl
*detector
= impl_from_IMediaDet(iface
);
322 IGraphBuilder
*graph
;
326 TRACE("detector %p, unk %p.\n", detector
, unk
);
331 if (FAILED(hr
= IUnknown_QueryInterface(unk
, &IID_IBaseFilter
, (void **)&filter
)))
333 WARN("Object does not expose IBaseFilter.\n");
338 MD_cleanup(detector
);
340 if (FAILED(hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
,
341 CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
, (void **)&graph
)))
343 IBaseFilter_Release(filter
);
347 if (FAILED(hr
= IGraphBuilder_AddFilter(graph
, filter
, L
"Source")))
349 IGraphBuilder_Release(graph
);
350 IBaseFilter_Release(filter
);
354 detector
->graph
= graph
;
355 detector
->source
= filter
;
356 if (FAILED(find_splitter(detector
)))
358 detector
->splitter
= detector
->source
;
359 IBaseFilter_AddRef(detector
->splitter
);
362 return IMediaDet_put_CurrentStream(&detector
->IMediaDet_iface
, 0);
365 static HRESULT WINAPI
MediaDet_get_OutputStreams(IMediaDet
* iface
, LONG
*pVal
)
367 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
372 TRACE("(%p)\n", This
);
377 if (This
->num_streams
!= -1)
379 *pVal
= This
->num_streams
;
385 hr
= IBaseFilter_EnumPins(This
->splitter
, &pins
);
389 while (IEnumPins_Next(pins
, 1, &pin
, NULL
) == S_OK
)
392 hr
= IPin_QueryDirection(pin
, &dir
);
396 IEnumPins_Release(pins
);
400 if (dir
== PINDIR_OUTPUT
)
403 IEnumPins_Release(pins
);
405 This
->num_streams
= *pVal
;
409 static HRESULT WINAPI
MediaDet_get_CurrentStream(IMediaDet
* iface
, LONG
*pVal
)
411 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
412 TRACE("(%p)\n", This
);
417 *pVal
= This
->cur_stream
;
421 static HRESULT
SetCurPin(MediaDetImpl
*This
, LONG strm
)
427 assert(This
->splitter
);
428 assert(0 <= strm
&& strm
< This
->num_streams
);
432 IPin_Release(This
->cur_pin
);
433 This
->cur_pin
= NULL
;
436 hr
= IBaseFilter_EnumPins(This
->splitter
, &pins
);
440 while (IEnumPins_Next(pins
, 1, &pin
, NULL
) == S_OK
&& !This
->cur_pin
)
443 hr
= IPin_QueryDirection(pin
, &dir
);
447 IEnumPins_Release(pins
);
451 if (dir
== PINDIR_OUTPUT
&& strm
-- == 0)
456 IEnumPins_Release(pins
);
458 assert(This
->cur_pin
);
462 static HRESULT WINAPI
MediaDet_put_CurrentStream(IMediaDet
* iface
, LONG newVal
)
464 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
467 TRACE("(%p)->(%d)\n", This
, newVal
);
469 if (This
->num_streams
== -1)
472 hr
= MediaDet_get_OutputStreams(iface
, &n
);
477 if (newVal
< 0 || This
->num_streams
<= newVal
)
480 hr
= SetCurPin(This
, newVal
);
484 This
->cur_stream
= newVal
;
488 static HRESULT WINAPI
MediaDet_get_StreamType(IMediaDet
*iface
, GUID
*majortype
)
490 MediaDetImpl
*detector
= impl_from_IMediaDet(iface
);
494 TRACE("detector %p, majortype %p.\n", detector
, majortype
);
499 if (SUCCEEDED(hr
= IMediaDet_get_StreamMediaType(iface
, &mt
)))
501 *majortype
= mt
.majortype
;
508 static HRESULT WINAPI
MediaDet_get_StreamTypeB(IMediaDet
*iface
, BSTR
*bstr
)
510 MediaDetImpl
*detector
= impl_from_IMediaDet(iface
);
514 TRACE("detector %p, bstr %p.\n", detector
, bstr
);
516 if (SUCCEEDED(hr
= IMediaDet_get_StreamType(iface
, &guid
)))
518 if (!(*bstr
= SysAllocStringLen(NULL
, CHARS_IN_GUID
- 1)))
519 return E_OUTOFMEMORY
;
520 StringFromGUID2(&guid
, *bstr
, CHARS_IN_GUID
);
525 static HRESULT WINAPI
MediaDet_get_StreamLength(IMediaDet
*iface
, double *length
)
527 MediaDetImpl
*detector
= impl_from_IMediaDet(iface
);
528 IMediaSeeking
*seeking
;
531 TRACE("detector %p, length %p.\n", detector
, length
);
536 if (!detector
->cur_pin
)
539 if (SUCCEEDED(hr
= IPin_QueryInterface(detector
->cur_pin
,
540 &IID_IMediaSeeking
, (void **)&seeking
)))
544 if (SUCCEEDED(hr
= IMediaSeeking_GetDuration(seeking
, &duration
)))
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;
550 IMediaSeeking_Release(seeking
);
556 static HRESULT WINAPI
MediaDet_get_Filename(IMediaDet
* iface
, BSTR
*pVal
)
558 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
560 TRACE("(%p)\n", This
);
566 /* MSDN says it should return E_FAIL if no file is open, but tests
571 *pVal
= SysAllocString(This
->filename
);
573 return E_OUTOFMEMORY
;
578 static HRESULT WINAPI
MediaDet_put_Filename(IMediaDet
*iface
, BSTR filename
)
580 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
585 TRACE("detector %p, filename %s.\n", This
, debugstr_w(filename
));
589 WARN("MSDN says not to call this method twice\n");
593 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
594 &IID_IGraphBuilder
, (void **) &gb
);
598 if (FAILED(hr
= IGraphBuilder_AddSourceFilter(gb
, filename
, L
"Source", &bf
)))
600 IGraphBuilder_Release(gb
);
604 if (!(This
->filename
= wcsdup(filename
)))
606 IBaseFilter_Release(bf
);
607 IGraphBuilder_Release(gb
);
608 return E_OUTOFMEMORY
;
613 hr
= find_splitter(This
);
617 return MediaDet_put_CurrentStream(iface
, 0);
620 static HRESULT WINAPI
MediaDet_GetBitmapBits(IMediaDet
* iface
,
622 LONG
*pBufferSize
, char *pBuffer
,
623 LONG Width
, LONG Height
)
625 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
626 FIXME("(%p)->(%f %p %p %d %d): not implemented!\n", This
, StreamTime
, pBufferSize
, pBuffer
,
631 static HRESULT WINAPI
MediaDet_WriteBitmapBits(IMediaDet
* iface
,
632 double StreamTime
, LONG Width
,
633 LONG Height
, BSTR Filename
)
635 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
636 FIXME("(%p)->(%f %d %d %p): not implemented!\n", This
, StreamTime
, Width
, Height
, Filename
);
640 static HRESULT WINAPI
MediaDet_get_StreamMediaType(IMediaDet
* iface
,
643 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
645 TRACE("(%p)\n", This
);
653 return get_pin_media_type(This
->cur_pin
, pVal
);
656 static HRESULT WINAPI
MediaDet_GetSampleGrabber(IMediaDet
* iface
,
657 ISampleGrabber
**ppVal
)
659 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
660 FIXME("(%p)->(%p): not implemented!\n", This
, ppVal
);
664 static HRESULT WINAPI
MediaDet_get_FrameRate(IMediaDet
* iface
, double *pVal
)
666 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
671 TRACE("(%p)\n", This
);
676 hr
= MediaDet_get_StreamMediaType(iface
, &mt
);
680 if (!IsEqualGUID(&mt
.majortype
, &MEDIATYPE_Video
))
682 CoTaskMemFree(mt
.pbFormat
);
683 return VFW_E_INVALIDMEDIATYPE
;
686 vh
= (VIDEOINFOHEADER
*) mt
.pbFormat
;
687 *pVal
= 1.0e7
/ (double) vh
->AvgTimePerFrame
;
689 CoTaskMemFree(mt
.pbFormat
);
693 static HRESULT WINAPI
MediaDet_EnterBitmapGrabMode(IMediaDet
* iface
,
696 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
697 FIXME("(%p)->(%f): not implemented!\n", This
, SeekTime
);
701 static const IMediaDetVtbl IMediaDet_VTable
=
703 MediaDet_QueryInterface
,
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
,
724 HRESULT
media_detector_create(IUnknown
*pUnkOuter
, IUnknown
**ppv
)
726 MediaDetImpl
* obj
= NULL
;
728 TRACE("(%p,%p)\n", pUnkOuter
, ppv
);
730 obj
= CoTaskMemAlloc(sizeof(MediaDetImpl
));
733 return E_OUTOFMEMORY
;
735 ZeroMemory(obj
, sizeof(MediaDetImpl
));
738 obj
->IUnknown_inner
.lpVtbl
= &mediadet_vtbl
;
739 obj
->IMediaDet_iface
.lpVtbl
= &IMediaDet_VTable
;
742 obj
->splitter
= NULL
;
744 obj
->num_streams
= -1;
748 obj
->outer_unk
= pUnkOuter
;
750 obj
->outer_unk
= &obj
->IUnknown_inner
;
752 *ppv
= &obj
->IUnknown_inner
;