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
20 #include "qedit_private.h"
25 typedef struct MediaDetImpl
{
26 IUnknown IUnknown_inner
;
27 IMediaDet IMediaDet_iface
;
32 IBaseFilter
*splitter
;
38 static inline MediaDetImpl
*impl_from_IUnknown(IUnknown
*iface
)
40 return CONTAINING_RECORD(iface
, MediaDetImpl
, IUnknown_inner
);
43 static inline MediaDetImpl
*impl_from_IMediaDet(IMediaDet
*iface
)
45 return CONTAINING_RECORD(iface
, MediaDetImpl
, IMediaDet_iface
);
48 static void MD_cleanup(MediaDetImpl
*This
)
50 if (This
->cur_pin
) IPin_Release(This
->cur_pin
);
52 if (This
->source
) IBaseFilter_Release(This
->source
);
54 if (This
->splitter
) IBaseFilter_Release(This
->splitter
);
55 This
->splitter
= NULL
;
56 if (This
->graph
) IGraphBuilder_Release(This
->graph
);
58 This
->num_streams
= -1;
62 /* MediaDet inner IUnknown */
63 static HRESULT WINAPI
MediaDet_inner_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
65 MediaDetImpl
*This
= impl_from_IUnknown(iface
);
67 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
70 if (IsEqualIID(riid
, &IID_IUnknown
))
71 *ppv
= &This
->IUnknown_inner
;
72 else if (IsEqualIID(riid
, &IID_IMediaDet
))
73 *ppv
= &This
->IMediaDet_iface
;
75 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
80 IUnknown_AddRef((IUnknown
*)*ppv
);
84 static ULONG WINAPI
MediaDet_inner_AddRef(IUnknown
*iface
)
86 MediaDetImpl
*This
= impl_from_IUnknown(iface
);
87 ULONG ref
= InterlockedIncrement(&This
->ref
);
89 TRACE("(%p) new ref = %u\n", This
, ref
);
94 static ULONG WINAPI
MediaDet_inner_Release(IUnknown
*iface
)
96 MediaDetImpl
*This
= impl_from_IUnknown(iface
);
97 ULONG ref
= InterlockedDecrement(&This
->ref
);
99 TRACE("(%p) new ref = %u\n", This
, ref
);
111 static const IUnknownVtbl mediadet_vtbl
=
113 MediaDet_inner_QueryInterface
,
114 MediaDet_inner_AddRef
,
115 MediaDet_inner_Release
,
118 /* IMediaDet implementation */
119 static HRESULT WINAPI
MediaDet_QueryInterface(IMediaDet
*iface
, REFIID riid
, void **ppv
)
121 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
122 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
125 static ULONG WINAPI
MediaDet_AddRef(IMediaDet
*iface
)
127 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
128 return IUnknown_AddRef(This
->outer_unk
);
131 static ULONG WINAPI
MediaDet_Release(IMediaDet
*iface
)
133 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
134 return IUnknown_Release(This
->outer_unk
);
137 static HRESULT WINAPI
MediaDet_get_Filter(IMediaDet
* iface
, IUnknown
**pVal
)
139 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
140 FIXME("(%p)->(%p): not implemented!\n", This
, pVal
);
144 static HRESULT WINAPI
MediaDet_put_Filter(IMediaDet
* iface
, IUnknown
*newVal
)
146 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
147 FIXME("(%p)->(%p): not implemented!\n", This
, newVal
);
151 static HRESULT WINAPI
MediaDet_get_OutputStreams(IMediaDet
* iface
, LONG
*pVal
)
153 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
158 TRACE("(%p)\n", This
);
163 if (This
->num_streams
!= -1)
165 *pVal
= This
->num_streams
;
171 hr
= IBaseFilter_EnumPins(This
->splitter
, &pins
);
175 while (IEnumPins_Next(pins
, 1, &pin
, NULL
) == S_OK
)
178 hr
= IPin_QueryDirection(pin
, &dir
);
182 IEnumPins_Release(pins
);
186 if (dir
== PINDIR_OUTPUT
)
189 IEnumPins_Release(pins
);
191 This
->num_streams
= *pVal
;
195 static HRESULT WINAPI
MediaDet_get_CurrentStream(IMediaDet
* iface
, LONG
*pVal
)
197 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
198 TRACE("(%p)\n", This
);
203 *pVal
= This
->cur_stream
;
207 static HRESULT
SetCurPin(MediaDetImpl
*This
, LONG strm
)
213 assert(This
->splitter
);
214 assert(0 <= strm
&& strm
< This
->num_streams
);
218 IPin_Release(This
->cur_pin
);
219 This
->cur_pin
= NULL
;
222 hr
= IBaseFilter_EnumPins(This
->splitter
, &pins
);
226 while (IEnumPins_Next(pins
, 1, &pin
, NULL
) == S_OK
&& !This
->cur_pin
)
229 hr
= IPin_QueryDirection(pin
, &dir
);
233 IEnumPins_Release(pins
);
237 if (dir
== PINDIR_OUTPUT
&& strm
-- == 0)
242 IEnumPins_Release(pins
);
244 assert(This
->cur_pin
);
248 static HRESULT WINAPI
MediaDet_put_CurrentStream(IMediaDet
* iface
, LONG newVal
)
250 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
253 TRACE("(%p)->(%d)\n", This
, newVal
);
255 if (This
->num_streams
== -1)
258 hr
= MediaDet_get_OutputStreams(iface
, &n
);
263 if (newVal
< 0 || This
->num_streams
<= newVal
)
266 hr
= SetCurPin(This
, newVal
);
270 This
->cur_stream
= newVal
;
274 static HRESULT WINAPI
MediaDet_get_StreamType(IMediaDet
* iface
, GUID
*pVal
)
276 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
277 FIXME("(%p)->(%s): not implemented!\n", This
, debugstr_guid(pVal
));
281 static HRESULT WINAPI
MediaDet_get_StreamTypeB(IMediaDet
* iface
, BSTR
*pVal
)
283 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
284 FIXME("(%p)->(%p): not implemented!\n", This
, pVal
);
288 static HRESULT WINAPI
MediaDet_get_StreamLength(IMediaDet
* iface
, double *pVal
)
290 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
291 FIXME("(%p): stub!\n", This
);
292 return VFW_E_INVALIDMEDIATYPE
;
295 static HRESULT WINAPI
MediaDet_get_Filename(IMediaDet
* iface
, BSTR
*pVal
)
297 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
298 IFileSourceFilter
*file
;
302 TRACE("(%p)\n", This
);
308 /* MSDN says it should return E_FAIL if no file is open, but tests
313 hr
= IBaseFilter_QueryInterface(This
->source
, &IID_IFileSourceFilter
,
318 hr
= IFileSourceFilter_GetCurFile(file
, &name
, NULL
);
319 IFileSourceFilter_Release(file
);
323 *pVal
= SysAllocString(name
);
326 return E_OUTOFMEMORY
;
331 /* From quartz, 2008/04/07 */
332 static HRESULT
GetFilterInfo(IMoniker
*pMoniker
, GUID
*pclsid
, VARIANT
*pvar
)
334 static const WCHAR wszClsidName
[] = {'C','L','S','I','D',0};
335 static const WCHAR wszFriendlyName
[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
336 IPropertyBag
*pPropBagCat
= NULL
;
340 V_VT(pvar
) = VT_BSTR
;
342 hr
= IMoniker_BindToStorage(pMoniker
, NULL
, NULL
, &IID_IPropertyBag
,
343 (LPVOID
*) &pPropBagCat
);
346 hr
= IPropertyBag_Read(pPropBagCat
, wszClsidName
, pvar
, NULL
);
350 hr
= CLSIDFromString(V_BSTR(pvar
), pclsid
);
352 V_VT(pvar
) = VT_BSTR
;
356 hr
= IPropertyBag_Read(pPropBagCat
, wszFriendlyName
, pvar
, NULL
);
359 TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid
), debugstr_w(V_BSTR(pvar
)));
362 IPropertyBag_Release(pPropBagCat
);
367 static HRESULT
GetSplitter(MediaDetImpl
*This
)
369 IFileSourceFilter
*file
;
374 IEnumMoniker
*filters
;
378 IBaseFilter
*splitter
;
380 IPin
*source_pin
, *splitter_pin
;
383 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
384 &IID_IFilterMapper2
, (void **) &map
);
388 hr
= IBaseFilter_QueryInterface(This
->source
, &IID_IFileSourceFilter
,
392 IFilterMapper2_Release(map
);
396 hr
= IFileSourceFilter_GetCurFile(file
, &name
, &mt
);
397 IFileSourceFilter_Release(file
);
401 IFilterMapper2_Release(map
);
404 type
[0] = mt
.majortype
;
405 type
[1] = mt
.subtype
;
406 CoTaskMemFree(mt
.pbFormat
);
408 hr
= IFilterMapper2_EnumMatchingFilters(map
, &filters
, 0, TRUE
,
409 MERIT_UNLIKELY
, FALSE
, 1, type
,
410 NULL
, NULL
, FALSE
, TRUE
,
411 0, NULL
, NULL
, NULL
);
412 IFilterMapper2_Release(map
);
417 while (IEnumMoniker_Next(filters
, 1, &mon
, NULL
) == S_OK
)
419 hr
= GetFilterInfo(mon
, &clsid
, &var
);
420 IMoniker_Release(mon
);
424 hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
,
425 &IID_IBaseFilter
, (void **) &splitter
);
432 hr
= IGraphBuilder_AddFilter(This
->graph
, splitter
, V_BSTR(&var
));
434 This
->splitter
= splitter
;
438 hr
= IBaseFilter_EnumPins(This
->source
, &pins
);
441 IEnumPins_Next(pins
, 1, &source_pin
, NULL
);
442 IEnumPins_Release(pins
);
444 hr
= IBaseFilter_EnumPins(splitter
, &pins
);
447 IPin_Release(source_pin
);
450 IEnumPins_Next(pins
, 1, &splitter_pin
, NULL
);
451 IEnumPins_Release(pins
);
453 hr
= IPin_Connect(source_pin
, splitter_pin
, NULL
);
454 IPin_Release(source_pin
);
455 IPin_Release(splitter_pin
);
460 IBaseFilter_Release(splitter
);
461 This
->splitter
= NULL
;
464 IEnumMoniker_Release(filters
);
471 static HRESULT WINAPI
MediaDet_put_Filename(IMediaDet
* iface
, BSTR newVal
)
473 static const WCHAR reader
[] = {'R','e','a','d','e','r',0};
474 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
479 TRACE("(%p)->(%s)\n", This
, debugstr_w(newVal
));
483 WARN("MSDN says not to call this method twice\n");
487 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
488 &IID_IGraphBuilder
, (void **) &gb
);
492 hr
= IGraphBuilder_AddSourceFilter(gb
, newVal
, reader
, &bf
);
495 IGraphBuilder_Release(gb
);
501 hr
= GetSplitter(This
);
505 return MediaDet_put_CurrentStream(iface
, 0);
508 static HRESULT WINAPI
MediaDet_GetBitmapBits(IMediaDet
* iface
,
510 LONG
*pBufferSize
, char *pBuffer
,
511 LONG Width
, LONG Height
)
513 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
514 FIXME("(%p)->(%f %p %p %d %d): not implemented!\n", This
, StreamTime
, pBufferSize
, pBuffer
,
519 static HRESULT WINAPI
MediaDet_WriteBitmapBits(IMediaDet
* iface
,
520 double StreamTime
, LONG Width
,
521 LONG Height
, BSTR Filename
)
523 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
524 FIXME("(%p)->(%f %d %d %p): not implemented!\n", This
, StreamTime
, Width
, Height
, Filename
);
528 static HRESULT WINAPI
MediaDet_get_StreamMediaType(IMediaDet
* iface
,
531 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
532 IEnumMediaTypes
*types
;
536 TRACE("(%p)\n", This
);
544 hr
= IPin_EnumMediaTypes(This
->cur_pin
, &types
);
547 hr
= (IEnumMediaTypes_Next(types
, 1, &pmt
, NULL
) == S_OK
550 IEnumMediaTypes_Release(types
);
562 static HRESULT WINAPI
MediaDet_GetSampleGrabber(IMediaDet
* iface
,
563 ISampleGrabber
**ppVal
)
565 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
566 FIXME("(%p)->(%p): not implemented!\n", This
, ppVal
);
570 static HRESULT WINAPI
MediaDet_get_FrameRate(IMediaDet
* iface
, double *pVal
)
572 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
577 TRACE("(%p)\n", This
);
582 hr
= MediaDet_get_StreamMediaType(iface
, &mt
);
586 if (!IsEqualGUID(&mt
.majortype
, &MEDIATYPE_Video
))
588 CoTaskMemFree(mt
.pbFormat
);
589 return VFW_E_INVALIDMEDIATYPE
;
592 vh
= (VIDEOINFOHEADER
*) mt
.pbFormat
;
593 *pVal
= 1.0e7
/ (double) vh
->AvgTimePerFrame
;
595 CoTaskMemFree(mt
.pbFormat
);
599 static HRESULT WINAPI
MediaDet_EnterBitmapGrabMode(IMediaDet
* iface
,
602 MediaDetImpl
*This
= impl_from_IMediaDet(iface
);
603 FIXME("(%p)->(%f): not implemented!\n", This
, SeekTime
);
607 static const IMediaDetVtbl IMediaDet_VTable
=
609 MediaDet_QueryInterface
,
614 MediaDet_get_OutputStreams
,
615 MediaDet_get_CurrentStream
,
616 MediaDet_put_CurrentStream
,
617 MediaDet_get_StreamType
,
618 MediaDet_get_StreamTypeB
,
619 MediaDet_get_StreamLength
,
620 MediaDet_get_Filename
,
621 MediaDet_put_Filename
,
622 MediaDet_GetBitmapBits
,
623 MediaDet_WriteBitmapBits
,
624 MediaDet_get_StreamMediaType
,
625 MediaDet_GetSampleGrabber
,
626 MediaDet_get_FrameRate
,
627 MediaDet_EnterBitmapGrabMode
,
630 HRESULT
MediaDet_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
) {
631 MediaDetImpl
* obj
= NULL
;
633 TRACE("(%p,%p)\n", ppv
, pUnkOuter
);
635 obj
= CoTaskMemAlloc(sizeof(MediaDetImpl
));
638 return E_OUTOFMEMORY
;
640 ZeroMemory(obj
, sizeof(MediaDetImpl
));
643 obj
->IUnknown_inner
.lpVtbl
= &mediadet_vtbl
;
644 obj
->IMediaDet_iface
.lpVtbl
= &IMediaDet_VTable
;
647 obj
->splitter
= NULL
;
649 obj
->num_streams
= -1;
654 obj
->outer_unk
= pUnkOuter
;
656 obj
->outer_unk
= &obj
->IUnknown_inner
;
658 *ppv
= &obj
->IUnknown_inner
;