kernel32: Update version to Win 10.
[wine.git] / dlls / qedit / mediadet.c
blobbacf5208a0869119bc5d865394124439fdec9e39
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 <assert.h>
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
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;
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;
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);
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;
75 static HRESULT get_filter_info(IMoniker *moniker, GUID *clsid, VARIANT *var)
77 IPropertyBag *prop_bag;
78 HRESULT hr;
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);
83 return hr;
86 VariantInit(var);
87 V_VT(var) = VT_BSTR;
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);
92 return hr;
94 CLSIDFromString(V_BSTR(var), clsid);
95 VariantClear(var);
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);
101 return hr;
104 static HRESULT get_pin_media_type(IPin *pin, AM_MEDIA_TYPE *out)
106 IEnumMediaTypes *enummt;
107 AM_MEDIA_TYPE *pmt;
108 HRESULT hr;
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;
117 *out = *pmt;
118 CoTaskMemFree(pmt);
119 return S_OK;
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;
129 AM_MEDIA_TYPE mt;
130 IMoniker *mon;
131 GUID type[2];
132 VARIANT var;
133 HRESULT hr;
134 GUID clsid;
136 if (FAILED(hr = IBaseFilter_EnumPins(detector->source, &enum_pins)))
138 ERR("Failed to enumerate source pins, hr %#x.\n", hr);
139 return hr;
141 hr = IEnumPins_Next(enum_pins, 1, &source_pin, NULL);
142 IEnumPins_Release(enum_pins);
143 if (hr != S_OK)
145 ERR("Failed to get source pin, hr %#x.\n", hr);
146 return 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);
153 return hr;
156 type[0] = mt.majortype;
157 type[1] = mt.subtype;
158 FreeMediaType(&mt);
160 if (FAILED(hr = CoCreateInstance(&CLSID_FilterMapper2, NULL,
161 CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (void **)&mapper)))
163 IPin_Release(source_pin);
164 return hr;
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))
172 IPin_Release(source_pin);
173 return hr;
176 hr = E_NOINTERFACE;
177 while (IEnumMoniker_Next(enum_moniker, 1, &mon, NULL) == S_OK)
179 hr = get_filter_info(mon, &clsid, &var);
180 IMoniker_Release(mon);
181 if (FAILED(hr))
182 continue;
184 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER,
185 &IID_IBaseFilter, (void **)&splitter);
186 if (FAILED(hr))
188 VariantClear(&var);
189 continue;
192 hr = IGraphBuilder_AddFilter(detector->graph, splitter, V_BSTR(&var));
193 VariantClear(&var);
194 if (FAILED(hr))
196 IBaseFilter_Release(splitter);
197 continue;
200 hr = IBaseFilter_EnumPins(splitter, &enum_pins);
201 if (FAILED(hr))
202 goto next;
204 hr = IEnumPins_Next(enum_pins, 1, &splitter_pin, NULL);
205 IEnumPins_Release(enum_pins);
206 if (hr != S_OK)
207 goto next;
209 hr = IPin_Connect(source_pin, splitter_pin, NULL);
210 IPin_Release(splitter_pin);
211 if (SUCCEEDED(hr))
213 detector->splitter = splitter;
214 break;
217 next:
218 IGraphBuilder_RemoveFilter(detector->graph, splitter);
219 IBaseFilter_Release(splitter);
222 IEnumMoniker_Release(enum_moniker);
223 IPin_Release(source_pin);
224 return hr;
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);
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);
242 if (!*ppv)
243 return E_NOINTERFACE;
245 IUnknown_AddRef((IUnknown*)*ppv);
246 return S_OK;
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);
256 return 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);
266 if (ref == 0)
268 MD_cleanup(This);
269 CoTaskMemFree(This);
272 return 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);
307 if (!filter)
308 return E_POINTER;
310 *filter = (IUnknown *)detector->source;
311 if (*filter)
312 IUnknown_AddRef(*filter);
313 else
314 return S_FALSE;
316 return S_OK;
319 static HRESULT WINAPI MediaDet_put_Filter(IMediaDet *iface, IUnknown *unk)
321 MediaDetImpl *detector = impl_from_IMediaDet(iface);
322 IGraphBuilder *graph;
323 IBaseFilter *filter;
324 HRESULT hr;
326 TRACE("detector %p, unk %p.\n", detector, unk);
328 if (!unk)
329 return E_POINTER;
331 if (FAILED(hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter)))
333 WARN("Object does not expose IBaseFilter.\n");
334 return hr;
337 if (detector->graph)
338 MD_cleanup(detector);
340 if (FAILED(hr = CoCreateInstance(&CLSID_FilterGraph, NULL,
341 CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&graph)))
343 IBaseFilter_Release(filter);
344 return hr;
347 if (FAILED(hr = IGraphBuilder_AddFilter(graph, filter, L"Source")))
349 IGraphBuilder_Release(graph);
350 IBaseFilter_Release(filter);
351 return hr;
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);
368 IEnumPins *pins;
369 IPin *pin;
370 HRESULT hr;
372 TRACE("(%p)\n", This);
374 if (!This->splitter)
375 return E_INVALIDARG;
377 if (This->num_streams != -1)
379 *pVal = This->num_streams;
380 return S_OK;
383 *pVal = 0;
385 hr = IBaseFilter_EnumPins(This->splitter, &pins);
386 if (FAILED(hr))
387 return hr;
389 while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK)
391 PIN_DIRECTION dir;
392 hr = IPin_QueryDirection(pin, &dir);
393 IPin_Release(pin);
394 if (FAILED(hr))
396 IEnumPins_Release(pins);
397 return hr;
400 if (dir == PINDIR_OUTPUT)
401 ++*pVal;
403 IEnumPins_Release(pins);
405 This->num_streams = *pVal;
406 return S_OK;
409 static HRESULT WINAPI MediaDet_get_CurrentStream(IMediaDet* iface, LONG *pVal)
411 MediaDetImpl *This = impl_from_IMediaDet(iface);
412 TRACE("(%p)\n", This);
414 if (!pVal)
415 return E_POINTER;
417 *pVal = This->cur_stream;
418 return S_OK;
421 static HRESULT SetCurPin(MediaDetImpl *This, LONG strm)
423 IEnumPins *pins;
424 IPin *pin;
425 HRESULT hr;
427 assert(This->splitter);
428 assert(0 <= strm && strm < This->num_streams);
430 if (This->cur_pin)
432 IPin_Release(This->cur_pin);
433 This->cur_pin = NULL;
436 hr = IBaseFilter_EnumPins(This->splitter, &pins);
437 if (FAILED(hr))
438 return hr;
440 while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK && !This->cur_pin)
442 PIN_DIRECTION dir;
443 hr = IPin_QueryDirection(pin, &dir);
444 if (FAILED(hr))
446 IPin_Release(pin);
447 IEnumPins_Release(pins);
448 return hr;
451 if (dir == PINDIR_OUTPUT && strm-- == 0)
452 This->cur_pin = pin;
453 else
454 IPin_Release(pin);
456 IEnumPins_Release(pins);
458 assert(This->cur_pin);
459 return S_OK;
462 static HRESULT WINAPI MediaDet_put_CurrentStream(IMediaDet* iface, LONG newVal)
464 MediaDetImpl *This = impl_from_IMediaDet(iface);
465 HRESULT hr;
467 TRACE("(%p)->(%d)\n", This, newVal);
469 if (This->num_streams == -1)
471 LONG n;
472 hr = MediaDet_get_OutputStreams(iface, &n);
473 if (FAILED(hr))
474 return hr;
477 if (newVal < 0 || This->num_streams <= newVal)
478 return E_INVALIDARG;
480 hr = SetCurPin(This, newVal);
481 if (FAILED(hr))
482 return hr;
484 This->cur_stream = newVal;
485 return S_OK;
488 static HRESULT WINAPI MediaDet_get_StreamType(IMediaDet *iface, GUID *majortype)
490 MediaDetImpl *detector = impl_from_IMediaDet(iface);
491 AM_MEDIA_TYPE mt;
492 HRESULT hr;
494 TRACE("detector %p, majortype %p.\n", detector, majortype);
496 if (!majortype)
497 return E_POINTER;
499 if (SUCCEEDED(hr = IMediaDet_get_StreamMediaType(iface, &mt)))
501 *majortype = mt.majortype;
502 FreeMediaType(&mt);
505 return hr;
508 static HRESULT WINAPI MediaDet_get_StreamTypeB(IMediaDet *iface, BSTR *bstr)
510 MediaDetImpl *detector = impl_from_IMediaDet(iface);
511 HRESULT hr;
512 GUID guid;
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);
522 return hr;
525 static HRESULT WINAPI MediaDet_get_StreamLength(IMediaDet *iface, double *length)
527 MediaDetImpl *detector = impl_from_IMediaDet(iface);
528 IMediaSeeking *seeking;
529 HRESULT hr;
531 TRACE("detector %p, length %p.\n", detector, length);
533 if (!length)
534 return E_POINTER;
536 if (!detector->cur_pin)
537 return E_INVALIDARG;
539 if (SUCCEEDED(hr = IPin_QueryInterface(detector->cur_pin,
540 &IID_IMediaSeeking, (void **)&seeking)))
542 LONGLONG duration;
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);
553 return hr;
556 static HRESULT WINAPI MediaDet_get_Filename(IMediaDet* iface, BSTR *pVal)
558 MediaDetImpl *This = impl_from_IMediaDet(iface);
560 TRACE("(%p)\n", This);
562 if (!pVal)
563 return E_POINTER;
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;
571 *pVal = SysAllocString(This->filename);
572 if (!*pVal)
573 return E_OUTOFMEMORY;
575 return S_OK;
578 static HRESULT WINAPI MediaDet_put_Filename(IMediaDet *iface, BSTR filename)
580 MediaDetImpl *This = impl_from_IMediaDet(iface);
581 IGraphBuilder *gb;
582 IBaseFilter *bf;
583 HRESULT hr;
585 TRACE("detector %p, filename %s.\n", This, debugstr_w(filename));
587 if (This->graph)
589 WARN("MSDN says not to call this method twice\n");
590 MD_cleanup(This);
593 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
594 &IID_IGraphBuilder, (void **) &gb);
595 if (FAILED(hr))
596 return hr;
598 if (FAILED(hr = IGraphBuilder_AddSourceFilter(gb, filename, L"Source", &bf)))
600 IGraphBuilder_Release(gb);
601 return hr;
604 if (!(This->filename = wcsdup(filename)))
606 IBaseFilter_Release(bf);
607 IGraphBuilder_Release(gb);
608 return E_OUTOFMEMORY;
611 This->graph = gb;
612 This->source = bf;
613 hr = find_splitter(This);
614 if (FAILED(hr))
615 return hr;
617 return MediaDet_put_CurrentStream(iface, 0);
620 static HRESULT WINAPI MediaDet_GetBitmapBits(IMediaDet* iface,
621 double StreamTime,
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,
627 Width, Height);
628 return E_NOTIMPL;
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);
637 return E_NOTIMPL;
640 static HRESULT WINAPI MediaDet_get_StreamMediaType(IMediaDet* iface,
641 AM_MEDIA_TYPE *pVal)
643 MediaDetImpl *This = impl_from_IMediaDet(iface);
645 TRACE("(%p)\n", This);
647 if (!pVal)
648 return E_POINTER;
650 if (!This->cur_pin)
651 return E_INVALIDARG;
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);
661 return E_NOTIMPL;
664 static HRESULT WINAPI MediaDet_get_FrameRate(IMediaDet* iface, double *pVal)
666 MediaDetImpl *This = impl_from_IMediaDet(iface);
667 AM_MEDIA_TYPE mt;
668 VIDEOINFOHEADER *vh;
669 HRESULT hr;
671 TRACE("(%p)\n", This);
673 if (!pVal)
674 return E_POINTER;
676 hr = MediaDet_get_StreamMediaType(iface, &mt);
677 if (FAILED(hr))
678 return hr;
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);
690 return S_OK;
693 static HRESULT WINAPI MediaDet_EnterBitmapGrabMode(IMediaDet* iface,
694 double SeekTime)
696 MediaDetImpl *This = impl_from_IMediaDet(iface);
697 FIXME("(%p)->(%f): not implemented!\n", This, SeekTime);
698 return E_NOTIMPL;
701 static const IMediaDetVtbl IMediaDet_VTable =
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,
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));
731 if (NULL == obj) {
732 *ppv = NULL;
733 return E_OUTOFMEMORY;
735 ZeroMemory(obj, sizeof(MediaDetImpl));
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;
747 if (pUnkOuter)
748 obj->outer_unk = pUnkOuter;
749 else
750 obj->outer_unk = &obj->IUnknown_inner;
752 *ppv = &obj->IUnknown_inner;
753 return S_OK;