cmd: DIR command outputs free space for the path.
[wine.git] / dlls / winegstreamer / media_source.c
blob8b9d42ea3f0cb8b4f2507da4d291089c9b1c1209
1 /* GStreamer Media Source
3 * Copyright 2020 Derek Lesho
4 * Copyright 2020 Zebediah Figura for CodeWeavers
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 #include "gst_private.h"
23 #include "mfapi.h"
24 #include "mferror.h"
26 #include "wine/list.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
30 struct object_context
32 IUnknown IUnknown_iface;
33 LONG refcount;
35 IMFAsyncResult *result;
36 IMFByteStream *stream;
37 UINT64 file_size;
38 WCHAR *url;
41 static struct object_context *impl_from_IUnknown(IUnknown *iface)
43 return CONTAINING_RECORD(iface, struct object_context, IUnknown_iface);
46 static HRESULT WINAPI object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
48 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
50 if (IsEqualIID(riid, &IID_IUnknown))
52 *obj = iface;
53 IUnknown_AddRef(iface);
54 return S_OK;
57 WARN("Unsupported %s.\n", debugstr_guid(riid));
58 *obj = NULL;
59 return E_NOINTERFACE;
62 static ULONG WINAPI object_context_AddRef(IUnknown *iface)
64 struct object_context *context = impl_from_IUnknown(iface);
65 ULONG refcount = InterlockedIncrement(&context->refcount);
67 TRACE("%p, refcount %lu.\n", iface, refcount);
69 return refcount;
72 static ULONG WINAPI object_context_Release(IUnknown *iface)
74 struct object_context *context = impl_from_IUnknown(iface);
75 ULONG refcount = InterlockedDecrement(&context->refcount);
77 TRACE("%p, refcount %lu.\n", iface, refcount);
79 if (!refcount)
81 IMFAsyncResult_Release(context->result);
82 IMFByteStream_Release(context->stream);
83 free(context->url);
84 free(context);
87 return refcount;
90 static const IUnknownVtbl object_context_vtbl =
92 object_context_QueryInterface,
93 object_context_AddRef,
94 object_context_Release,
97 static HRESULT object_context_create(DWORD flags, IMFByteStream *stream, const WCHAR *url,
98 QWORD file_size, IMFAsyncResult *result, IUnknown **out)
100 WCHAR *tmp_url = url ? wcsdup(url) : NULL;
101 struct object_context *context;
103 if (!(context = calloc(1, sizeof(*context))))
105 free(tmp_url);
106 return E_OUTOFMEMORY;
109 context->IUnknown_iface.lpVtbl = &object_context_vtbl;
110 context->refcount = 1;
111 context->stream = stream;
112 IMFByteStream_AddRef(context->stream);
113 context->file_size = file_size;
114 context->url = tmp_url;
115 context->result = result;
116 IMFAsyncResult_AddRef(context->result);
118 *out = &context->IUnknown_iface;
119 return S_OK;
122 struct media_stream
124 IMFMediaStream IMFMediaStream_iface;
125 LONG ref;
127 IMFMediaSource *media_source;
128 IMFMediaEventQueue *event_queue;
129 IMFStreamDescriptor *descriptor;
131 wg_parser_stream_t wg_stream;
133 IUnknown **token_queue;
134 LONG token_queue_count;
135 LONG token_queue_cap;
137 DWORD stream_id;
138 BOOL active;
139 BOOL eos;
142 enum source_async_op
144 SOURCE_ASYNC_START,
145 SOURCE_ASYNC_PAUSE,
146 SOURCE_ASYNC_STOP,
147 SOURCE_ASYNC_REQUEST_SAMPLE,
150 struct source_async_command
152 IUnknown IUnknown_iface;
153 LONG refcount;
154 enum source_async_op op;
155 union
157 struct
159 IMFPresentationDescriptor *descriptor;
160 GUID format;
161 PROPVARIANT position;
162 } start;
163 struct
165 struct media_stream *stream;
166 IUnknown *token;
167 } request_sample;
168 } u;
171 struct media_source
173 IMFMediaSource IMFMediaSource_iface;
174 IMFGetService IMFGetService_iface;
175 IMFRateSupport IMFRateSupport_iface;
176 IMFRateControl IMFRateControl_iface;
177 IMFAsyncCallback async_commands_callback;
178 LONG ref;
179 DWORD async_commands_queue;
180 IMFMediaEventQueue *event_queue;
181 IMFByteStream *byte_stream;
183 CRITICAL_SECTION cs;
185 UINT64 file_size;
186 wg_parser_t wg_parser;
187 UINT64 duration;
189 IMFStreamDescriptor **descriptors;
190 struct media_stream **streams;
191 ULONG stream_count;
193 enum
195 SOURCE_OPENING,
196 SOURCE_STOPPED,
197 SOURCE_PAUSED,
198 SOURCE_RUNNING,
199 SOURCE_SHUTDOWN,
200 } state;
201 float rate;
203 HANDLE read_thread;
204 bool read_thread_shutdown;
207 static inline struct media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface)
209 return CONTAINING_RECORD(iface, struct media_stream, IMFMediaStream_iface);
212 static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
214 return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
217 static inline struct media_source *impl_from_IMFGetService(IMFGetService *iface)
219 return CONTAINING_RECORD(iface, struct media_source, IMFGetService_iface);
222 static inline struct media_source *impl_from_IMFRateSupport(IMFRateSupport *iface)
224 return CONTAINING_RECORD(iface, struct media_source, IMFRateSupport_iface);
227 static inline struct media_source *impl_from_IMFRateControl(IMFRateControl *iface)
229 return CONTAINING_RECORD(iface, struct media_source, IMFRateControl_iface);
232 static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
234 return CONTAINING_RECORD(iface, struct media_source, async_commands_callback);
237 static inline struct source_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
239 return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface);
242 static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
244 if (IsEqualIID(riid, &IID_IUnknown))
246 *obj = iface;
247 IUnknown_AddRef(iface);
248 return S_OK;
251 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
252 *obj = NULL;
253 return E_NOINTERFACE;
256 static ULONG WINAPI source_async_command_AddRef(IUnknown *iface)
258 struct source_async_command *command = impl_from_async_command_IUnknown(iface);
259 return InterlockedIncrement(&command->refcount);
262 static ULONG WINAPI source_async_command_Release(IUnknown *iface)
264 struct source_async_command *command = impl_from_async_command_IUnknown(iface);
265 ULONG refcount = InterlockedDecrement(&command->refcount);
267 if (!refcount)
269 if (command->op == SOURCE_ASYNC_START)
271 IMFPresentationDescriptor_Release(command->u.start.descriptor);
272 PropVariantClear(&command->u.start.position);
274 else if (command->op == SOURCE_ASYNC_REQUEST_SAMPLE)
276 if (command->u.request_sample.token)
277 IUnknown_Release(command->u.request_sample.token);
279 free(command);
282 return refcount;
285 static const IUnknownVtbl source_async_command_vtbl =
287 source_async_command_QueryInterface,
288 source_async_command_AddRef,
289 source_async_command_Release,
292 static HRESULT source_create_async_op(enum source_async_op op, IUnknown **out)
294 struct source_async_command *command;
296 if (!(command = calloc(1, sizeof(*command))))
297 return E_OUTOFMEMORY;
299 command->IUnknown_iface.lpVtbl = &source_async_command_vtbl;
300 command->refcount = 1;
301 command->op = op;
303 *out = &command->IUnknown_iface;
304 return S_OK;
307 static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
309 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
311 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
312 IsEqualIID(riid, &IID_IUnknown))
314 *obj = iface;
315 IMFAsyncCallback_AddRef(iface);
316 return S_OK;
319 WARN("Unsupported %s.\n", debugstr_guid(riid));
320 *obj = NULL;
321 return E_NOINTERFACE;
324 static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface,
325 DWORD *flags, DWORD *queue)
327 return E_NOTIMPL;
330 static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface)
332 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
333 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
336 static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface)
338 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
339 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
342 static HRESULT stream_descriptor_get_media_type(IMFStreamDescriptor *descriptor, IMFMediaType **media_type)
344 IMFMediaTypeHandler *handler;
345 HRESULT hr;
347 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler)))
348 return hr;
349 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
350 IMFMediaTypeHandler_Release(handler);
352 return hr;
355 static HRESULT wg_format_from_stream_descriptor(IMFStreamDescriptor *descriptor, struct wg_format *format)
357 IMFMediaType *media_type;
358 HRESULT hr;
360 if (FAILED(hr = stream_descriptor_get_media_type(descriptor, &media_type)))
361 return hr;
362 mf_media_type_to_wg_format(media_type, format);
363 IMFMediaType_Release(media_type);
365 return hr;
368 static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, wg_parser_stream_t stream,
369 const GUID *attr, enum wg_parser_tag tag)
371 WCHAR *strW;
372 HRESULT hr;
373 DWORD len;
374 char *str;
376 if (!(str = wg_parser_stream_get_tag(stream, tag))
377 || !(len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
378 hr = S_OK;
379 else if (!(strW = malloc(len * sizeof(*strW))))
380 hr = E_OUTOFMEMORY;
381 else
383 if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len))
384 hr = IMFStreamDescriptor_SetString(descriptor, attr, strW);
385 else
386 hr = E_FAIL;
387 free(strW);
390 free(str);
391 return hr;
394 static HRESULT init_video_media_types(struct wg_format *format, IMFMediaType *types[6], DWORD *types_count)
396 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
397 * YUV color space, and it's generally much less expensive for
398 * videoconvert to do YUV -> YUV transformations. */
399 static const enum wg_video_format video_formats[] =
401 WG_VIDEO_FORMAT_NV12,
402 WG_VIDEO_FORMAT_YV12,
403 WG_VIDEO_FORMAT_YUY2,
404 WG_VIDEO_FORMAT_I420,
406 UINT count = *types_count, i;
407 GUID base_subtype;
408 HRESULT hr;
410 if (FAILED(hr = IMFMediaType_GetGUID(types[0], &MF_MT_SUBTYPE, &base_subtype)))
411 return hr;
413 for (i = 0; i < ARRAY_SIZE(video_formats); ++i)
415 struct wg_format new_format = *format;
416 IMFMediaType *new_type;
418 new_format.u.video.format = video_formats[i];
420 if (!(new_type = mf_media_type_from_wg_format(&new_format)))
422 hr = E_OUTOFMEMORY;
423 goto done;
425 types[count++] = new_type;
427 if (video_formats[i] == WG_VIDEO_FORMAT_I420)
429 IMFMediaType *iyuv_type;
431 if (FAILED(hr = MFCreateMediaType(&iyuv_type)))
432 goto done;
433 if (FAILED(hr = IMFMediaType_CopyAllItems(new_type, (IMFAttributes *)iyuv_type)))
434 goto done;
435 if (FAILED(hr = IMFMediaType_SetGUID(iyuv_type, &MF_MT_SUBTYPE, &MFVideoFormat_IYUV)))
436 goto done;
437 types[count++] = iyuv_type;
441 done:
442 *types_count = count;
443 return hr;
446 static HRESULT init_audio_media_types(struct wg_format *format, IMFMediaType *types[6], DWORD *types_count)
448 /* Expose at least one PCM and one floating point type for the
449 consumer to pick from. */
450 static const enum wg_audio_format audio_types[] =
452 WG_AUDIO_FORMAT_S16LE,
453 WG_AUDIO_FORMAT_F32LE,
455 UINT count = *types_count, i;
457 for (i = 0; i < ARRAY_SIZE(audio_types); i++)
459 struct wg_format new_format = *format;
460 if (new_format.u.audio.format == audio_types[i])
461 continue;
462 new_format.u.audio.format = audio_types[i];
463 if ((types[count] = mf_media_type_from_wg_format(&new_format)))
464 count++;
467 *types_count = count;
468 return S_OK;
471 static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMFStreamDescriptor **out)
473 IMFStreamDescriptor *descriptor;
474 IMFMediaTypeHandler *handler;
475 IMFMediaType *types[6];
476 DWORD count = 0;
477 HRESULT hr;
479 if (!(types[0] = mf_media_type_from_wg_format(format)))
480 return MF_E_INVALIDMEDIATYPE;
481 count = 1;
483 if (format->major_type == WG_MAJOR_TYPE_VIDEO)
485 if (FAILED(hr = init_video_media_types(format, types, &count)))
486 goto done;
488 else if (format->major_type == WG_MAJOR_TYPE_AUDIO)
490 if (FAILED(hr = init_audio_media_types(format, types, &count)))
491 goto done;
494 assert(count <= ARRAY_SIZE(types));
496 if (FAILED(hr = MFCreateStreamDescriptor(id, count, types, &descriptor)))
497 goto done;
499 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler)))
500 IMFStreamDescriptor_Release(descriptor);
501 else
503 hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, types[0]);
504 IMFMediaTypeHandler_Release(handler);
507 done:
508 while (count--)
509 IMFMediaType_Release(types[count]);
510 *out = SUCCEEDED(hr) ? descriptor : NULL;
511 return hr;
514 static BOOL enqueue_token(struct media_stream *stream, IUnknown *token)
516 if (stream->token_queue_count == stream->token_queue_cap)
518 IUnknown **buf;
519 stream->token_queue_cap = stream->token_queue_cap * 2 + 1;
520 buf = realloc(stream->token_queue, stream->token_queue_cap * sizeof(*buf));
521 if (buf)
522 stream->token_queue = buf;
523 else
525 stream->token_queue_cap = stream->token_queue_count;
526 return FALSE;
529 stream->token_queue[stream->token_queue_count++] = token;
530 return TRUE;
533 static void flush_token_queue(struct media_stream *stream, BOOL send)
535 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
536 LONG i;
538 for (i = 0; i < stream->token_queue_count; i++)
540 if (send)
542 IUnknown *op;
543 HRESULT hr;
545 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op)))
547 struct source_async_command *command = impl_from_async_command_IUnknown(op);
548 command->u.request_sample.stream = stream;
549 command->u.request_sample.token = stream->token_queue[i];
551 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
552 IUnknown_Release(op);
554 if (FAILED(hr))
555 WARN("Could not enqueue sample request, hr %#lx\n", hr);
557 else if (stream->token_queue[i])
558 IUnknown_Release(stream->token_queue[i]);
560 free(stream->token_queue);
561 stream->token_queue = NULL;
562 stream->token_queue_count = 0;
563 stream->token_queue_cap = 0;
566 static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL seeking, const PROPVARIANT *position)
568 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
569 struct wg_format format;
570 HRESULT hr;
572 TRACE("source %p, stream %p\n", source, stream);
574 if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format)))
575 WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr);
576 wg_parser_stream_enable(stream->wg_stream, &format);
578 if (FAILED(hr = IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, active ? MEUpdatedStream : MENewStream,
579 &GUID_NULL, S_OK, (IUnknown *)&stream->IMFMediaStream_iface)))
580 WARN("Failed to send source stream event, hr %#lx\n", hr);
581 return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, seeking ? MEStreamSeeked : MEStreamStarted,
582 &GUID_NULL, S_OK, position);
585 static HRESULT media_source_start(struct media_source *source, IMFPresentationDescriptor *descriptor,
586 GUID *format, PROPVARIANT *position)
588 BOOL starting = source->state == SOURCE_STOPPED, seek_message = !starting && position->vt != VT_EMPTY;
589 IMFStreamDescriptor **descriptors;
590 DWORD i, count;
591 HRESULT hr;
593 TRACE("source %p, descriptor %p, format %s, position %s\n", source, descriptor,
594 debugstr_guid(format), wine_dbgstr_variant((VARIANT *)position));
596 if (source->state == SOURCE_SHUTDOWN)
597 return MF_E_SHUTDOWN;
599 /* seek to beginning on stop->play */
600 if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY)
602 position->vt = VT_I8;
603 position->hVal.QuadPart = 0;
606 if (!(descriptors = calloc(source->stream_count, sizeof(*descriptors))))
607 return E_OUTOFMEMORY;
609 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count)))
610 WARN("Failed to get presentation descriptor stream count, hr %#lx\n", hr);
612 for (i = 0; i < count; i++)
614 IMFStreamDescriptor *stream_descriptor;
615 BOOL selected;
616 DWORD id;
618 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i,
619 &selected, &stream_descriptor)))
620 WARN("Failed to get presentation stream descriptor, hr %#lx\n", hr);
621 else
623 if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(stream_descriptor, &id)))
624 WARN("Failed to get stream descriptor id, hr %#lx\n", hr);
625 else if (id >= source->stream_count)
626 WARN("Invalid stream descriptor id %lu, hr %#lx\n", id, hr);
627 else if (selected)
628 IMFStreamDescriptor_AddRef((descriptors[id] = stream_descriptor));
630 IMFStreamDescriptor_Release(stream_descriptor);
634 for (i = 0; i < source->stream_count; i++)
636 struct media_stream *stream = source->streams[i];
637 BOOL was_active = !starting && stream->active;
639 if (position->vt != VT_EMPTY)
640 stream->eos = FALSE;
642 if (!(stream->active = !!descriptors[i]))
643 wg_parser_stream_disable(stream->wg_stream);
644 else
646 if (FAILED(hr = media_stream_start(stream, was_active, seek_message, position)))
647 WARN("Failed to start media stream, hr %#lx\n", hr);
648 IMFStreamDescriptor_Release(descriptors[i]);
652 free(descriptors);
654 source->state = SOURCE_RUNNING;
656 if (position->vt == VT_I8)
657 wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, position->hVal.QuadPart, 0,
658 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
660 for (i = 0; i < source->stream_count; i++)
661 flush_token_queue(source->streams[i], position->vt == VT_EMPTY);
663 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue,
664 seek_message ? MESourceSeeked : MESourceStarted, &GUID_NULL, S_OK, position);
667 static HRESULT media_source_pause(struct media_source *source)
669 unsigned int i;
670 HRESULT hr;
672 TRACE("source %p\n", source);
674 if (source->state == SOURCE_SHUTDOWN)
675 return MF_E_SHUTDOWN;
677 for (i = 0; i < source->stream_count; i++)
679 struct media_stream *stream = source->streams[i];
680 if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamPaused,
681 &GUID_NULL, S_OK, NULL)))
682 WARN("Failed to queue MEStreamPaused event, hr %#lx\n", hr);
685 source->state = SOURCE_PAUSED;
686 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL);
689 static HRESULT media_source_stop(struct media_source *source)
691 unsigned int i;
692 HRESULT hr;
694 TRACE("source %p\n", source);
696 if (source->state == SOURCE_SHUTDOWN)
697 return MF_E_SHUTDOWN;
699 for (i = 0; i < source->stream_count; i++)
701 struct media_stream *stream = source->streams[i];
702 if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped,
703 &GUID_NULL, S_OK, NULL)))
704 WARN("Failed to queue MEStreamStopped event, hr %#lx\n", hr);
707 source->state = SOURCE_STOPPED;
709 for (i = 0; i < source->stream_count; i++)
710 flush_token_queue(source->streams[i], FALSE);
712 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL);
715 static HRESULT media_stream_send_sample(struct media_stream *stream, const struct wg_parser_buffer *wg_buffer, IUnknown *token)
717 IMFSample *sample = NULL;
718 IMFMediaBuffer *buffer;
719 HRESULT hr;
720 BYTE *data;
722 if (FAILED(hr = MFCreateMemoryBuffer(wg_buffer->size, &buffer)))
723 return hr;
724 if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, wg_buffer->size)))
725 goto out;
726 if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL)))
727 goto out;
729 if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, wg_buffer->size))
731 wg_parser_stream_release_buffer(stream->wg_stream);
732 IMFMediaBuffer_Unlock(buffer);
733 goto out;
735 wg_parser_stream_release_buffer(stream->wg_stream);
737 if (FAILED(hr = IMFMediaBuffer_Unlock(buffer)))
738 goto out;
740 if (FAILED(hr = MFCreateSample(&sample)))
741 goto out;
742 if (FAILED(hr = IMFSample_AddBuffer(sample, buffer)))
743 goto out;
744 if (FAILED(hr = IMFSample_SetSampleTime(sample, wg_buffer->pts)))
745 goto out;
746 if (FAILED(hr = IMFSample_SetSampleDuration(sample, wg_buffer->duration)))
747 goto out;
748 if (token && FAILED(hr = IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token)))
749 goto out;
751 hr = IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample,
752 &GUID_NULL, S_OK, (IUnknown *)sample);
754 out:
755 if (sample)
756 IMFSample_Release(sample);
757 IMFMediaBuffer_Release(buffer);
758 return hr;
761 static HRESULT media_stream_send_eos(struct media_source *source, struct media_stream *stream)
763 PROPVARIANT empty = {.vt = VT_EMPTY};
764 HRESULT hr;
765 UINT i;
767 TRACE("source %p, stream %p\n", source, stream);
769 stream->eos = TRUE;
770 if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty)))
771 WARN("Failed to queue MEEndOfStream event, hr %#lx\n", hr);
773 for (i = 0; i < source->stream_count; i++)
775 struct media_stream *stream = source->streams[i];
776 if (stream->active && !stream->eos)
777 return S_OK;
780 if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty)))
781 WARN("Failed to queue MEEndOfPresentation event, hr %#lx\n", hr);
782 return S_OK;
785 static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token)
787 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
788 struct wg_parser_buffer buffer;
790 TRACE("%p, %p\n", stream, token);
792 if (wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer))
793 return media_stream_send_sample(stream, &buffer, token);
795 return media_stream_send_eos(source, stream);
798 static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
800 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
801 struct source_async_command *command;
802 IUnknown *state;
803 HRESULT hr;
805 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
806 return hr;
808 EnterCriticalSection(&source->cs);
810 command = impl_from_async_command_IUnknown(state);
811 switch (command->op)
813 case SOURCE_ASYNC_START:
815 IMFPresentationDescriptor *descriptor = command->u.start.descriptor;
816 GUID format = command->u.start.format;
817 PROPVARIANT position = command->u.start.position;
819 if (FAILED(hr = media_source_start(source, descriptor, &format, &position)))
820 WARN("Failed to start source %p, hr %#lx\n", source, hr);
821 break;
823 case SOURCE_ASYNC_PAUSE:
824 if (FAILED(hr = media_source_pause(source)))
825 WARN("Failed to pause source %p, hr %#lx\n", source, hr);
826 break;
827 case SOURCE_ASYNC_STOP:
828 if (FAILED(hr = media_source_stop(source)))
829 WARN("Failed to stop source %p, hr %#lx\n", source, hr);
830 break;
831 case SOURCE_ASYNC_REQUEST_SAMPLE:
832 if (source->state == SOURCE_PAUSED)
833 enqueue_token(command->u.request_sample.stream, command->u.request_sample.token);
834 else if (source->state == SOURCE_RUNNING)
836 if (FAILED(hr = wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token)))
837 WARN("Failed to request sample, hr %#lx\n", hr);
839 break;
842 LeaveCriticalSection(&source->cs);
844 IUnknown_Release(state);
846 return S_OK;
849 static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
851 callback_QueryInterface,
852 source_async_commands_callback_AddRef,
853 source_async_commands_callback_Release,
854 callback_GetParameters,
855 source_async_commands_Invoke,
858 static DWORD CALLBACK read_thread(void *arg)
860 struct media_source *source = arg;
861 IMFByteStream *byte_stream = source->byte_stream;
862 size_t buffer_size = 4096;
863 QWORD file_size;
864 void *data;
866 if (!(data = malloc(buffer_size)))
867 return 0;
869 IMFByteStream_GetLength(byte_stream, &file_size);
871 TRACE("Starting read thread for media source %p.\n", source);
873 while (!source->read_thread_shutdown)
875 uint64_t offset;
876 ULONG ret_size;
877 uint32_t size;
878 HRESULT hr;
880 if (!wg_parser_get_next_read_offset(source->wg_parser, &offset, &size))
881 continue;
883 if (offset >= file_size)
884 size = 0;
885 else if (offset + size >= file_size)
886 size = file_size - offset;
888 /* Some IMFByteStreams (including the standard file-based stream) return
889 * an error when reading past the file size. */
890 if (!size)
892 wg_parser_push_data(source->wg_parser, data, 0);
893 continue;
896 if (!array_reserve(&data, &buffer_size, size, 1))
898 free(data);
899 return 0;
902 ret_size = 0;
904 if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset)))
905 hr = IMFByteStream_Read(byte_stream, data, size, &ret_size);
906 if (FAILED(hr))
907 ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr);
908 else if (ret_size != size)
909 ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size);
910 wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size);
913 free(data);
914 TRACE("Media source is shutting down; exiting.\n");
915 return 0;
918 static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
920 struct media_stream *stream = impl_from_IMFMediaStream(iface);
922 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
924 if (IsEqualIID(riid, &IID_IMFMediaStream) ||
925 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
926 IsEqualIID(riid, &IID_IUnknown))
928 *out = &stream->IMFMediaStream_iface;
930 else
932 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
933 *out = NULL;
934 return E_NOINTERFACE;
937 IUnknown_AddRef((IUnknown*)*out);
938 return S_OK;
941 static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface)
943 struct media_stream *stream = impl_from_IMFMediaStream(iface);
944 ULONG ref = InterlockedIncrement(&stream->ref);
946 TRACE("%p, refcount %lu.\n", iface, ref);
948 return ref;
951 static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
953 struct media_stream *stream = impl_from_IMFMediaStream(iface);
954 ULONG ref = InterlockedDecrement(&stream->ref);
956 TRACE("%p, refcount %lu.\n", iface, ref);
958 if (!ref)
960 IMFMediaSource_Release(stream->media_source);
961 IMFStreamDescriptor_Release(stream->descriptor);
962 IMFMediaEventQueue_Release(stream->event_queue);
963 flush_token_queue(stream, FALSE);
964 free(stream);
967 return ref;
970 static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
972 struct media_stream *stream = impl_from_IMFMediaStream(iface);
974 TRACE("%p, %#lx, %p.\n", iface, flags, event);
976 return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
979 static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
981 struct media_stream *stream = impl_from_IMFMediaStream(iface);
983 TRACE("%p, %p, %p.\n", iface, callback, state);
985 return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
988 static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
990 struct media_stream *stream = impl_from_IMFMediaStream(iface);
992 TRACE("%p, %p, %p.\n", stream, result, event);
994 return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
997 static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
998 HRESULT hr, const PROPVARIANT *value)
1000 struct media_stream *stream = impl_from_IMFMediaStream(iface);
1002 TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1004 return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
1007 static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **out)
1009 struct media_stream *stream = impl_from_IMFMediaStream(iface);
1010 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
1011 HRESULT hr = S_OK;
1013 TRACE("%p, %p.\n", iface, out);
1015 EnterCriticalSection(&source->cs);
1017 if (source->state == SOURCE_SHUTDOWN)
1018 hr = MF_E_SHUTDOWN;
1019 else
1021 IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1022 *out = &source->IMFMediaSource_iface;
1025 LeaveCriticalSection(&source->cs);
1027 return hr;
1030 static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
1032 struct media_stream *stream = impl_from_IMFMediaStream(iface);
1033 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
1034 HRESULT hr = S_OK;
1036 TRACE("%p, %p.\n", iface, descriptor);
1038 EnterCriticalSection(&source->cs);
1040 if (source->state == SOURCE_SHUTDOWN)
1041 hr = MF_E_SHUTDOWN;
1042 else
1044 IMFStreamDescriptor_AddRef(stream->descriptor);
1045 *descriptor = stream->descriptor;
1048 LeaveCriticalSection(&source->cs);
1050 return hr;
1053 static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
1055 struct media_stream *stream = impl_from_IMFMediaStream(iface);
1056 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
1057 IUnknown *op;
1058 HRESULT hr;
1060 TRACE("%p, %p.\n", iface, token);
1062 EnterCriticalSection(&source->cs);
1064 if (source->state == SOURCE_SHUTDOWN)
1065 hr = MF_E_SHUTDOWN;
1066 else if (!stream->active)
1067 hr = MF_E_MEDIA_SOURCE_WRONGSTATE;
1068 else if (stream->eos)
1069 hr = MF_E_END_OF_STREAM;
1070 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op)))
1072 struct source_async_command *command = impl_from_async_command_IUnknown(op);
1073 command->u.request_sample.stream = stream;
1074 if (token)
1075 IUnknown_AddRef(token);
1076 command->u.request_sample.token = token;
1078 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
1079 IUnknown_Release(op);
1082 LeaveCriticalSection(&source->cs);
1084 return hr;
1087 static const IMFMediaStreamVtbl media_stream_vtbl =
1089 media_stream_QueryInterface,
1090 media_stream_AddRef,
1091 media_stream_Release,
1092 media_stream_GetEvent,
1093 media_stream_BeginGetEvent,
1094 media_stream_EndGetEvent,
1095 media_stream_QueueEvent,
1096 media_stream_GetMediaSource,
1097 media_stream_GetStreamDescriptor,
1098 media_stream_RequestSample
1101 static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor *descriptor,
1102 wg_parser_stream_t wg_stream, struct media_stream **out)
1104 struct media_stream *object;
1105 HRESULT hr;
1107 TRACE("source %p, descriptor %p, wg_stream %#I64x.\n", source, descriptor, wg_stream);
1109 if (!(object = calloc(1, sizeof(*object))))
1110 return E_OUTOFMEMORY;
1112 object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
1113 object->ref = 1;
1115 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1117 free(object);
1118 return hr;
1121 IMFMediaSource_AddRef(source);
1122 object->media_source = source;
1123 IMFStreamDescriptor_AddRef(descriptor);
1124 object->descriptor = descriptor;
1126 object->active = TRUE;
1127 object->eos = FALSE;
1128 object->wg_stream = wg_stream;
1130 TRACE("Created stream object %p.\n", object);
1132 *out = object;
1133 return S_OK;
1136 static HRESULT WINAPI media_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1138 struct media_source *source = impl_from_IMFGetService(iface);
1139 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
1142 static ULONG WINAPI media_source_get_service_AddRef(IMFGetService *iface)
1144 struct media_source *source = impl_from_IMFGetService(iface);
1145 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1148 static ULONG WINAPI media_source_get_service_Release(IMFGetService *iface)
1150 struct media_source *source = impl_from_IMFGetService(iface);
1151 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
1154 static HRESULT WINAPI media_source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1156 struct media_source *source = impl_from_IMFGetService(iface);
1158 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1160 *obj = NULL;
1162 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1164 if (IsEqualIID(riid, &IID_IMFRateSupport))
1166 *obj = &source->IMFRateSupport_iface;
1168 else if (IsEqualIID(riid, &IID_IMFRateControl))
1170 *obj = &source->IMFRateControl_iface;
1173 else
1174 FIXME("Unsupported service %s.\n", debugstr_guid(service));
1176 if (*obj)
1177 IUnknown_AddRef((IUnknown *)*obj);
1179 return *obj ? S_OK : E_NOINTERFACE;
1182 static const IMFGetServiceVtbl media_source_get_service_vtbl =
1184 media_source_get_service_QueryInterface,
1185 media_source_get_service_AddRef,
1186 media_source_get_service_Release,
1187 media_source_get_service_GetService,
1190 static HRESULT WINAPI media_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1192 struct media_source *source = impl_from_IMFRateSupport(iface);
1193 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
1196 static ULONG WINAPI media_source_rate_support_AddRef(IMFRateSupport *iface)
1198 struct media_source *source = impl_from_IMFRateSupport(iface);
1199 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1202 static ULONG WINAPI media_source_rate_support_Release(IMFRateSupport *iface)
1204 struct media_source *source = impl_from_IMFRateSupport(iface);
1205 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
1208 static HRESULT WINAPI media_source_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
1210 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1212 *rate = 0.0f;
1214 return S_OK;
1217 static HRESULT WINAPI media_source_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
1219 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1221 *rate = direction == MFRATE_FORWARD ? 1e6f : -1e6f;
1223 return S_OK;
1226 static HRESULT WINAPI media_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1227 float *nearest_rate)
1229 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_rate);
1231 if (nearest_rate)
1232 *nearest_rate = rate;
1234 return rate >= -1e6f && rate <= 1e6f ? S_OK : MF_E_UNSUPPORTED_RATE;
1237 static const IMFRateSupportVtbl media_source_rate_support_vtbl =
1239 media_source_rate_support_QueryInterface,
1240 media_source_rate_support_AddRef,
1241 media_source_rate_support_Release,
1242 media_source_rate_support_GetSlowestRate,
1243 media_source_rate_support_GetFastestRate,
1244 media_source_rate_support_IsRateSupported,
1247 static HRESULT WINAPI media_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
1249 struct media_source *source = impl_from_IMFRateControl(iface);
1250 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
1253 static ULONG WINAPI media_source_rate_control_AddRef(IMFRateControl *iface)
1255 struct media_source *source = impl_from_IMFRateControl(iface);
1256 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1259 static ULONG WINAPI media_source_rate_control_Release(IMFRateControl *iface)
1261 struct media_source *source = impl_from_IMFRateControl(iface);
1262 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
1265 static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
1267 struct media_source *source = impl_from_IMFRateControl(iface);
1268 HRESULT hr;
1270 FIXME("%p, %d, %f.\n", iface, thin, rate);
1272 if (rate < 0.0f)
1273 return MF_E_REVERSE_UNSUPPORTED;
1275 if (thin)
1276 return MF_E_THINNING_UNSUPPORTED;
1278 if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL)))
1279 return hr;
1281 EnterCriticalSection(&source->cs);
1282 source->rate = rate;
1283 LeaveCriticalSection(&source->cs);
1285 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL);
1288 static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
1290 struct media_source *source = impl_from_IMFRateControl(iface);
1292 TRACE("%p, %p, %p.\n", iface, thin, rate);
1294 if (thin)
1295 *thin = FALSE;
1297 EnterCriticalSection(&source->cs);
1298 *rate = source->rate;
1299 LeaveCriticalSection(&source->cs);
1301 return S_OK;
1304 static const IMFRateControlVtbl media_source_rate_control_vtbl =
1306 media_source_rate_control_QueryInterface,
1307 media_source_rate_control_AddRef,
1308 media_source_rate_control_Release,
1309 media_source_rate_control_SetRate,
1310 media_source_rate_control_GetRate,
1313 static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
1315 struct media_source *source = impl_from_IMFMediaSource(iface);
1317 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1319 if (IsEqualIID(riid, &IID_IMFMediaSource) ||
1320 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1321 IsEqualIID(riid, &IID_IUnknown))
1323 *out = &source->IMFMediaSource_iface;
1325 else if (IsEqualIID(riid, &IID_IMFGetService))
1327 *out = &source->IMFGetService_iface;
1329 else
1331 FIXME("%s, %p.\n", debugstr_guid(riid), out);
1332 *out = NULL;
1333 return E_NOINTERFACE;
1336 IUnknown_AddRef((IUnknown*)*out);
1337 return S_OK;
1340 static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface)
1342 struct media_source *source = impl_from_IMFMediaSource(iface);
1343 ULONG ref = InterlockedIncrement(&source->ref);
1345 TRACE("%p, refcount %lu.\n", iface, ref);
1347 return ref;
1350 static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
1352 struct media_source *source = impl_from_IMFMediaSource(iface);
1353 ULONG ref = InterlockedDecrement(&source->ref);
1355 TRACE("%p, refcount %lu.\n", iface, ref);
1357 if (!ref)
1359 IMFMediaSource_Shutdown(iface);
1360 IMFMediaEventQueue_Release(source->event_queue);
1361 IMFByteStream_Release(source->byte_stream);
1362 wg_parser_destroy(source->wg_parser);
1363 source->cs.DebugInfo->Spare[0] = 0;
1364 DeleteCriticalSection(&source->cs);
1365 free(source);
1368 return ref;
1371 static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
1373 struct media_source *source = impl_from_IMFMediaSource(iface);
1375 TRACE("%p, %#lx, %p.\n", iface, flags, event);
1377 return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
1380 static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
1382 struct media_source *source = impl_from_IMFMediaSource(iface);
1384 TRACE("%p, %p, %p.\n", iface, callback, state);
1386 return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
1389 static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1391 struct media_source *source = impl_from_IMFMediaSource(iface);
1393 TRACE("%p, %p, %p.\n", iface, result, event);
1395 return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
1398 static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
1399 HRESULT hr, const PROPVARIANT *value)
1401 struct media_source *source = impl_from_IMFMediaSource(iface);
1403 TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1405 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
1408 static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
1410 struct media_source *source = impl_from_IMFMediaSource(iface);
1411 HRESULT hr = S_OK;
1413 TRACE("%p, %p.\n", iface, characteristics);
1415 EnterCriticalSection(&source->cs);
1417 if (source->state == SOURCE_SHUTDOWN)
1418 hr = MF_E_SHUTDOWN;
1419 else
1420 *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE;
1422 LeaveCriticalSection(&source->cs);
1424 return hr;
1427 static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
1429 struct media_source *source = impl_from_IMFMediaSource(iface);
1430 HRESULT hr;
1431 UINT i;
1433 TRACE("%p, %p.\n", iface, descriptor);
1435 EnterCriticalSection(&source->cs);
1437 if (source->state == SOURCE_SHUTDOWN)
1438 hr = MF_E_SHUTDOWN;
1439 else if (SUCCEEDED(hr = MFCreatePresentationDescriptor(source->stream_count, source->descriptors, descriptor)))
1441 if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_DURATION, source->duration)))
1442 WARN("Failed to set presentation descriptor MF_PD_DURATION, hr %#lx\n", hr);
1444 for (i = 0; i < source->stream_count; ++i)
1446 if (FAILED(hr = IMFPresentationDescriptor_SelectStream(*descriptor, i)))
1447 WARN("Failed to select stream %u, hr %#lx\n", i, hr);
1450 hr = S_OK;
1453 LeaveCriticalSection(&source->cs);
1455 return hr;
1458 static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
1459 const GUID *time_format, const PROPVARIANT *position)
1461 struct media_source *source = impl_from_IMFMediaSource(iface);
1462 IUnknown *op;
1463 HRESULT hr;
1465 TRACE("%p, %p, %p, %p.\n", iface, descriptor, time_format, position);
1467 EnterCriticalSection(&source->cs);
1469 if (source->state == SOURCE_SHUTDOWN)
1470 hr = MF_E_SHUTDOWN;
1471 else if (!(IsEqualIID(time_format, &GUID_NULL)))
1472 hr = MF_E_UNSUPPORTED_TIME_FORMAT;
1473 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &op)))
1475 struct source_async_command *command = impl_from_async_command_IUnknown(op);
1476 command->u.start.descriptor = descriptor;
1477 IMFPresentationDescriptor_AddRef(descriptor);
1478 command->u.start.format = *time_format;
1479 PropVariantCopy(&command->u.start.position, position);
1481 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
1482 IUnknown_Release(op);
1485 LeaveCriticalSection(&source->cs);
1487 return hr;
1490 static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
1492 struct media_source *source = impl_from_IMFMediaSource(iface);
1493 IUnknown *op;
1494 HRESULT hr;
1496 TRACE("%p.\n", iface);
1498 EnterCriticalSection(&source->cs);
1500 if (source->state == SOURCE_SHUTDOWN)
1501 hr = MF_E_SHUTDOWN;
1502 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &op)))
1504 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
1505 IUnknown_Release(op);
1508 LeaveCriticalSection(&source->cs);
1510 return hr;
1513 static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
1515 struct media_source *source = impl_from_IMFMediaSource(iface);
1516 IUnknown *op;
1517 HRESULT hr;
1519 TRACE("%p.\n", iface);
1521 EnterCriticalSection(&source->cs);
1523 if (source->state == SOURCE_SHUTDOWN)
1524 hr = MF_E_SHUTDOWN;
1525 else if (source->state != SOURCE_RUNNING)
1526 hr = MF_E_INVALID_STATE_TRANSITION;
1527 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &op)))
1529 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
1530 IUnknown_Release(op);
1533 LeaveCriticalSection(&source->cs);
1535 return S_OK;
1538 static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
1540 struct media_source *source = impl_from_IMFMediaSource(iface);
1542 TRACE("%p.\n", iface);
1544 EnterCriticalSection(&source->cs);
1546 if (source->state == SOURCE_SHUTDOWN)
1548 LeaveCriticalSection(&source->cs);
1549 return MF_E_SHUTDOWN;
1552 source->state = SOURCE_SHUTDOWN;
1554 wg_parser_disconnect(source->wg_parser);
1556 source->read_thread_shutdown = true;
1557 WaitForSingleObject(source->read_thread, INFINITE);
1558 CloseHandle(source->read_thread);
1560 IMFMediaEventQueue_Shutdown(source->event_queue);
1561 IMFByteStream_Close(source->byte_stream);
1563 while (source->stream_count--)
1565 struct media_stream *stream = source->streams[source->stream_count];
1566 IMFStreamDescriptor_Release(source->descriptors[source->stream_count]);
1567 IMFMediaEventQueue_Shutdown(stream->event_queue);
1568 IMFMediaStream_Release(&stream->IMFMediaStream_iface);
1570 free(source->descriptors);
1571 free(source->streams);
1573 LeaveCriticalSection(&source->cs);
1575 MFUnlockWorkQueue(source->async_commands_queue);
1577 return S_OK;
1580 static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
1582 media_source_QueryInterface,
1583 media_source_AddRef,
1584 media_source_Release,
1585 media_source_GetEvent,
1586 media_source_BeginGetEvent,
1587 media_source_EndGetEvent,
1588 media_source_QueueEvent,
1589 media_source_GetCharacteristics,
1590 media_source_CreatePresentationDescriptor,
1591 media_source_Start,
1592 media_source_Stop,
1593 media_source_Pause,
1594 media_source_Shutdown,
1597 static void media_source_init_descriptors(struct media_source *source)
1599 HRESULT hr = S_OK;
1600 UINT i;
1602 for (i = 0; i < source->stream_count; i++)
1604 struct media_stream *stream = source->streams[i];
1605 IMFStreamDescriptor *descriptor = stream->descriptor;
1607 if (FAILED(hr = stream_descriptor_set_tag(descriptor, stream->wg_stream,
1608 &MF_SD_LANGUAGE, WG_PARSER_TAG_LANGUAGE)))
1609 WARN("Failed to set stream descriptor language, hr %#lx\n", hr);
1610 if (FAILED(hr = stream_descriptor_set_tag(descriptor, stream->wg_stream,
1611 &MF_SD_STREAM_NAME, WG_PARSER_TAG_NAME)))
1612 WARN("Failed to set stream descriptor name, hr %#lx\n", hr);
1616 static HRESULT media_source_create(struct object_context *context, IMFMediaSource **out)
1618 unsigned int stream_count = UINT_MAX;
1619 struct media_source *object;
1620 wg_parser_t parser;
1621 unsigned int i;
1622 HRESULT hr;
1624 if (!(object = calloc(1, sizeof(*object))))
1625 return E_OUTOFMEMORY;
1627 object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
1628 object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl;
1629 object->IMFRateSupport_iface.lpVtbl = &media_source_rate_support_vtbl;
1630 object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl;
1631 object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
1632 object->ref = 1;
1633 object->byte_stream = context->stream;
1634 IMFByteStream_AddRef(context->stream);
1635 object->file_size = context->file_size;
1636 object->rate = 1.0f;
1637 InitializeCriticalSection(&object->cs);
1638 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
1640 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1641 goto fail;
1643 if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
1644 goto fail;
1646 if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN)))
1648 hr = E_OUTOFMEMORY;
1649 goto fail;
1651 object->wg_parser = parser;
1653 object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL);
1655 object->state = SOURCE_OPENING;
1657 if (FAILED(hr = wg_parser_connect(parser, object->file_size)))
1658 goto fail;
1660 stream_count = wg_parser_get_stream_count(parser);
1662 if (!(object->descriptors = calloc(stream_count, sizeof(*object->descriptors)))
1663 || !(object->streams = calloc(stream_count, sizeof(*object->streams))))
1665 hr = E_OUTOFMEMORY;
1666 goto fail;
1669 for (i = 0; i < stream_count; ++i)
1671 wg_parser_stream_t wg_stream = wg_parser_get_stream(object->wg_parser, i);
1672 IMFStreamDescriptor *descriptor;
1673 struct media_stream *stream;
1674 struct wg_format format;
1676 wg_parser_stream_get_preferred_format(wg_stream, &format);
1677 if (FAILED(hr = stream_descriptor_create(i, &format, &descriptor)))
1678 goto fail;
1679 if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, descriptor, wg_stream, &stream)))
1681 IMFStreamDescriptor_Release(descriptor);
1682 goto fail;
1685 object->duration = max(object->duration, wg_parser_stream_get_duration(wg_stream));
1686 IMFStreamDescriptor_AddRef(descriptor);
1687 object->descriptors[i] = descriptor;
1688 object->streams[i] = stream;
1689 object->stream_count++;
1692 media_source_init_descriptors(object);
1693 object->state = SOURCE_STOPPED;
1695 *out = &object->IMFMediaSource_iface;
1696 TRACE("Created IMFMediaSource %p\n", *out);
1697 return S_OK;
1699 fail:
1700 WARN("Failed to construct MFMediaSource, hr %#lx.\n", hr);
1702 while (object->streams && object->stream_count--)
1704 struct media_stream *stream = object->streams[object->stream_count];
1705 IMFStreamDescriptor_Release(object->descriptors[object->stream_count]);
1706 IMFMediaStream_Release(&stream->IMFMediaStream_iface);
1708 free(object->descriptors);
1709 free(object->streams);
1711 if (stream_count != UINT_MAX)
1712 wg_parser_disconnect(object->wg_parser);
1713 if (object->read_thread)
1715 object->read_thread_shutdown = true;
1716 WaitForSingleObject(object->read_thread, INFINITE);
1717 CloseHandle(object->read_thread);
1719 if (object->wg_parser)
1720 wg_parser_destroy(object->wg_parser);
1721 if (object->async_commands_queue)
1722 MFUnlockWorkQueue(object->async_commands_queue);
1723 if (object->event_queue)
1724 IMFMediaEventQueue_Release(object->event_queue);
1725 IMFByteStream_Release(object->byte_stream);
1726 free(object);
1727 return hr;
1730 struct result_entry
1732 struct list entry;
1733 IMFAsyncResult *result;
1734 MF_OBJECT_TYPE type;
1735 IUnknown *object;
1738 static HRESULT result_entry_create(IMFAsyncResult *result, MF_OBJECT_TYPE type,
1739 IUnknown *object, struct result_entry **out)
1741 struct result_entry *entry;
1743 if (!(entry = malloc(sizeof(*entry))))
1744 return E_OUTOFMEMORY;
1746 entry->result = result;
1747 IMFAsyncResult_AddRef(entry->result);
1748 entry->object = object;
1749 IUnknown_AddRef(entry->object);
1750 entry->type = type;
1752 *out = entry;
1753 return S_OK;
1756 static void result_entry_destroy(struct result_entry *entry)
1758 IMFAsyncResult_Release(entry->result);
1759 IUnknown_Release(entry->object);
1760 free(entry);
1763 struct stream_handler
1765 IMFByteStreamHandler IMFByteStreamHandler_iface;
1766 IMFAsyncCallback IMFAsyncCallback_iface;
1767 LONG refcount;
1768 struct list results;
1769 CRITICAL_SECTION cs;
1772 static struct result_entry *handler_find_result_entry(struct stream_handler *handler, IMFAsyncResult *result)
1774 struct result_entry *entry;
1776 EnterCriticalSection(&handler->cs);
1777 LIST_FOR_EACH_ENTRY(entry, &handler->results, struct result_entry, entry)
1779 if (result == entry->result)
1781 list_remove(&entry->entry);
1782 LeaveCriticalSection(&handler->cs);
1783 return entry;
1786 LeaveCriticalSection(&handler->cs);
1788 return NULL;
1791 static struct stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface)
1793 return CONTAINING_RECORD(iface, struct stream_handler, IMFByteStreamHandler_iface);
1796 static struct stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
1798 return CONTAINING_RECORD(iface, struct stream_handler, IMFAsyncCallback_iface);
1801 static HRESULT WINAPI stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj)
1803 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1805 if (IsEqualIID(riid, &IID_IMFByteStreamHandler) ||
1806 IsEqualIID(riid, &IID_IUnknown))
1808 *obj = iface;
1809 IMFByteStreamHandler_AddRef(iface);
1810 return S_OK;
1813 WARN("Unsupported %s.\n", debugstr_guid(riid));
1814 *obj = NULL;
1815 return E_NOINTERFACE;
1818 static ULONG WINAPI stream_handler_AddRef(IMFByteStreamHandler *iface)
1820 struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1821 ULONG refcount = InterlockedIncrement(&handler->refcount);
1823 TRACE("%p, refcount %lu.\n", handler, refcount);
1825 return refcount;
1828 static ULONG WINAPI stream_handler_Release(IMFByteStreamHandler *iface)
1830 struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1831 ULONG refcount = InterlockedDecrement(&handler->refcount);
1832 struct result_entry *result, *next;
1834 TRACE("%p, refcount %lu.\n", iface, refcount);
1836 if (!refcount)
1838 LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct result_entry, entry)
1839 result_entry_destroy(result);
1840 DeleteCriticalSection(&handler->cs);
1841 free(handler);
1844 return refcount;
1847 static HRESULT WINAPI stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
1848 IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
1850 struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1851 IMFAsyncResult *result;
1852 IUnknown *context;
1853 QWORD file_size;
1854 HRESULT hr;
1855 DWORD caps;
1857 TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
1859 if (cancel_cookie)
1860 *cancel_cookie = NULL;
1862 if (!stream)
1863 return E_INVALIDARG;
1864 if (flags != MF_RESOLUTION_MEDIASOURCE)
1865 FIXME("Unimplemented flags %#lx\n", flags);
1867 if (FAILED(hr = IMFByteStream_GetCapabilities(stream, &caps)))
1868 return hr;
1869 if (!(caps & MFBYTESTREAM_IS_SEEKABLE))
1871 FIXME("Non-seekable bytestreams not supported.\n");
1872 return MF_E_BYTESTREAM_NOT_SEEKABLE;
1874 if (FAILED(hr = IMFByteStream_GetLength(stream, &file_size)))
1876 FIXME("Failed to get byte stream length, hr %#lx.\n", hr);
1877 return hr;
1880 if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &result)))
1881 return hr;
1882 if (FAILED(hr = object_context_create(flags, stream, url, file_size, result, &context)))
1884 IMFAsyncResult_Release(result);
1885 return hr;
1888 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_IO, &handler->IMFAsyncCallback_iface, context);
1889 IUnknown_Release(context);
1891 if (SUCCEEDED(hr) && cancel_cookie)
1893 *cancel_cookie = (IUnknown *)result;
1894 IUnknown_AddRef(*cancel_cookie);
1897 IMFAsyncResult_Release(result);
1899 return hr;
1902 static HRESULT WINAPI stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
1903 MF_OBJECT_TYPE *type, IUnknown **object)
1905 struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1906 struct result_entry *entry;
1907 HRESULT hr;
1909 TRACE("%p, %p, %p, %p.\n", iface, result, type, object);
1911 if (!(entry = handler_find_result_entry(handler, result)))
1913 *type = MF_OBJECT_INVALID;
1914 *object = NULL;
1915 return MF_E_UNEXPECTED;
1918 hr = IMFAsyncResult_GetStatus(entry->result);
1919 *type = entry->type;
1920 *object = entry->object;
1921 IUnknown_AddRef(*object);
1922 result_entry_destroy(entry);
1923 return hr;
1926 static HRESULT WINAPI stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cookie)
1928 struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1929 IMFAsyncResult *result = (IMFAsyncResult *)cookie;
1930 struct result_entry *entry;
1932 TRACE("%p, %p.\n", iface, cookie);
1934 if (!(entry = handler_find_result_entry(handler, result)))
1935 return MF_E_UNEXPECTED;
1937 result_entry_destroy(entry);
1938 return S_OK;
1941 static HRESULT WINAPI stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes)
1943 FIXME("stub (%p %p)\n", iface, bytes);
1944 return E_NOTIMPL;
1947 static const IMFByteStreamHandlerVtbl stream_handler_vtbl =
1949 stream_handler_QueryInterface,
1950 stream_handler_AddRef,
1951 stream_handler_Release,
1952 stream_handler_BeginCreateObject,
1953 stream_handler_EndCreateObject,
1954 stream_handler_CancelObjectCreation,
1955 stream_handler_GetMaxNumberOfBytesRequiredForResolution,
1958 static HRESULT WINAPI stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
1960 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1961 IsEqualIID(riid, &IID_IUnknown))
1963 *obj = iface;
1964 IMFAsyncCallback_AddRef(iface);
1965 return S_OK;
1968 WARN("Unsupported %s.\n", debugstr_guid(riid));
1969 *obj = NULL;
1970 return E_NOINTERFACE;
1973 static ULONG WINAPI stream_handler_callback_AddRef(IMFAsyncCallback *iface)
1975 struct stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1976 return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
1979 static ULONG WINAPI stream_handler_callback_Release(IMFAsyncCallback *iface)
1981 struct stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1982 return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
1985 static HRESULT WINAPI stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
1987 return E_NOTIMPL;
1990 static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1992 struct stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1993 IUnknown *object, *state = IMFAsyncResult_GetStateNoAddRef(result);
1994 struct object_context *context;
1995 struct result_entry *entry;
1996 HRESULT hr;
1998 if (!state || !(context = impl_from_IUnknown(state)))
1999 return E_INVALIDARG;
2001 if (FAILED(hr = media_source_create(context, (IMFMediaSource **)&object)))
2002 WARN("Failed to create media source, hr %#lx\n", hr);
2003 else
2005 if (FAILED(hr = result_entry_create(context->result, MF_OBJECT_MEDIASOURCE, object, &entry)))
2006 WARN("Failed to create handler result, hr %#lx\n", hr);
2007 else
2009 EnterCriticalSection(&handler->cs);
2010 list_add_tail(&handler->results, &entry->entry);
2011 LeaveCriticalSection(&handler->cs);
2014 IUnknown_Release(object);
2017 IMFAsyncResult_SetStatus(context->result, hr);
2018 MFInvokeCallback(context->result);
2020 return S_OK;
2023 static const IMFAsyncCallbackVtbl stream_handler_callback_vtbl =
2025 stream_handler_callback_QueryInterface,
2026 stream_handler_callback_AddRef,
2027 stream_handler_callback_Release,
2028 stream_handler_callback_GetParameters,
2029 stream_handler_callback_Invoke,
2032 HRESULT gstreamer_byte_stream_handler_create(REFIID riid, void **obj)
2034 struct stream_handler *handler;
2035 HRESULT hr;
2037 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
2039 if (!(handler = calloc(1, sizeof(*handler))))
2040 return E_OUTOFMEMORY;
2042 list_init(&handler->results);
2043 InitializeCriticalSection(&handler->cs);
2045 handler->IMFByteStreamHandler_iface.lpVtbl = &stream_handler_vtbl;
2046 handler->IMFAsyncCallback_iface.lpVtbl = &stream_handler_callback_vtbl;
2047 handler->refcount = 1;
2049 hr = IMFByteStreamHandler_QueryInterface(&handler->IMFByteStreamHandler_iface, riid, obj);
2050 IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
2052 return hr;