dplayx: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / amstream / filter.c
blobc1c97630bb9b9066a8e56e2aabd30b14f4c7ad2a
1 /*
2 * Implementation of MediaStream Filter
4 * Copyright 2008, 2012 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
22 #include "amstream_private.h"
23 #include "wine/debug.h"
24 #include "wine/list.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
28 struct enum_pins
30 IEnumPins IEnumPins_iface;
31 LONG refcount;
33 IPin **pins;
34 unsigned int count, index;
37 static const IEnumPinsVtbl enum_pins_vtbl;
39 static struct enum_pins *impl_from_IEnumPins(IEnumPins *iface)
41 return CONTAINING_RECORD(iface, struct enum_pins, IEnumPins_iface);
44 static HRESULT WINAPI enum_pins_QueryInterface(IEnumPins *iface, REFIID iid, void **out)
46 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
48 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IEnumPins))
50 IEnumPins_AddRef(iface);
51 *out = iface;
52 return S_OK;
55 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
56 *out = NULL;
57 return E_NOINTERFACE;
60 static ULONG WINAPI enum_pins_AddRef(IEnumPins *iface)
62 struct enum_pins *enum_pins = impl_from_IEnumPins(iface);
63 ULONG refcount = InterlockedIncrement(&enum_pins->refcount);
64 TRACE("%p increasing refcount to %lu.\n", enum_pins, refcount);
65 return refcount;
68 static ULONG WINAPI enum_pins_Release(IEnumPins *iface)
70 struct enum_pins *enum_pins = impl_from_IEnumPins(iface);
71 ULONG refcount = InterlockedDecrement(&enum_pins->refcount);
72 unsigned int i;
74 TRACE("%p decreasing refcount to %lu.\n", enum_pins, refcount);
75 if (!refcount)
77 for (i = 0; i < enum_pins->count; ++i)
78 IPin_Release(enum_pins->pins[i]);
79 free(enum_pins->pins);
80 free(enum_pins);
82 return refcount;
85 static HRESULT WINAPI enum_pins_Next(IEnumPins *iface, ULONG count, IPin **pins, ULONG *ret_count)
87 struct enum_pins *enum_pins = impl_from_IEnumPins(iface);
88 unsigned int i;
90 TRACE("iface %p, count %lu, pins %p, ret_count %p.\n", iface, count, pins, ret_count);
92 if (!pins || (count > 1 && !ret_count))
93 return E_POINTER;
95 for (i = 0; i < count && enum_pins->index < enum_pins->count; ++i)
97 IPin_AddRef(pins[i] = enum_pins->pins[i]);
98 enum_pins->index++;
101 if (ret_count) *ret_count = i;
102 return i == count ? S_OK : S_FALSE;
105 static HRESULT WINAPI enum_pins_Skip(IEnumPins *iface, ULONG count)
107 struct enum_pins *enum_pins = impl_from_IEnumPins(iface);
109 TRACE("iface %p, count %lu.\n", iface, count);
111 enum_pins->index += count;
113 return enum_pins->index >= enum_pins->count ? S_FALSE : S_OK;
116 static HRESULT WINAPI enum_pins_Reset(IEnumPins *iface)
118 struct enum_pins *enum_pins = impl_from_IEnumPins(iface);
120 TRACE("iface %p.\n", iface);
122 enum_pins->index = 0;
123 return S_OK;
126 static HRESULT WINAPI enum_pins_Clone(IEnumPins *iface, IEnumPins **out)
128 struct enum_pins *enum_pins = impl_from_IEnumPins(iface);
129 struct enum_pins *object;
130 unsigned int i;
132 TRACE("iface %p, out %p.\n", iface, out);
134 if (!(object = calloc(1, sizeof(*object))))
135 return E_OUTOFMEMORY;
137 object->IEnumPins_iface.lpVtbl = &enum_pins_vtbl;
138 object->refcount = 1;
139 object->count = enum_pins->count;
140 object->index = enum_pins->index;
141 if (!(object->pins = malloc(enum_pins->count * sizeof(*object->pins))))
143 free(object);
144 return E_OUTOFMEMORY;
146 for (i = 0; i < enum_pins->count; ++i)
147 IPin_AddRef(object->pins[i] = enum_pins->pins[i]);
149 *out = &object->IEnumPins_iface;
150 return S_OK;
153 static const IEnumPinsVtbl enum_pins_vtbl =
155 enum_pins_QueryInterface,
156 enum_pins_AddRef,
157 enum_pins_Release,
158 enum_pins_Next,
159 enum_pins_Skip,
160 enum_pins_Reset,
161 enum_pins_Clone,
164 struct filter
166 IMediaStreamFilter IMediaStreamFilter_iface;
167 IMediaSeeking IMediaSeeking_iface;
168 LONG refcount;
169 CRITICAL_SECTION cs;
171 IReferenceClock *clock;
172 WCHAR name[128];
173 IFilterGraph *graph;
174 ULONG nb_streams;
175 IAMMediaStream **streams;
176 IAMMediaStream *seekable_stream;
177 FILTER_STATE state;
178 REFERENCE_TIME start_time;
179 struct list free_events;
180 struct list used_events;
181 LONG eos_count;
184 struct event
186 struct list entry;
187 HANDLE event;
188 DWORD_PTR cookie;
189 BOOL interrupted;
192 static inline struct filter *impl_from_IMediaStreamFilter(IMediaStreamFilter *iface)
194 return CONTAINING_RECORD(iface, struct filter, IMediaStreamFilter_iface);
197 static HRESULT WINAPI filter_QueryInterface(IMediaStreamFilter *iface, REFIID iid, void **out)
199 struct filter *filter = impl_from_IMediaStreamFilter(iface);
201 TRACE("filter %p, iid %s, out %p.\n", filter, debugstr_guid(iid), out);
203 *out = NULL;
205 if (IsEqualGUID(iid, &IID_IUnknown)
206 || IsEqualGUID(iid, &IID_IPersist)
207 || IsEqualGUID(iid, &IID_IMediaFilter)
208 || IsEqualGUID(iid, &IID_IBaseFilter)
209 || IsEqualGUID(iid, &IID_IMediaStreamFilter))
210 *out = iface;
211 else if (IsEqualGUID(iid, &IID_IMediaSeeking) && filter->seekable_stream)
212 *out = &filter->IMediaSeeking_iface;
213 else
214 return E_NOINTERFACE;
216 IUnknown_AddRef((IUnknown *)*out);
217 return S_OK;
220 static ULONG WINAPI filter_AddRef(IMediaStreamFilter *iface)
222 struct filter *filter = impl_from_IMediaStreamFilter(iface);
223 ULONG refcount = InterlockedIncrement(&filter->refcount);
225 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
227 return refcount;
230 static ULONG WINAPI filter_Release(IMediaStreamFilter *iface)
232 struct filter *filter = impl_from_IMediaStreamFilter(iface);
233 ULONG refcount = InterlockedDecrement(&filter->refcount);
234 unsigned int i;
236 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
238 if (!refcount)
240 struct list *entry;
242 while ((entry = list_head(&filter->free_events)))
244 struct event *event = LIST_ENTRY(entry, struct event, entry);
245 list_remove(entry);
246 CloseHandle(event->event);
247 free(event);
249 for (i = 0; i < filter->nb_streams; ++i)
251 IAMMediaStream_JoinFilter(filter->streams[i], NULL);
252 IAMMediaStream_Release(filter->streams[i]);
254 free(filter->streams);
255 if (filter->clock)
256 IReferenceClock_Release(filter->clock);
257 DeleteCriticalSection(&filter->cs);
258 free(filter);
261 return refcount;
264 static HRESULT WINAPI filter_GetClassID(IMediaStreamFilter *iface, CLSID *clsid)
266 *clsid = CLSID_MediaStreamFilter;
267 return S_OK;
270 static void send_ec_complete(struct filter *filter)
272 IMediaEventSink *event_sink;
274 if (!filter->graph)
275 return;
277 if (FAILED(IFilterGraph_QueryInterface(filter->graph, &IID_IMediaEventSink, (void **)&event_sink)))
278 return;
280 IMediaEventSink_Notify(event_sink, EC_COMPLETE, S_OK,
281 (LONG_PTR)&filter->IMediaStreamFilter_iface);
283 IMediaEventSink_Release(event_sink);
286 static void set_state(struct filter *filter, FILTER_STATE state)
288 if (filter->state != state)
290 ULONG i;
292 for (i = 0; i < filter->nb_streams; ++i)
293 IAMMediaStream_SetState(filter->streams[i], state);
294 filter->state = state;
298 static HRESULT WINAPI filter_Stop(IMediaStreamFilter *iface)
300 struct filter *filter = impl_from_IMediaStreamFilter(iface);
301 struct event *event;
303 TRACE("iface %p.\n", iface);
305 EnterCriticalSection(&filter->cs);
307 if (filter->state != State_Stopped)
308 filter->eos_count = 0;
310 set_state(filter, State_Stopped);
312 LIST_FOR_EACH_ENTRY(event, &filter->used_events, struct event, entry)
314 if (!event->interrupted)
316 event->interrupted = TRUE;
317 IReferenceClock_Unadvise(filter->clock, event->cookie);
318 SetEvent(event->event);
322 LeaveCriticalSection(&filter->cs);
324 return S_OK;
327 static HRESULT WINAPI filter_Pause(IMediaStreamFilter *iface)
329 struct filter *filter = impl_from_IMediaStreamFilter(iface);
331 TRACE("iface %p.\n", iface);
333 EnterCriticalSection(&filter->cs);
335 set_state(filter, State_Paused);
337 LeaveCriticalSection(&filter->cs);
339 return S_OK;
342 static HRESULT WINAPI filter_Run(IMediaStreamFilter *iface, REFERENCE_TIME start)
344 struct filter *filter = impl_from_IMediaStreamFilter(iface);
346 TRACE("iface %p, start %s.\n", iface, wine_dbgstr_longlong(start));
348 EnterCriticalSection(&filter->cs);
350 if (filter->state != State_Running && filter->seekable_stream
351 && filter->eos_count == (LONG)filter->nb_streams)
352 send_ec_complete(filter);
354 filter->start_time = start;
355 set_state(filter, State_Running);
357 LeaveCriticalSection(&filter->cs);
359 return S_OK;
362 static HRESULT WINAPI filter_GetState(IMediaStreamFilter *iface, DWORD timeout, FILTER_STATE *state)
364 struct filter *filter = impl_from_IMediaStreamFilter(iface);
366 TRACE("iface %p, timeout %lu, state %p.\n", iface, timeout, state);
368 if (!state)
369 return E_POINTER;
371 EnterCriticalSection(&filter->cs);
373 *state = filter->state;
375 LeaveCriticalSection(&filter->cs);
377 return S_OK;
380 static HRESULT WINAPI filter_SetSyncSource(IMediaStreamFilter *iface, IReferenceClock *clock)
382 struct filter *filter = impl_from_IMediaStreamFilter(iface);
384 TRACE("iface %p, clock %p.\n", iface, clock);
386 EnterCriticalSection(&filter->cs);
388 if (clock)
389 IReferenceClock_AddRef(clock);
390 if (filter->clock)
391 IReferenceClock_Release(filter->clock);
392 filter->clock = clock;
394 LeaveCriticalSection(&filter->cs);
396 return S_OK;
399 static HRESULT WINAPI filter_GetSyncSource(IMediaStreamFilter *iface, IReferenceClock **clock)
401 struct filter *filter = impl_from_IMediaStreamFilter(iface);
403 TRACE("iface %p, clock %p.\n", iface, clock);
405 EnterCriticalSection(&filter->cs);
407 if (filter->clock)
408 IReferenceClock_AddRef(filter->clock);
409 *clock = filter->clock;
411 LeaveCriticalSection(&filter->cs);
413 return S_OK;
416 static HRESULT WINAPI filter_EnumPins(IMediaStreamFilter *iface, IEnumPins **enum_pins)
418 struct filter *filter = impl_from_IMediaStreamFilter(iface);
419 struct enum_pins *object;
420 unsigned int i;
422 TRACE("iface %p, enum_pins %p.\n", iface, enum_pins);
424 if (!enum_pins)
425 return E_POINTER;
427 if (!(object = calloc(1, sizeof(*object))))
428 return E_OUTOFMEMORY;
430 EnterCriticalSection(&filter->cs);
432 object->IEnumPins_iface.lpVtbl = &enum_pins_vtbl;
433 object->refcount = 1;
434 object->count = filter->nb_streams;
435 object->index = 0;
436 if (!(object->pins = malloc(filter->nb_streams * sizeof(*object->pins))))
438 free(object);
439 LeaveCriticalSection(&filter->cs);
440 return E_OUTOFMEMORY;
442 for (i = 0; i < filter->nb_streams; ++i)
444 if (FAILED(IAMMediaStream_QueryInterface(filter->streams[i], &IID_IPin, (void **)&object->pins[i])))
445 WARN("Stream %p does not support IPin.\n", filter->streams[i]);
448 LeaveCriticalSection(&filter->cs);
450 *enum_pins = &object->IEnumPins_iface;
451 return S_OK;
454 static HRESULT WINAPI filter_FindPin(IMediaStreamFilter *iface, const WCHAR *id, IPin **out)
456 struct filter *filter = impl_from_IMediaStreamFilter(iface);
457 unsigned int i;
458 WCHAR *ret_id;
459 IPin *pin;
461 TRACE("iface %p, id %s, out %p.\n", iface, debugstr_w(id), out);
463 EnterCriticalSection(&filter->cs);
465 for (i = 0; i < filter->nb_streams; ++i)
467 if (FAILED(IAMMediaStream_QueryInterface(filter->streams[i], &IID_IPin, (void **)&pin)))
469 WARN("Stream %p does not support IPin.\n", filter->streams[i]);
470 continue;
473 if (SUCCEEDED(IPin_QueryId(pin, &ret_id)))
475 if (!wcscmp(id, ret_id))
477 CoTaskMemFree(ret_id);
478 *out = pin;
479 LeaveCriticalSection(&filter->cs);
480 return S_OK;
482 CoTaskMemFree(ret_id);
484 IPin_Release(pin);
487 LeaveCriticalSection(&filter->cs);
489 return VFW_E_NOT_FOUND;
492 static HRESULT WINAPI filter_QueryFilterInfo(IMediaStreamFilter *iface, FILTER_INFO *info)
494 struct filter *filter = impl_from_IMediaStreamFilter(iface);
496 TRACE("iface %p, info %p.\n", iface, info);
498 EnterCriticalSection(&filter->cs);
500 wcscpy(info->achName, filter->name);
501 if (filter->graph)
502 IFilterGraph_AddRef(filter->graph);
503 info->pGraph = filter->graph;
505 LeaveCriticalSection(&filter->cs);
507 return S_OK;
510 static HRESULT WINAPI filter_JoinFilterGraph(IMediaStreamFilter *iface,
511 IFilterGraph *graph, const WCHAR *name)
513 struct filter *filter = impl_from_IMediaStreamFilter(iface);
515 TRACE("iface %p, graph %p, name.%s.\n", iface, graph, debugstr_w(name));
517 EnterCriticalSection(&filter->cs);
519 if (name)
520 lstrcpynW(filter->name, name, ARRAY_SIZE(filter->name));
521 else
522 filter->name[0] = 0;
523 filter->graph = graph;
525 LeaveCriticalSection(&filter->cs);
527 return S_OK;
530 static HRESULT WINAPI filter_QueryVendorInfo(IMediaStreamFilter *iface, LPWSTR *vendor_info)
532 WARN("iface %p, vendor_info %p, stub!\n", iface, vendor_info);
533 return E_NOTIMPL;
536 /*** IMediaStreamFilter methods ***/
538 static HRESULT WINAPI filter_AddMediaStream(IMediaStreamFilter *iface, IAMMediaStream *pAMMediaStream)
540 struct filter *This = impl_from_IMediaStreamFilter(iface);
541 IAMMediaStream** streams;
542 HRESULT hr;
544 TRACE("(%p)->(%p)\n", iface, pAMMediaStream);
546 streams = realloc(This->streams, (This->nb_streams + 1) * sizeof(*streams));
547 if (!streams)
548 return E_OUTOFMEMORY;
549 This->streams = streams;
551 hr = IAMMediaStream_JoinFilter(pAMMediaStream, iface);
552 if (FAILED(hr))
553 return hr;
555 hr = IAMMediaStream_JoinFilterGraph(pAMMediaStream, This->graph);
556 if (FAILED(hr))
557 return hr;
559 This->streams[This->nb_streams] = pAMMediaStream;
560 This->nb_streams++;
562 IAMMediaStream_AddRef(pAMMediaStream);
564 return S_OK;
567 static HRESULT WINAPI filter_GetMediaStream(IMediaStreamFilter *iface, REFMSPID idPurpose, IMediaStream **ppMediaStream)
569 struct filter *This = impl_from_IMediaStreamFilter(iface);
570 MSPID purpose_id;
571 unsigned int i;
573 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(idPurpose), ppMediaStream);
575 if (!ppMediaStream)
576 return E_POINTER;
578 for (i = 0; i < This->nb_streams; i++)
580 IAMMediaStream_GetInformation(This->streams[i], &purpose_id, NULL);
581 if (IsEqualIID(&purpose_id, idPurpose))
583 *ppMediaStream = (IMediaStream *)This->streams[i];
584 IMediaStream_AddRef(*ppMediaStream);
585 return S_OK;
589 return MS_E_NOSTREAM;
592 static HRESULT WINAPI filter_EnumMediaStreams(IMediaStreamFilter *iface, LONG index, IMediaStream **stream)
594 struct filter *filter = impl_from_IMediaStreamFilter(iface);
596 TRACE("filter %p, index %ld, stream %p.\n", filter, index, stream);
598 if (index >= filter->nb_streams)
599 return S_FALSE;
601 if (!stream)
602 return E_POINTER;
604 IMediaStream_AddRef(*stream = (IMediaStream *)filter->streams[index]);
605 return S_OK;
608 static IMediaSeeking *get_seeking(IAMMediaStream *stream)
610 IMediaSeeking *seeking;
611 IPin *pin, *peer;
612 HRESULT hr;
614 if (FAILED(IAMMediaStream_QueryInterface(stream, &IID_IPin, (void **)&pin)))
616 WARN("Stream %p does not support IPin.\n", stream);
617 return NULL;
620 hr = IPin_ConnectedTo(pin, &peer);
621 IPin_Release(pin);
622 if (FAILED(hr))
623 return NULL;
625 hr = IPin_QueryInterface(peer, &IID_IMediaSeeking, (void **)&seeking);
626 IPin_Release(peer);
627 if (FAILED(hr))
628 return NULL;
630 return seeking;
633 static HRESULT WINAPI filter_SupportSeeking(IMediaStreamFilter *iface, BOOL renderer)
635 struct filter *filter = impl_from_IMediaStreamFilter(iface);
636 unsigned int i;
638 TRACE("filter %p, renderer %d\n", iface, renderer);
640 if (!renderer)
641 FIXME("Non-renderer filter support is not yet implemented.\n");
643 EnterCriticalSection(&filter->cs);
645 if (filter->seekable_stream)
647 LeaveCriticalSection(&filter->cs);
648 return HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
651 for (i = 0; i < filter->nb_streams; ++i)
653 IMediaSeeking *seeking = get_seeking(filter->streams[i]);
654 LONGLONG duration;
656 if (!seeking)
657 continue;
659 if (SUCCEEDED(IMediaSeeking_GetDuration(seeking, &duration)))
661 filter->seekable_stream = filter->streams[i];
662 IMediaSeeking_Release(seeking);
663 LeaveCriticalSection(&filter->cs);
664 return S_OK;
667 IMediaSeeking_Release(seeking);
670 LeaveCriticalSection(&filter->cs);
671 return E_NOINTERFACE;
674 static HRESULT WINAPI filter_ReferenceTimeToStreamTime(IMediaStreamFilter *iface, REFERENCE_TIME *time)
676 struct filter *filter = impl_from_IMediaStreamFilter(iface);
678 TRACE("filter %p, time %p.\n", filter, time);
680 EnterCriticalSection(&filter->cs);
682 if (!filter->clock)
684 LeaveCriticalSection(&filter->cs);
685 return S_FALSE;
688 *time -= filter->start_time;
690 LeaveCriticalSection(&filter->cs);
692 return S_OK;
695 static HRESULT WINAPI filter_GetCurrentStreamTime(IMediaStreamFilter *iface, REFERENCE_TIME *time)
697 struct filter *filter = impl_from_IMediaStreamFilter(iface);
699 TRACE("filter %p, time %p.\n", filter, time);
701 if (!time)
702 return E_POINTER;
704 EnterCriticalSection(&filter->cs);
706 if (filter->state != State_Running || !filter->clock)
708 *time = 0;
709 LeaveCriticalSection(&filter->cs);
710 return S_FALSE;
713 IReferenceClock_GetTime(filter->clock, time);
715 *time -= filter->start_time;
717 LeaveCriticalSection(&filter->cs);
719 return S_OK;
722 static HRESULT WINAPI filter_WaitUntil(IMediaStreamFilter *iface, REFERENCE_TIME time)
724 struct filter *filter = impl_from_IMediaStreamFilter(iface);
725 struct event *event;
726 struct list *entry;
727 HRESULT hr;
729 TRACE("filter %p, time %s.\n", iface, wine_dbgstr_longlong(time));
731 EnterCriticalSection(&filter->cs);
733 if (!filter->clock)
735 LeaveCriticalSection(&filter->cs);
736 return E_FAIL;
739 if ((entry = list_head(&filter->free_events)))
741 list_remove(entry);
742 event = LIST_ENTRY(entry, struct event, entry);
744 else
746 event = calloc(1, sizeof(struct event));
747 event->event = CreateEventW(NULL, FALSE, FALSE, NULL);
749 entry = &event->entry;
752 hr = IReferenceClock_AdviseTime(filter->clock, time, filter->start_time, (HEVENT)event->event, &event->cookie);
753 if (FAILED(hr))
755 list_add_tail(&filter->free_events, entry);
756 LeaveCriticalSection(&filter->cs);
757 return hr;
760 event->interrupted = FALSE;
761 list_add_tail(&filter->used_events, entry);
763 LeaveCriticalSection(&filter->cs);
764 WaitForSingleObject(event->event, INFINITE);
765 EnterCriticalSection(&filter->cs);
767 hr = event->interrupted ? S_FALSE : S_OK;
769 list_remove(entry);
770 list_add_tail(&filter->free_events, entry);
772 LeaveCriticalSection(&filter->cs);
774 return hr;
777 static HRESULT WINAPI filter_Flush(IMediaStreamFilter *iface, BOOL cancel_eos)
779 struct filter *filter = impl_from_IMediaStreamFilter(iface);
780 struct event *event;
782 TRACE("filter %p, cancel_eos %d.\n", iface, cancel_eos);
784 EnterCriticalSection(&filter->cs);
786 LIST_FOR_EACH_ENTRY(event, &filter->used_events, struct event, entry)
788 if (!event->interrupted)
790 event->interrupted = TRUE;
791 IReferenceClock_Unadvise(filter->clock, event->cookie);
792 SetEvent(event->event);
796 if (cancel_eos)
797 --filter->eos_count;
799 LeaveCriticalSection(&filter->cs);
801 return S_OK;
804 static HRESULT WINAPI filter_EndOfStream(IMediaStreamFilter *iface)
806 struct filter *filter = impl_from_IMediaStreamFilter(iface);
808 TRACE("filter %p.\n", filter);
810 EnterCriticalSection(&filter->cs);
812 ++filter->eos_count;
813 if (filter->state == State_Running && filter->seekable_stream &&
814 filter->eos_count == (LONG)filter->nb_streams)
815 send_ec_complete(filter);
817 LeaveCriticalSection(&filter->cs);
819 return S_OK;
822 static const IMediaStreamFilterVtbl filter_vtbl =
824 filter_QueryInterface,
825 filter_AddRef,
826 filter_Release,
827 filter_GetClassID,
828 filter_Stop,
829 filter_Pause,
830 filter_Run,
831 filter_GetState,
832 filter_SetSyncSource,
833 filter_GetSyncSource,
834 filter_EnumPins,
835 filter_FindPin,
836 filter_QueryFilterInfo,
837 filter_JoinFilterGraph,
838 filter_QueryVendorInfo,
839 filter_AddMediaStream,
840 filter_GetMediaStream,
841 filter_EnumMediaStreams,
842 filter_SupportSeeking,
843 filter_ReferenceTimeToStreamTime,
844 filter_GetCurrentStreamTime,
845 filter_WaitUntil,
846 filter_Flush,
847 filter_EndOfStream
850 static inline struct filter *impl_from_IMediaSeeking(IMediaSeeking *iface)
852 return CONTAINING_RECORD(iface, struct filter, IMediaSeeking_iface);
855 static HRESULT WINAPI filter_seeking_QueryInterface(IMediaSeeking *iface, REFIID iid, void **out)
857 struct filter *filter = impl_from_IMediaSeeking(iface);
858 return IMediaStreamFilter_QueryInterface(&filter->IMediaStreamFilter_iface, iid, out);
861 static ULONG WINAPI filter_seeking_AddRef(IMediaSeeking *iface)
863 struct filter *filter = impl_from_IMediaSeeking(iface);
864 return IMediaStreamFilter_AddRef(&filter->IMediaStreamFilter_iface);
867 static ULONG WINAPI filter_seeking_Release(IMediaSeeking *iface)
869 struct filter *filter = impl_from_IMediaSeeking(iface);
870 return IMediaStreamFilter_Release(&filter->IMediaStreamFilter_iface);
873 static HRESULT WINAPI filter_seeking_GetCapabilities(IMediaSeeking *iface, DWORD *capabilities)
875 FIXME("iface %p, capabilities %p, stub!\n", iface, capabilities);
877 return E_NOTIMPL;
880 static HRESULT WINAPI filter_seeking_CheckCapabilities(IMediaSeeking *iface, DWORD *capabilities)
882 FIXME("iface %p, capabilities %p, stub!\n", iface, capabilities);
884 return E_NOTIMPL;
887 static HRESULT WINAPI filter_seeking_IsFormatSupported(IMediaSeeking *iface, const GUID *format)
889 struct filter *filter = impl_from_IMediaSeeking(iface);
890 IMediaSeeking *seeking;
891 HRESULT hr;
893 TRACE("filter %p, format %s.\n", filter, debugstr_guid(format));
895 EnterCriticalSection(&filter->cs);
897 seeking = get_seeking(filter->seekable_stream);
899 LeaveCriticalSection(&filter->cs);
901 if (!seeking)
902 return E_NOTIMPL;
904 hr = IMediaSeeking_IsFormatSupported(seeking, format);
905 IMediaSeeking_Release(seeking);
907 return hr;
910 static HRESULT WINAPI filter_seeking_QueryPreferredFormat(IMediaSeeking *iface, GUID *format)
912 FIXME("iface %p, format %p, stub!\n", iface, format);
914 return E_NOTIMPL;
917 static HRESULT WINAPI filter_seeking_GetTimeFormat(IMediaSeeking *iface, GUID *format)
919 FIXME("iface %p, format %p, stub!\n", iface, format);
921 return E_NOTIMPL;
924 static HRESULT WINAPI filter_seeking_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *format)
926 FIXME("iface %p, format %s, stub!\n", iface, debugstr_guid(format));
928 return E_NOTIMPL;
931 static HRESULT WINAPI filter_seeking_SetTimeFormat(IMediaSeeking *iface, const GUID *format)
933 FIXME("iface %p, format %s, stub!\n", iface, debugstr_guid(format));
935 return E_NOTIMPL;
938 static HRESULT WINAPI filter_seeking_GetDuration(IMediaSeeking *iface, LONGLONG *duration)
940 struct filter *filter = impl_from_IMediaSeeking(iface);
941 IMediaSeeking *seeking;
942 HRESULT hr;
944 TRACE("filter %p, duration %p.\n", filter, duration);
946 EnterCriticalSection(&filter->cs);
948 seeking = get_seeking(filter->seekable_stream);
950 LeaveCriticalSection(&filter->cs);
952 if (!seeking)
953 return E_NOTIMPL;
955 hr = IMediaSeeking_GetDuration(seeking, duration);
956 IMediaSeeking_Release(seeking);
958 return hr;
961 static HRESULT WINAPI filter_seeking_GetStopPosition(IMediaSeeking *iface, LONGLONG *stop)
963 struct filter *filter = impl_from_IMediaSeeking(iface);
964 IMediaSeeking *seeking;
965 HRESULT hr;
967 TRACE("filter %p, stop %p.\n", filter, stop);
969 EnterCriticalSection(&filter->cs);
971 seeking = get_seeking(filter->seekable_stream);
973 LeaveCriticalSection(&filter->cs);
975 if (!seeking)
976 return E_NOTIMPL;
978 hr = IMediaSeeking_GetStopPosition(seeking, stop);
979 IMediaSeeking_Release(seeking);
981 return hr;
984 static HRESULT WINAPI filter_seeking_GetCurrentPosition(IMediaSeeking *iface, LONGLONG *current)
986 FIXME("iface %p, current %p, stub!\n", iface, current);
988 return E_NOTIMPL;
991 static HRESULT WINAPI filter_seeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *target,
992 const GUID *target_format, LONGLONG source, const GUID *source_format)
994 FIXME("iface %p, target %p, target_format %s, source 0x%s, source_format %s, stub!\n", iface, target, debugstr_guid(target_format),
995 wine_dbgstr_longlong(source), debugstr_guid(source_format));
997 return E_NOTIMPL;
1000 static HRESULT WINAPI filter_seeking_SetPositions(IMediaSeeking *iface, LONGLONG *current_ptr, DWORD current_flags,
1001 LONGLONG *stop_ptr, DWORD stop_flags)
1003 struct filter *filter = impl_from_IMediaSeeking(iface);
1004 IMediaSeeking *seeking;
1005 HRESULT hr;
1007 TRACE("iface %p, current %s, current_flags %#lx, stop %s, stop_flags %#lx.\n", iface,
1008 current_ptr ? wine_dbgstr_longlong(*current_ptr) : "<null>", current_flags,
1009 stop_ptr ? wine_dbgstr_longlong(*stop_ptr): "<null>", stop_flags);
1011 EnterCriticalSection(&filter->cs);
1013 seeking = get_seeking(filter->seekable_stream);
1015 LeaveCriticalSection(&filter->cs);
1017 if (!seeking)
1018 return E_NOTIMPL;
1020 hr = IMediaSeeking_SetPositions(seeking, current_ptr, current_flags, stop_ptr, stop_flags);
1022 IMediaSeeking_Release(seeking);
1024 return hr;
1027 static HRESULT WINAPI filter_seeking_GetPositions(IMediaSeeking *iface, LONGLONG *current, LONGLONG *stop)
1029 FIXME("iface %p, current %p, stop %p, stub!\n", iface, current, stop);
1031 return E_NOTIMPL;
1034 static HRESULT WINAPI filter_seeking_GetAvailable(IMediaSeeking *iface, LONGLONG *earliest, LONGLONG *latest)
1036 FIXME("iface %p, earliest %p, latest %p, stub!\n", iface, earliest, latest);
1038 return E_NOTIMPL;
1041 static HRESULT WINAPI filter_seeking_SetRate(IMediaSeeking *iface, double rate)
1043 FIXME("iface %p, rate %f, stub!\n", iface, rate);
1045 return E_NOTIMPL;
1048 static HRESULT WINAPI filter_seeking_GetRate(IMediaSeeking *iface, double *rate)
1050 FIXME("iface %p, rate %p, stub!\n", iface, rate);
1052 return E_NOTIMPL;
1055 static HRESULT WINAPI filter_seeking_GetPreroll(IMediaSeeking *iface, LONGLONG *preroll)
1057 FIXME("iface %p, preroll %p, stub!\n", iface, preroll);
1059 return E_NOTIMPL;
1062 static const IMediaSeekingVtbl filter_seeking_vtbl =
1064 filter_seeking_QueryInterface,
1065 filter_seeking_AddRef,
1066 filter_seeking_Release,
1067 filter_seeking_GetCapabilities,
1068 filter_seeking_CheckCapabilities,
1069 filter_seeking_IsFormatSupported,
1070 filter_seeking_QueryPreferredFormat,
1071 filter_seeking_GetTimeFormat,
1072 filter_seeking_IsUsingTimeFormat,
1073 filter_seeking_SetTimeFormat,
1074 filter_seeking_GetDuration,
1075 filter_seeking_GetStopPosition,
1076 filter_seeking_GetCurrentPosition,
1077 filter_seeking_ConvertTimeFormat,
1078 filter_seeking_SetPositions,
1079 filter_seeking_GetPositions,
1080 filter_seeking_GetAvailable,
1081 filter_seeking_SetRate,
1082 filter_seeking_GetRate,
1083 filter_seeking_GetPreroll,
1086 HRESULT filter_create(IUnknown *outer, void **out)
1088 struct filter *object;
1090 TRACE("outer %p, out %p.\n", outer, out);
1092 if (outer)
1093 return CLASS_E_NOAGGREGATION;
1095 if (!(object = calloc(1, sizeof(*object))))
1096 return E_OUTOFMEMORY;
1098 object->IMediaStreamFilter_iface.lpVtbl = &filter_vtbl;
1099 object->IMediaSeeking_iface.lpVtbl = &filter_seeking_vtbl;
1100 object->refcount = 1;
1101 list_init(&object->free_events);
1102 list_init(&object->used_events);
1103 InitializeCriticalSection(&object->cs);
1104 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MediaStreamFilter.cs");
1106 TRACE("Created media stream filter %p.\n", object);
1107 *out = &object->IMediaStreamFilter_iface;
1108 return S_OK;