wsdapi: Add a trailing '\n' to a WARN() message.
[wine.git] / dlls / qedit / mediadet.c
blobb7a5abb80caa9b69bef8adb0c45256192d35495e
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 LONG num_streams;
44 LONG cur_stream;
45 IPin *cur_pin;
46 } MediaDetImpl;
48 static inline MediaDetImpl *impl_from_IUnknown(IUnknown *iface)
50 return CONTAINING_RECORD(iface, MediaDetImpl, IUnknown_inner);
53 static inline MediaDetImpl *impl_from_IMediaDet(IMediaDet *iface)
55 return CONTAINING_RECORD(iface, MediaDetImpl, IMediaDet_iface);
58 static void MD_cleanup(MediaDetImpl *This)
60 if (This->cur_pin) IPin_Release(This->cur_pin);
61 This->cur_pin = NULL;
62 if (This->source) IBaseFilter_Release(This->source);
63 This->source = NULL;
64 if (This->splitter) IBaseFilter_Release(This->splitter);
65 This->splitter = NULL;
66 if (This->graph) IGraphBuilder_Release(This->graph);
67 This->graph = NULL;
68 This->num_streams = -1;
69 This->cur_stream = 0;
72 /* MediaDet inner IUnknown */
73 static HRESULT WINAPI MediaDet_inner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
75 MediaDetImpl *This = impl_from_IUnknown(iface);
77 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
79 *ppv = NULL;
80 if (IsEqualIID(riid, &IID_IUnknown))
81 *ppv = &This->IUnknown_inner;
82 else if (IsEqualIID(riid, &IID_IMediaDet))
83 *ppv = &This->IMediaDet_iface;
84 else
85 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
87 if (!*ppv)
88 return E_NOINTERFACE;
90 IUnknown_AddRef((IUnknown*)*ppv);
91 return S_OK;
94 static ULONG WINAPI MediaDet_inner_AddRef(IUnknown *iface)
96 MediaDetImpl *This = impl_from_IUnknown(iface);
97 ULONG ref = InterlockedIncrement(&This->ref);
99 TRACE("(%p) new ref = %u\n", This, ref);
101 return ref;
104 static ULONG WINAPI MediaDet_inner_Release(IUnknown *iface)
106 MediaDetImpl *This = impl_from_IUnknown(iface);
107 ULONG ref = InterlockedDecrement(&This->ref);
109 TRACE("(%p) new ref = %u\n", This, ref);
111 if (ref == 0)
113 MD_cleanup(This);
114 CoTaskMemFree(This);
117 return ref;
120 static const IUnknownVtbl mediadet_vtbl =
122 MediaDet_inner_QueryInterface,
123 MediaDet_inner_AddRef,
124 MediaDet_inner_Release,
127 /* IMediaDet implementation */
128 static HRESULT WINAPI MediaDet_QueryInterface(IMediaDet *iface, REFIID riid, void **ppv)
130 MediaDetImpl *This = impl_from_IMediaDet(iface);
131 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
134 static ULONG WINAPI MediaDet_AddRef(IMediaDet *iface)
136 MediaDetImpl *This = impl_from_IMediaDet(iface);
137 return IUnknown_AddRef(This->outer_unk);
140 static ULONG WINAPI MediaDet_Release(IMediaDet *iface)
142 MediaDetImpl *This = impl_from_IMediaDet(iface);
143 return IUnknown_Release(This->outer_unk);
146 static HRESULT WINAPI MediaDet_get_Filter(IMediaDet* iface, IUnknown **pVal)
148 MediaDetImpl *This = impl_from_IMediaDet(iface);
149 FIXME("(%p)->(%p): not implemented!\n", This, pVal);
150 return E_NOTIMPL;
153 static HRESULT WINAPI MediaDet_put_Filter(IMediaDet* iface, IUnknown *newVal)
155 MediaDetImpl *This = impl_from_IMediaDet(iface);
156 FIXME("(%p)->(%p): not implemented!\n", This, newVal);
157 return E_NOTIMPL;
160 static HRESULT WINAPI MediaDet_get_OutputStreams(IMediaDet* iface, LONG *pVal)
162 MediaDetImpl *This = impl_from_IMediaDet(iface);
163 IEnumPins *pins;
164 IPin *pin;
165 HRESULT hr;
167 TRACE("(%p)\n", This);
169 if (!This->splitter)
170 return E_INVALIDARG;
172 if (This->num_streams != -1)
174 *pVal = This->num_streams;
175 return S_OK;
178 *pVal = 0;
180 hr = IBaseFilter_EnumPins(This->splitter, &pins);
181 if (FAILED(hr))
182 return hr;
184 while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK)
186 PIN_DIRECTION dir;
187 hr = IPin_QueryDirection(pin, &dir);
188 IPin_Release(pin);
189 if (FAILED(hr))
191 IEnumPins_Release(pins);
192 return hr;
195 if (dir == PINDIR_OUTPUT)
196 ++*pVal;
198 IEnumPins_Release(pins);
200 This->num_streams = *pVal;
201 return S_OK;
204 static HRESULT WINAPI MediaDet_get_CurrentStream(IMediaDet* iface, LONG *pVal)
206 MediaDetImpl *This = impl_from_IMediaDet(iface);
207 TRACE("(%p)\n", This);
209 if (!pVal)
210 return E_POINTER;
212 *pVal = This->cur_stream;
213 return S_OK;
216 static HRESULT SetCurPin(MediaDetImpl *This, LONG strm)
218 IEnumPins *pins;
219 IPin *pin;
220 HRESULT hr;
222 assert(This->splitter);
223 assert(0 <= strm && strm < This->num_streams);
225 if (This->cur_pin)
227 IPin_Release(This->cur_pin);
228 This->cur_pin = NULL;
231 hr = IBaseFilter_EnumPins(This->splitter, &pins);
232 if (FAILED(hr))
233 return hr;
235 while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK && !This->cur_pin)
237 PIN_DIRECTION dir;
238 hr = IPin_QueryDirection(pin, &dir);
239 if (FAILED(hr))
241 IPin_Release(pin);
242 IEnumPins_Release(pins);
243 return hr;
246 if (dir == PINDIR_OUTPUT && strm-- == 0)
247 This->cur_pin = pin;
248 else
249 IPin_Release(pin);
251 IEnumPins_Release(pins);
253 assert(This->cur_pin);
254 return S_OK;
257 static HRESULT WINAPI MediaDet_put_CurrentStream(IMediaDet* iface, LONG newVal)
259 MediaDetImpl *This = impl_from_IMediaDet(iface);
260 HRESULT hr;
262 TRACE("(%p)->(%d)\n", This, newVal);
264 if (This->num_streams == -1)
266 LONG n;
267 hr = MediaDet_get_OutputStreams(iface, &n);
268 if (FAILED(hr))
269 return hr;
272 if (newVal < 0 || This->num_streams <= newVal)
273 return E_INVALIDARG;
275 hr = SetCurPin(This, newVal);
276 if (FAILED(hr))
277 return hr;
279 This->cur_stream = newVal;
280 return S_OK;
283 static HRESULT WINAPI MediaDet_get_StreamType(IMediaDet* iface, GUID *pVal)
285 MediaDetImpl *This = impl_from_IMediaDet(iface);
286 FIXME("(%p)->(%s): not implemented!\n", This, debugstr_guid(pVal));
287 return E_NOTIMPL;
290 static HRESULT WINAPI MediaDet_get_StreamTypeB(IMediaDet* iface, BSTR *pVal)
292 MediaDetImpl *This = impl_from_IMediaDet(iface);
293 FIXME("(%p)->(%p): not implemented!\n", This, pVal);
294 return E_NOTIMPL;
297 static HRESULT WINAPI MediaDet_get_StreamLength(IMediaDet* iface, double *pVal)
299 MediaDetImpl *This = impl_from_IMediaDet(iface);
300 FIXME("(%p): stub!\n", This);
301 return VFW_E_INVALIDMEDIATYPE;
304 static HRESULT WINAPI MediaDet_get_Filename(IMediaDet* iface, BSTR *pVal)
306 MediaDetImpl *This = impl_from_IMediaDet(iface);
307 IFileSourceFilter *file;
308 LPOLESTR name;
309 HRESULT hr;
311 TRACE("(%p)\n", This);
313 if (!pVal)
314 return E_POINTER;
316 *pVal = NULL;
317 /* MSDN says it should return E_FAIL if no file is open, but tests
318 show otherwise. */
319 if (!This->source)
320 return S_OK;
322 hr = IBaseFilter_QueryInterface(This->source, &IID_IFileSourceFilter,
323 (void **) &file);
324 if (FAILED(hr))
325 return hr;
327 hr = IFileSourceFilter_GetCurFile(file, &name, NULL);
328 IFileSourceFilter_Release(file);
329 if (FAILED(hr))
330 return hr;
332 *pVal = SysAllocString(name);
333 CoTaskMemFree(name);
334 if (!*pVal)
335 return E_OUTOFMEMORY;
337 return S_OK;
340 /* From quartz, 2008/04/07 */
341 static HRESULT GetFilterInfo(IMoniker *pMoniker, GUID *pclsid, VARIANT *pvar)
343 static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
344 static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
345 IPropertyBag *pPropBagCat = NULL;
346 HRESULT hr;
348 VariantInit(pvar);
349 V_VT(pvar) = VT_BSTR;
351 hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag,
352 (LPVOID *) &pPropBagCat);
354 if (SUCCEEDED(hr))
355 hr = IPropertyBag_Read(pPropBagCat, wszClsidName, pvar, NULL);
357 if (SUCCEEDED(hr))
359 hr = CLSIDFromString(V_BSTR(pvar), pclsid);
360 VariantClear(pvar);
361 V_VT(pvar) = VT_BSTR;
364 if (SUCCEEDED(hr))
365 hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
367 if (SUCCEEDED(hr))
368 TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), debugstr_w(V_BSTR(pvar)));
370 if (pPropBagCat)
371 IPropertyBag_Release(pPropBagCat);
373 return hr;
376 static HRESULT GetSplitter(MediaDetImpl *This)
378 IFileSourceFilter *file;
379 LPOLESTR name;
380 AM_MEDIA_TYPE mt;
381 GUID type[2];
382 IFilterMapper2 *map;
383 IEnumMoniker *filters;
384 IMoniker *mon;
385 VARIANT var;
386 GUID clsid;
387 IBaseFilter *splitter;
388 IEnumPins *pins;
389 IPin *source_pin, *splitter_pin;
390 HRESULT hr;
392 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
393 &IID_IFilterMapper2, (void **) &map);
394 if (FAILED(hr))
395 return hr;
397 hr = IBaseFilter_QueryInterface(This->source, &IID_IFileSourceFilter,
398 (void **) &file);
399 if (FAILED(hr))
401 IFilterMapper2_Release(map);
402 return hr;
405 hr = IFileSourceFilter_GetCurFile(file, &name, &mt);
406 IFileSourceFilter_Release(file);
407 CoTaskMemFree(name);
408 if (FAILED(hr))
410 IFilterMapper2_Release(map);
411 return hr;
413 type[0] = mt.majortype;
414 type[1] = mt.subtype;
415 CoTaskMemFree(mt.pbFormat);
417 hr = IFilterMapper2_EnumMatchingFilters(map, &filters, 0, TRUE,
418 MERIT_UNLIKELY, FALSE, 1, type,
419 NULL, NULL, FALSE, TRUE,
420 0, NULL, NULL, NULL);
421 IFilterMapper2_Release(map);
422 if (FAILED(hr))
423 return hr;
425 hr = E_NOINTERFACE;
426 while (IEnumMoniker_Next(filters, 1, &mon, NULL) == S_OK)
428 hr = GetFilterInfo(mon, &clsid, &var);
429 IMoniker_Release(mon);
430 if (FAILED(hr))
431 continue;
433 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER,
434 &IID_IBaseFilter, (void **) &splitter);
435 if (FAILED(hr))
437 VariantClear(&var);
438 continue;
441 hr = IGraphBuilder_AddFilter(This->graph, splitter, V_BSTR(&var));
442 VariantClear(&var);
443 This->splitter = splitter;
444 if (FAILED(hr))
445 goto retry;
447 hr = IBaseFilter_EnumPins(This->source, &pins);
448 if (FAILED(hr))
449 goto retry;
450 IEnumPins_Next(pins, 1, &source_pin, NULL);
451 IEnumPins_Release(pins);
453 hr = IBaseFilter_EnumPins(splitter, &pins);
454 if (FAILED(hr))
456 IPin_Release(source_pin);
457 goto retry;
459 IEnumPins_Next(pins, 1, &splitter_pin, NULL);
460 IEnumPins_Release(pins);
462 hr = IPin_Connect(source_pin, splitter_pin, NULL);
463 IPin_Release(source_pin);
464 IPin_Release(splitter_pin);
465 if (SUCCEEDED(hr))
466 break;
468 retry:
469 IBaseFilter_Release(splitter);
470 This->splitter = NULL;
473 IEnumMoniker_Release(filters);
474 if (FAILED(hr))
475 return hr;
477 return S_OK;
480 static HRESULT WINAPI MediaDet_put_Filename(IMediaDet* iface, BSTR newVal)
482 static const WCHAR reader[] = {'R','e','a','d','e','r',0};
483 MediaDetImpl *This = impl_from_IMediaDet(iface);
484 IGraphBuilder *gb;
485 IBaseFilter *bf;
486 HRESULT hr;
488 TRACE("(%p)->(%s)\n", This, debugstr_w(newVal));
490 if (This->graph)
492 WARN("MSDN says not to call this method twice\n");
493 MD_cleanup(This);
496 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
497 &IID_IGraphBuilder, (void **) &gb);
498 if (FAILED(hr))
499 return hr;
501 hr = IGraphBuilder_AddSourceFilter(gb, newVal, reader, &bf);
502 if (FAILED(hr))
504 IGraphBuilder_Release(gb);
505 return hr;
508 This->graph = gb;
509 This->source = bf;
510 hr = GetSplitter(This);
511 if (FAILED(hr))
512 return hr;
514 return MediaDet_put_CurrentStream(iface, 0);
517 static HRESULT WINAPI MediaDet_GetBitmapBits(IMediaDet* iface,
518 double StreamTime,
519 LONG *pBufferSize, char *pBuffer,
520 LONG Width, LONG Height)
522 MediaDetImpl *This = impl_from_IMediaDet(iface);
523 FIXME("(%p)->(%f %p %p %d %d): not implemented!\n", This, StreamTime, pBufferSize, pBuffer,
524 Width, Height);
525 return E_NOTIMPL;
528 static HRESULT WINAPI MediaDet_WriteBitmapBits(IMediaDet* iface,
529 double StreamTime, LONG Width,
530 LONG Height, BSTR Filename)
532 MediaDetImpl *This = impl_from_IMediaDet(iface);
533 FIXME("(%p)->(%f %d %d %p): not implemented!\n", This, StreamTime, Width, Height, Filename);
534 return E_NOTIMPL;
537 static HRESULT WINAPI MediaDet_get_StreamMediaType(IMediaDet* iface,
538 AM_MEDIA_TYPE *pVal)
540 MediaDetImpl *This = impl_from_IMediaDet(iface);
541 IEnumMediaTypes *types;
542 AM_MEDIA_TYPE *pmt;
543 HRESULT hr;
545 TRACE("(%p)\n", This);
547 if (!pVal)
548 return E_POINTER;
550 if (!This->cur_pin)
551 return E_INVALIDARG;
553 hr = IPin_EnumMediaTypes(This->cur_pin, &types);
554 if (SUCCEEDED(hr))
556 hr = (IEnumMediaTypes_Next(types, 1, &pmt, NULL) == S_OK
557 ? S_OK
558 : E_NOINTERFACE);
559 IEnumMediaTypes_Release(types);
562 if (SUCCEEDED(hr))
564 *pVal = *pmt;
565 CoTaskMemFree(pmt);
568 return hr;
571 static HRESULT WINAPI MediaDet_GetSampleGrabber(IMediaDet* iface,
572 ISampleGrabber **ppVal)
574 MediaDetImpl *This = impl_from_IMediaDet(iface);
575 FIXME("(%p)->(%p): not implemented!\n", This, ppVal);
576 return E_NOTIMPL;
579 static HRESULT WINAPI MediaDet_get_FrameRate(IMediaDet* iface, double *pVal)
581 MediaDetImpl *This = impl_from_IMediaDet(iface);
582 AM_MEDIA_TYPE mt;
583 VIDEOINFOHEADER *vh;
584 HRESULT hr;
586 TRACE("(%p)\n", This);
588 if (!pVal)
589 return E_POINTER;
591 hr = MediaDet_get_StreamMediaType(iface, &mt);
592 if (FAILED(hr))
593 return hr;
595 if (!IsEqualGUID(&mt.majortype, &MEDIATYPE_Video))
597 CoTaskMemFree(mt.pbFormat);
598 return VFW_E_INVALIDMEDIATYPE;
601 vh = (VIDEOINFOHEADER *) mt.pbFormat;
602 *pVal = 1.0e7 / (double) vh->AvgTimePerFrame;
604 CoTaskMemFree(mt.pbFormat);
605 return S_OK;
608 static HRESULT WINAPI MediaDet_EnterBitmapGrabMode(IMediaDet* iface,
609 double SeekTime)
611 MediaDetImpl *This = impl_from_IMediaDet(iface);
612 FIXME("(%p)->(%f): not implemented!\n", This, SeekTime);
613 return E_NOTIMPL;
616 static const IMediaDetVtbl IMediaDet_VTable =
618 MediaDet_QueryInterface,
619 MediaDet_AddRef,
620 MediaDet_Release,
621 MediaDet_get_Filter,
622 MediaDet_put_Filter,
623 MediaDet_get_OutputStreams,
624 MediaDet_get_CurrentStream,
625 MediaDet_put_CurrentStream,
626 MediaDet_get_StreamType,
627 MediaDet_get_StreamTypeB,
628 MediaDet_get_StreamLength,
629 MediaDet_get_Filename,
630 MediaDet_put_Filename,
631 MediaDet_GetBitmapBits,
632 MediaDet_WriteBitmapBits,
633 MediaDet_get_StreamMediaType,
634 MediaDet_GetSampleGrabber,
635 MediaDet_get_FrameRate,
636 MediaDet_EnterBitmapGrabMode,
639 HRESULT MediaDet_create(IUnknown * pUnkOuter, LPVOID * ppv) {
640 MediaDetImpl* obj = NULL;
642 TRACE("(%p,%p)\n", pUnkOuter, ppv);
644 obj = CoTaskMemAlloc(sizeof(MediaDetImpl));
645 if (NULL == obj) {
646 *ppv = NULL;
647 return E_OUTOFMEMORY;
649 ZeroMemory(obj, sizeof(MediaDetImpl));
651 obj->ref = 1;
652 obj->IUnknown_inner.lpVtbl = &mediadet_vtbl;
653 obj->IMediaDet_iface.lpVtbl = &IMediaDet_VTable;
654 obj->graph = NULL;
655 obj->source = NULL;
656 obj->splitter = NULL;
657 obj->cur_pin = NULL;
658 obj->num_streams = -1;
659 obj->cur_stream = 0;
661 if (pUnkOuter)
662 obj->outer_unk = pUnkOuter;
663 else
664 obj->outer_unk = &obj->IUnknown_inner;
666 *ppv = &obj->IUnknown_inner;
667 return S_OK;