ntdll: Use list_empty() instead of list_count() == 0.
[wine/multimedia.git] / dlls / qedit / mediadet.c
blob38a54ce9c4e7996cf4ffc6490906c115c33c975d
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 IMediaDet IMediaDet_iface;
37 LONG refCount;
38 IGraphBuilder *graph;
39 IBaseFilter *source;
40 IBaseFilter *splitter;
41 LONG num_streams;
42 LONG cur_stream;
43 IPin *cur_pin;
44 } MediaDetImpl;
46 static inline MediaDetImpl *impl_from_IMediaDet(IMediaDet *iface)
48 return CONTAINING_RECORD(iface, MediaDetImpl, IMediaDet_iface);
51 static void MD_cleanup(MediaDetImpl *This)
53 if (This->cur_pin) IPin_Release(This->cur_pin);
54 This->cur_pin = NULL;
55 if (This->source) IBaseFilter_Release(This->source);
56 This->source = NULL;
57 if (This->splitter) IBaseFilter_Release(This->splitter);
58 This->splitter = NULL;
59 if (This->graph) IGraphBuilder_Release(This->graph);
60 This->graph = NULL;
61 This->num_streams = -1;
62 This->cur_stream = 0;
65 static ULONG WINAPI MediaDet_AddRef(IMediaDet* iface)
67 MediaDetImpl *This = impl_from_IMediaDet(iface);
68 ULONG refCount = InterlockedIncrement(&This->refCount);
69 TRACE("(%p)->() AddRef from %d\n", This, refCount - 1);
70 return refCount;
73 static ULONG WINAPI MediaDet_Release(IMediaDet* iface)
75 MediaDetImpl *This = impl_from_IMediaDet(iface);
76 ULONG refCount = InterlockedDecrement(&This->refCount);
77 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
79 if (refCount == 0)
81 MD_cleanup(This);
82 CoTaskMemFree(This);
83 return 0;
86 return refCount;
89 static HRESULT WINAPI MediaDet_QueryInterface(IMediaDet* iface, REFIID riid,
90 void **ppvObject)
92 MediaDetImpl *This = impl_from_IMediaDet(iface);
93 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
95 if (IsEqualIID(riid, &IID_IUnknown) ||
96 IsEqualIID(riid, &IID_IMediaDet)) {
97 MediaDet_AddRef(iface);
98 *ppvObject = This;
99 return S_OK;
101 *ppvObject = NULL;
102 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
103 return E_NOINTERFACE;
106 static HRESULT WINAPI MediaDet_get_Filter(IMediaDet* iface, IUnknown **pVal)
108 MediaDetImpl *This = impl_from_IMediaDet(iface);
109 FIXME("(%p)->(%p): not implemented!\n", This, pVal);
110 return E_NOTIMPL;
113 static HRESULT WINAPI MediaDet_put_Filter(IMediaDet* iface, IUnknown *newVal)
115 MediaDetImpl *This = impl_from_IMediaDet(iface);
116 FIXME("(%p)->(%p): not implemented!\n", This, newVal);
117 return E_NOTIMPL;
120 static HRESULT WINAPI MediaDet_get_OutputStreams(IMediaDet* iface, LONG *pVal)
122 MediaDetImpl *This = impl_from_IMediaDet(iface);
123 IEnumPins *pins;
124 IPin *pin;
125 HRESULT hr;
127 TRACE("(%p)\n", This);
129 if (!This->splitter)
130 return E_INVALIDARG;
132 if (This->num_streams != -1)
134 *pVal = This->num_streams;
135 return S_OK;
138 *pVal = 0;
140 hr = IBaseFilter_EnumPins(This->splitter, &pins);
141 if (FAILED(hr))
142 return hr;
144 while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK)
146 PIN_DIRECTION dir;
147 hr = IPin_QueryDirection(pin, &dir);
148 IPin_Release(pin);
149 if (FAILED(hr))
151 IEnumPins_Release(pins);
152 return hr;
155 if (dir == PINDIR_OUTPUT)
156 ++*pVal;
158 IEnumPins_Release(pins);
160 This->num_streams = *pVal;
161 return S_OK;
164 static HRESULT WINAPI MediaDet_get_CurrentStream(IMediaDet* iface, LONG *pVal)
166 MediaDetImpl *This = impl_from_IMediaDet(iface);
167 TRACE("(%p)\n", This);
169 if (!pVal)
170 return E_POINTER;
172 *pVal = This->cur_stream;
173 return S_OK;
176 static HRESULT SetCurPin(MediaDetImpl *This, LONG strm)
178 IEnumPins *pins;
179 IPin *pin;
180 HRESULT hr;
182 assert(This->splitter);
183 assert(0 <= strm && strm < This->num_streams);
185 if (This->cur_pin)
187 IPin_Release(This->cur_pin);
188 This->cur_pin = NULL;
191 hr = IBaseFilter_EnumPins(This->splitter, &pins);
192 if (FAILED(hr))
193 return hr;
195 while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK && !This->cur_pin)
197 PIN_DIRECTION dir;
198 hr = IPin_QueryDirection(pin, &dir);
199 if (FAILED(hr))
201 IPin_Release(pin);
202 IEnumPins_Release(pins);
203 return hr;
206 if (dir == PINDIR_OUTPUT && strm-- == 0)
207 This->cur_pin = pin;
208 else
209 IPin_Release(pin);
211 IEnumPins_Release(pins);
213 assert(This->cur_pin);
214 return S_OK;
217 static HRESULT WINAPI MediaDet_put_CurrentStream(IMediaDet* iface, LONG newVal)
219 MediaDetImpl *This = impl_from_IMediaDet(iface);
220 HRESULT hr;
222 TRACE("(%p)->(%d)\n", This, newVal);
224 if (This->num_streams == -1)
226 LONG n;
227 hr = MediaDet_get_OutputStreams(iface, &n);
228 if (FAILED(hr))
229 return hr;
232 if (newVal < 0 || This->num_streams <= newVal)
233 return E_INVALIDARG;
235 hr = SetCurPin(This, newVal);
236 if (FAILED(hr))
237 return hr;
239 This->cur_stream = newVal;
240 return S_OK;
243 static HRESULT WINAPI MediaDet_get_StreamType(IMediaDet* iface, GUID *pVal)
245 MediaDetImpl *This = impl_from_IMediaDet(iface);
246 FIXME("(%p)->(%p): not implemented!\n", This, debugstr_guid(pVal));
247 return E_NOTIMPL;
250 static HRESULT WINAPI MediaDet_get_StreamTypeB(IMediaDet* iface, BSTR *pVal)
252 MediaDetImpl *This = impl_from_IMediaDet(iface);
253 FIXME("(%p)->(%p): not implemented!\n", This, pVal);
254 return E_NOTIMPL;
257 static HRESULT WINAPI MediaDet_get_StreamLength(IMediaDet* iface, double *pVal)
259 MediaDetImpl *This = impl_from_IMediaDet(iface);
260 FIXME("(%p): stub!\n", This);
261 return VFW_E_INVALIDMEDIATYPE;
264 static HRESULT WINAPI MediaDet_get_Filename(IMediaDet* iface, BSTR *pVal)
266 MediaDetImpl *This = impl_from_IMediaDet(iface);
267 IFileSourceFilter *file;
268 LPOLESTR name;
269 HRESULT hr;
271 TRACE("(%p)\n", This);
273 if (!pVal)
274 return E_POINTER;
276 *pVal = NULL;
277 /* MSDN says it should return E_FAIL if no file is open, but tests
278 show otherwise. */
279 if (!This->source)
280 return S_OK;
282 hr = IBaseFilter_QueryInterface(This->source, &IID_IFileSourceFilter,
283 (void **) &file);
284 if (FAILED(hr))
285 return hr;
287 hr = IFileSourceFilter_GetCurFile(file, &name, NULL);
288 IFileSourceFilter_Release(file);
289 if (FAILED(hr))
290 return hr;
292 *pVal = SysAllocString(name);
293 CoTaskMemFree(name);
294 if (!*pVal)
295 return E_OUTOFMEMORY;
297 return S_OK;
300 /* From quartz, 2008/04/07 */
301 static HRESULT GetFilterInfo(IMoniker *pMoniker, GUID *pclsid, VARIANT *pvar)
303 static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
304 static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
305 IPropertyBag *pPropBagCat = NULL;
306 HRESULT hr;
308 VariantInit(pvar);
309 V_VT(pvar) = VT_BSTR;
311 hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag,
312 (LPVOID *) &pPropBagCat);
314 if (SUCCEEDED(hr))
315 hr = IPropertyBag_Read(pPropBagCat, wszClsidName, pvar, NULL);
317 if (SUCCEEDED(hr))
319 hr = CLSIDFromString(V_UNION(pvar, bstrVal), pclsid);
320 VariantClear(pvar);
321 V_VT(pvar) = VT_BSTR;
324 if (SUCCEEDED(hr))
325 hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
327 if (SUCCEEDED(hr))
328 TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid),
329 debugstr_w(V_UNION(pvar, bstrVal)));
331 if (pPropBagCat)
332 IPropertyBag_Release(pPropBagCat);
334 return hr;
337 static HRESULT GetSplitter(MediaDetImpl *This)
339 IFileSourceFilter *file;
340 LPOLESTR name;
341 AM_MEDIA_TYPE mt;
342 GUID type[2];
343 IFilterMapper2 *map;
344 IEnumMoniker *filters;
345 IMoniker *mon;
346 VARIANT var;
347 GUID clsid;
348 IBaseFilter *splitter;
349 IEnumPins *pins;
350 IPin *source_pin, *splitter_pin;
351 HRESULT hr;
353 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
354 &IID_IFilterMapper2, (void **) &map);
355 if (FAILED(hr))
356 return hr;
358 hr = IBaseFilter_QueryInterface(This->source, &IID_IFileSourceFilter,
359 (void **) &file);
360 if (FAILED(hr))
362 IFilterMapper2_Release(map);
363 return hr;
366 hr = IFileSourceFilter_GetCurFile(file, &name, &mt);
367 IFileSourceFilter_Release(file);
368 CoTaskMemFree(name);
369 if (FAILED(hr))
371 IFilterMapper2_Release(map);
372 return hr;
374 type[0] = mt.majortype;
375 type[1] = mt.subtype;
376 CoTaskMemFree(mt.pbFormat);
378 hr = IFilterMapper2_EnumMatchingFilters(map, &filters, 0, TRUE,
379 MERIT_UNLIKELY, FALSE, 1, type,
380 NULL, NULL, FALSE, TRUE,
381 0, NULL, NULL, NULL);
382 IFilterMapper2_Release(map);
383 if (FAILED(hr))
384 return hr;
386 hr = E_NOINTERFACE;
387 while (IEnumMoniker_Next(filters, 1, &mon, NULL) == S_OK)
389 hr = GetFilterInfo(mon, &clsid, &var);
390 IMoniker_Release(mon);
391 if (FAILED(hr))
392 continue;
394 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER,
395 &IID_IBaseFilter, (void **) &splitter);
396 if (FAILED(hr))
398 VariantClear(&var);
399 goto retry;
402 hr = IGraphBuilder_AddFilter(This->graph, splitter,
403 V_UNION(&var, bstrVal));
404 VariantClear(&var);
405 This->splitter = splitter;
406 if (FAILED(hr))
407 goto retry;
409 hr = IBaseFilter_EnumPins(This->source, &pins);
410 if (FAILED(hr))
411 goto retry;
412 IEnumPins_Next(pins, 1, &source_pin, NULL);
413 IEnumPins_Release(pins);
415 hr = IBaseFilter_EnumPins(splitter, &pins);
416 if (FAILED(hr))
418 IPin_Release(source_pin);
419 goto retry;
421 IEnumPins_Next(pins, 1, &splitter_pin, NULL);
422 IEnumPins_Release(pins);
424 hr = IPin_Connect(source_pin, splitter_pin, NULL);
425 IPin_Release(source_pin);
426 IPin_Release(splitter_pin);
427 if (SUCCEEDED(hr))
428 break;
430 retry:
431 IBaseFilter_Release(splitter);
432 This->splitter = NULL;
435 IEnumMoniker_Release(filters);
436 if (FAILED(hr))
437 return hr;
439 return S_OK;
442 static HRESULT WINAPI MediaDet_put_Filename(IMediaDet* iface, BSTR newVal)
444 static const WCHAR reader[] = {'R','e','a','d','e','r',0};
445 MediaDetImpl *This = impl_from_IMediaDet(iface);
446 IGraphBuilder *gb;
447 IBaseFilter *bf;
448 HRESULT hr;
450 TRACE("(%p)->(%s)\n", This, debugstr_w(newVal));
452 if (This->graph)
454 WARN("MSDN says not to call this method twice\n");
455 MD_cleanup(This);
458 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
459 &IID_IGraphBuilder, (void **) &gb);
460 if (FAILED(hr))
461 return hr;
463 hr = IGraphBuilder_AddSourceFilter(gb, newVal, reader, &bf);
464 if (FAILED(hr))
466 IGraphBuilder_Release(gb);
467 return hr;
470 This->graph = gb;
471 This->source = bf;
472 hr = GetSplitter(This);
473 if (FAILED(hr))
474 return hr;
476 return MediaDet_put_CurrentStream(iface, 0);
479 static HRESULT WINAPI MediaDet_GetBitmapBits(IMediaDet* iface,
480 double StreamTime,
481 LONG *pBufferSize, char *pBuffer,
482 LONG Width, LONG Height)
484 MediaDetImpl *This = impl_from_IMediaDet(iface);
485 FIXME("(%p)->(%f %p %p %d %d): not implemented!\n", This, StreamTime, pBufferSize, pBuffer,
486 Width, Height);
487 return E_NOTIMPL;
490 static HRESULT WINAPI MediaDet_WriteBitmapBits(IMediaDet* iface,
491 double StreamTime, LONG Width,
492 LONG Height, BSTR Filename)
494 MediaDetImpl *This = impl_from_IMediaDet(iface);
495 FIXME("(%p)->(%f %d %d %p): not implemented!\n", This, StreamTime, Width, Height, Filename);
496 return E_NOTIMPL;
499 static HRESULT WINAPI MediaDet_get_StreamMediaType(IMediaDet* iface,
500 AM_MEDIA_TYPE *pVal)
502 MediaDetImpl *This = impl_from_IMediaDet(iface);
503 IEnumMediaTypes *types;
504 AM_MEDIA_TYPE *pmt;
505 HRESULT hr;
507 TRACE("(%p)\n", This);
509 if (!pVal)
510 return E_POINTER;
512 if (!This->cur_pin)
513 return E_INVALIDARG;
515 hr = IPin_EnumMediaTypes(This->cur_pin, &types);
516 if (SUCCEEDED(hr))
518 hr = (IEnumMediaTypes_Next(types, 1, &pmt, NULL) == S_OK
519 ? S_OK
520 : E_NOINTERFACE);
521 IEnumMediaTypes_Release(types);
524 if (SUCCEEDED(hr))
526 *pVal = *pmt;
527 CoTaskMemFree(pmt);
530 return hr;
533 static HRESULT WINAPI MediaDet_GetSampleGrabber(IMediaDet* iface,
534 ISampleGrabber **ppVal)
536 MediaDetImpl *This = impl_from_IMediaDet(iface);
537 FIXME("(%p)->(%p): not implemented!\n", This, ppVal);
538 return E_NOTIMPL;
541 static HRESULT WINAPI MediaDet_get_FrameRate(IMediaDet* iface, double *pVal)
543 MediaDetImpl *This = impl_from_IMediaDet(iface);
544 AM_MEDIA_TYPE mt;
545 VIDEOINFOHEADER *vh;
546 HRESULT hr;
548 TRACE("(%p)\n", This);
550 if (!pVal)
551 return E_POINTER;
553 hr = MediaDet_get_StreamMediaType(iface, &mt);
554 if (FAILED(hr))
555 return hr;
557 if (!IsEqualGUID(&mt.majortype, &MEDIATYPE_Video))
559 CoTaskMemFree(mt.pbFormat);
560 return VFW_E_INVALIDMEDIATYPE;
563 vh = (VIDEOINFOHEADER *) mt.pbFormat;
564 *pVal = 1.0e7 / (double) vh->AvgTimePerFrame;
566 CoTaskMemFree(mt.pbFormat);
567 return S_OK;
570 static HRESULT WINAPI MediaDet_EnterBitmapGrabMode(IMediaDet* iface,
571 double SeekTime)
573 MediaDetImpl *This = impl_from_IMediaDet(iface);
574 FIXME("(%p)->(%f): not implemented!\n", This, SeekTime);
575 return E_NOTIMPL;
578 static const IMediaDetVtbl IMediaDet_VTable =
580 MediaDet_QueryInterface,
581 MediaDet_AddRef,
582 MediaDet_Release,
583 MediaDet_get_Filter,
584 MediaDet_put_Filter,
585 MediaDet_get_OutputStreams,
586 MediaDet_get_CurrentStream,
587 MediaDet_put_CurrentStream,
588 MediaDet_get_StreamType,
589 MediaDet_get_StreamTypeB,
590 MediaDet_get_StreamLength,
591 MediaDet_get_Filename,
592 MediaDet_put_Filename,
593 MediaDet_GetBitmapBits,
594 MediaDet_WriteBitmapBits,
595 MediaDet_get_StreamMediaType,
596 MediaDet_GetSampleGrabber,
597 MediaDet_get_FrameRate,
598 MediaDet_EnterBitmapGrabMode,
601 HRESULT MediaDet_create(IUnknown * pUnkOuter, LPVOID * ppv) {
602 MediaDetImpl* obj = NULL;
604 TRACE("(%p,%p)\n", ppv, pUnkOuter);
606 if (pUnkOuter)
607 return CLASS_E_NOAGGREGATION;
609 obj = CoTaskMemAlloc(sizeof(MediaDetImpl));
610 if (NULL == obj) {
611 *ppv = NULL;
612 return E_OUTOFMEMORY;
614 ZeroMemory(obj, sizeof(MediaDetImpl));
616 obj->refCount = 1;
617 obj->IMediaDet_iface.lpVtbl = &IMediaDet_VTable;
618 obj->graph = NULL;
619 obj->source = NULL;
620 obj->splitter = NULL;
621 obj->cur_pin = NULL;
622 obj->num_streams = -1;
623 obj->cur_stream = 0;
624 *ppv = obj;
626 return S_OK;