mfreadwrite/reader: Implement IMFSourceReaderEx_GetTransformForStream.
[wine.git] / dlls / mfreadwrite / reader.c
blob58de40c772bf4df2011f562acb000a1847fcfb49
1 /*
3 * Copyright 2014 Austin English
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 <stdarg.h>
22 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "ole2.h"
26 #include "rpcproxy.h"
28 #undef INITGUID
29 #include <guiddef.h>
30 #include "mfapi.h"
31 #include "mfidl.h"
32 #include "mfreadwrite.h"
33 #include "d3d9.h"
34 #include "initguid.h"
35 #include "dxva2api.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 #include "mf_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
44 struct stream_response
46 struct list entry;
47 HRESULT status;
48 DWORD stream_index;
49 DWORD stream_flags;
50 LONGLONG timestamp;
51 IMFSample *sample;
54 enum media_stream_state
56 STREAM_STATE_READY = 0,
57 STREAM_STATE_EOS,
60 enum media_source_state
62 SOURCE_STATE_STOPPED = 0,
63 SOURCE_STATE_STARTED,
66 enum media_stream_flags
68 STREAM_FLAG_SAMPLE_REQUESTED = 0x1, /* Protects from making multiple sample requests. */
69 STREAM_FLAG_SELECTED = 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
70 STREAM_FLAG_PRESENTED = 0x4, /* Set if stream was selected last time Start() was called. */
71 STREAM_FLAG_STOPPED = 0x8, /* Received MEStreamStopped */
74 struct transform_entry
76 struct list entry;
77 IMFTransform *transform;
78 unsigned int min_buffer_size;
79 GUID category;
80 BOOL hidden;
83 struct media_stream
85 IMFMediaStream *stream;
86 IMFMediaType *current;
87 struct list transforms;
88 IMFVideoSampleAllocatorEx *allocator;
89 IMFTransform *transform_service;
90 DWORD id;
91 unsigned int index;
92 enum media_stream_state state;
93 unsigned int flags;
94 unsigned int requests;
95 unsigned int responses;
96 LONGLONG last_sample_ts;
97 struct source_reader *reader;
100 enum source_reader_async_op
102 SOURCE_READER_ASYNC_READ,
103 SOURCE_READER_ASYNC_SEEK,
104 SOURCE_READER_ASYNC_FLUSH,
105 SOURCE_READER_ASYNC_SAMPLE_READY,
108 struct source_reader_async_command
110 IUnknown IUnknown_iface;
111 LONG refcount;
112 enum source_reader_async_op op;
113 union
115 struct
117 unsigned int flags;
118 unsigned int stream_index;
119 } read;
120 struct
122 GUID format;
123 PROPVARIANT position;
124 } seek;
125 struct
127 unsigned int stream_index;
128 } flush;
129 struct
131 unsigned int stream_index;
132 } sample;
133 struct
135 unsigned int stream_index;
136 } sa;
137 } u;
140 enum source_reader_flags
142 SOURCE_READER_FLUSHING = 0x1,
143 SOURCE_READER_SEEKING = 0x2,
144 SOURCE_READER_SHUTDOWN_ON_RELEASE = 0x4,
145 SOURCE_READER_D3D9_DEVICE_MANAGER = 0x8,
146 SOURCE_READER_DXGI_DEVICE_MANAGER = 0x10,
147 SOURCE_READER_HAS_DEVICE_MANAGER = SOURCE_READER_D3D9_DEVICE_MANAGER | SOURCE_READER_DXGI_DEVICE_MANAGER,
150 struct source_reader
152 IMFSourceReaderEx IMFSourceReaderEx_iface;
153 IMFAsyncCallback source_events_callback;
154 IMFAsyncCallback stream_events_callback;
155 IMFAsyncCallback async_commands_callback;
156 LONG refcount;
157 LONG public_refcount;
158 IMFMediaSource *source;
159 IMFPresentationDescriptor *descriptor;
160 IMFSourceReaderCallback *async_callback;
161 IMFAttributes *attributes;
162 IUnknown *device_manager;
163 unsigned int first_audio_stream_index;
164 unsigned int first_video_stream_index;
165 DWORD stream_count;
166 unsigned int flags;
167 DWORD queue;
168 enum media_source_state source_state;
169 struct media_stream *streams;
170 struct list responses;
171 CRITICAL_SECTION cs;
172 CONDITION_VARIABLE sample_event;
173 CONDITION_VARIABLE state_event;
174 CONDITION_VARIABLE stop_event;
177 static inline struct source_reader *impl_from_IMFSourceReaderEx(IMFSourceReaderEx *iface)
179 return CONTAINING_RECORD(iface, struct source_reader, IMFSourceReaderEx_iface);
182 static struct source_reader *impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
184 return CONTAINING_RECORD(iface, struct source_reader, source_events_callback);
187 static struct source_reader *impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
189 return CONTAINING_RECORD(iface, struct source_reader, stream_events_callback);
192 static struct source_reader *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
194 return CONTAINING_RECORD(iface, struct source_reader, async_commands_callback);
197 static struct source_reader_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
199 return CONTAINING_RECORD(iface, struct source_reader_async_command, IUnknown_iface);
202 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream);
204 static ULONG source_reader_addref(struct source_reader *reader)
206 return InterlockedIncrement(&reader->refcount);
209 static void transform_entry_destroy(struct transform_entry *entry)
211 IMFTransform_Release(entry->transform);
212 free(entry);
215 static void media_stream_destroy(struct media_stream *stream)
217 struct transform_entry *entry, *next;
219 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry)
221 list_remove(&entry->entry);
222 transform_entry_destroy(entry);
225 if (stream->stream)
226 IMFMediaStream_Release(stream->stream);
227 if (stream->current)
228 IMFMediaType_Release(stream->current);
229 if (stream->allocator)
230 IMFVideoSampleAllocatorEx_Release(stream->allocator);
233 static ULONG source_reader_release(struct source_reader *reader)
235 ULONG refcount = InterlockedDecrement(&reader->refcount);
236 unsigned int i;
238 if (!refcount)
240 if (reader->device_manager)
241 IUnknown_Release(reader->device_manager);
242 if (reader->async_callback)
243 IMFSourceReaderCallback_Release(reader->async_callback);
244 if (reader->descriptor)
245 IMFPresentationDescriptor_Release(reader->descriptor);
246 if (reader->attributes)
247 IMFAttributes_Release(reader->attributes);
248 IMFMediaSource_Release(reader->source);
250 for (i = 0; i < reader->stream_count; ++i)
252 struct media_stream *stream = &reader->streams[i];
253 media_stream_destroy(stream);
255 source_reader_release_responses(reader, NULL);
256 free(reader->streams);
257 MFUnlockWorkQueue(reader->queue);
258 DeleteCriticalSection(&reader->cs);
259 free(reader);
262 return refcount;
265 static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
267 if (IsEqualIID(riid, &IID_IUnknown))
269 *obj = iface;
270 IUnknown_AddRef(iface);
271 return S_OK;
274 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
275 *obj = NULL;
276 return E_NOINTERFACE;
279 static ULONG WINAPI source_reader_async_command_AddRef(IUnknown *iface)
281 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
282 return InterlockedIncrement(&command->refcount);
285 static ULONG WINAPI source_reader_async_command_Release(IUnknown *iface)
287 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
288 ULONG refcount = InterlockedIncrement(&command->refcount);
290 if (!refcount)
292 if (command->op == SOURCE_READER_ASYNC_SEEK)
293 PropVariantClear(&command->u.seek.position);
294 free(command);
297 return refcount;
300 static const IUnknownVtbl source_reader_async_command_vtbl =
302 source_reader_async_command_QueryInterface,
303 source_reader_async_command_AddRef,
304 source_reader_async_command_Release,
307 static HRESULT source_reader_create_async_op(enum source_reader_async_op op, struct source_reader_async_command **ret)
309 struct source_reader_async_command *command;
311 if (!(command = calloc(1, sizeof(*command))))
312 return E_OUTOFMEMORY;
314 command->IUnknown_iface.lpVtbl = &source_reader_async_command_vtbl;
315 command->op = op;
317 *ret = command;
319 return S_OK;
322 static HRESULT media_event_get_object(IMFMediaEvent *event, REFIID riid, void **obj)
324 PROPVARIANT value;
325 HRESULT hr;
327 PropVariantInit(&value);
328 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
330 WARN("Failed to get event value, hr %#lx.\n", hr);
331 return hr;
334 if (value.vt != VT_UNKNOWN || !value.punkVal)
336 WARN("Unexpected value type %d.\n", value.vt);
337 PropVariantClear(&value);
338 return E_UNEXPECTED;
341 hr = IUnknown_QueryInterface(value.punkVal, riid, obj);
342 PropVariantClear(&value);
343 if (FAILED(hr))
345 WARN("Unexpected object type.\n");
346 return hr;
349 return hr;
352 static HRESULT media_stream_get_id(IMFMediaStream *stream, DWORD *id)
354 IMFStreamDescriptor *sd;
355 HRESULT hr;
357 if (SUCCEEDED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
359 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, id);
360 IMFStreamDescriptor_Release(sd);
363 return hr;
366 static HRESULT WINAPI source_reader_callback_QueryInterface(IMFAsyncCallback *iface,
367 REFIID riid, void **obj)
369 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
371 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
372 IsEqualIID(riid, &IID_IUnknown))
374 *obj = iface;
375 IMFAsyncCallback_AddRef(iface);
376 return S_OK;
379 WARN("Unsupported %s.\n", debugstr_guid(riid));
380 *obj = NULL;
381 return E_NOINTERFACE;
384 static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface)
386 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
387 return source_reader_addref(reader);
390 static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface)
392 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
393 return source_reader_release(reader);
396 static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface,
397 DWORD *flags, DWORD *queue)
399 return E_NOTIMPL;
402 static void source_reader_response_ready(struct source_reader *reader, struct stream_response *response)
404 struct source_reader_async_command *command;
405 struct media_stream *stream = &reader->streams[response->stream_index];
406 HRESULT hr;
408 if (!stream->requests)
409 return;
411 if (reader->async_callback)
413 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY, &command)))
415 command->u.sample.stream_index = stream->index;
416 if (FAILED(hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface)))
417 WARN("Failed to submit async result, hr %#lx.\n", hr);
418 IUnknown_Release(&command->IUnknown_iface);
421 else
422 WakeAllConditionVariable(&reader->sample_event);
424 stream->requests--;
427 static void source_reader_copy_sample_buffer(IMFSample *src, IMFSample *dst)
429 IMFMediaBuffer *buffer;
430 LONGLONG time;
431 DWORD flags;
432 HRESULT hr;
434 IMFSample_CopyAllItems(src, (IMFAttributes *)dst);
436 IMFSample_SetSampleDuration(dst, 0);
437 IMFSample_SetSampleTime(dst, 0);
438 IMFSample_SetSampleFlags(dst, 0);
440 if (SUCCEEDED(IMFSample_GetSampleDuration(src, &time)))
441 IMFSample_SetSampleDuration(dst, time);
443 if (SUCCEEDED(IMFSample_GetSampleTime(src, &time)))
444 IMFSample_SetSampleTime(dst, time);
446 if (SUCCEEDED(IMFSample_GetSampleFlags(src, &flags)))
447 IMFSample_SetSampleFlags(dst, flags);
449 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src, NULL)))
451 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst, 0, &buffer)))
453 if (FAILED(hr = IMFSample_CopyToBuffer(src, buffer)))
454 WARN("Failed to copy a buffer, hr %#lx.\n", hr);
455 IMFMediaBuffer_Release(buffer);
460 static HRESULT source_reader_queue_response(struct source_reader *reader, struct media_stream *stream, HRESULT status,
461 DWORD stream_flags, LONGLONG timestamp, IMFSample *sample)
463 struct stream_response *response;
465 if (!(response = calloc(1, sizeof(*response))))
466 return E_OUTOFMEMORY;
468 response->status = status;
469 response->stream_index = stream->index;
470 response->stream_flags = stream_flags;
471 response->timestamp = timestamp;
472 response->sample = sample;
473 if (response->sample)
474 IMFSample_AddRef(response->sample);
476 list_add_tail(&reader->responses, &response->entry);
477 stream->responses++;
479 source_reader_response_ready(reader, response);
481 stream->last_sample_ts = timestamp;
483 return S_OK;
486 static HRESULT source_reader_queue_sample(struct source_reader *reader, struct media_stream *stream,
487 IMFSample *sample)
489 LONGLONG timestamp = 0;
491 if (FAILED(IMFSample_GetSampleTime(sample, &timestamp)))
492 WARN("Sample time wasn't set.\n");
494 return source_reader_queue_response(reader, stream, S_OK, 0, timestamp, sample);
497 static HRESULT source_reader_request_sample(struct source_reader *reader, struct media_stream *stream)
499 HRESULT hr = S_OK;
501 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
503 if (FAILED(hr = IMFMediaStream_RequestSample(stream->stream, NULL)))
504 WARN("Sample request failed, hr %#lx.\n", hr);
505 else
507 stream->flags |= STREAM_FLAG_SAMPLE_REQUESTED;
511 return hr;
514 static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IMFMediaEvent *event)
516 IMFMediaStream *stream;
517 unsigned int i;
518 DWORD id = 0;
519 HRESULT hr;
521 if (FAILED(hr = media_event_get_object(event, &IID_IMFMediaStream, (void **)&stream)))
523 WARN("Failed to get stream object, hr %#lx.\n", hr);
524 return hr;
527 TRACE("Got new stream %p.\n", stream);
529 if (FAILED(hr = media_stream_get_id(stream, &id)))
531 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
532 IMFMediaStream_Release(stream);
533 return hr;
536 EnterCriticalSection(&reader->cs);
538 for (i = 0; i < reader->stream_count; ++i)
540 if (id == reader->streams[i].id)
542 if (!reader->streams[i].stream)
544 reader->streams[i].stream = stream;
545 IMFMediaStream_AddRef(reader->streams[i].stream);
546 if (FAILED(hr = IMFMediaStream_BeginGetEvent(stream, &reader->stream_events_callback,
547 (IUnknown *)stream)))
549 WARN("Failed to subscribe to stream events, hr %#lx.\n", hr);
552 if (reader->streams[i].requests)
553 if (FAILED(source_reader_request_sample(reader, &reader->streams[i])))
554 WakeAllConditionVariable(&reader->sample_event);
556 break;
560 if (i == reader->stream_count)
561 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id);
563 LeaveCriticalSection(&reader->cs);
565 IMFMediaStream_Release(stream);
567 return hr;
570 static HRESULT source_reader_source_state_handler(struct source_reader *reader, MediaEventType event_type)
572 EnterCriticalSection(&reader->cs);
574 switch (event_type)
576 case MESourceStarted:
577 reader->source_state = SOURCE_STATE_STARTED;
578 reader->flags &= ~SOURCE_READER_SEEKING;
579 break;
580 case MESourceStopped:
581 reader->source_state = SOURCE_STATE_STOPPED;
582 reader->flags &= ~SOURCE_READER_SEEKING;
583 break;
584 case MESourceSeeked:
585 reader->flags &= ~SOURCE_READER_SEEKING;
586 break;
587 default:
588 WARN("Unhandled event %ld.\n", event_type);
591 LeaveCriticalSection(&reader->cs);
593 WakeAllConditionVariable(&reader->state_event);
594 if (event_type == MESourceStopped)
595 WakeAllConditionVariable(&reader->stop_event);
597 return S_OK;
600 static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
602 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
603 MediaEventType event_type;
604 IMFMediaSource *source;
605 IMFMediaEvent *event;
606 HRESULT hr;
608 TRACE("%p, %p.\n", iface, result);
610 source = (IMFMediaSource *)IMFAsyncResult_GetStateNoAddRef(result);
612 if (FAILED(hr = IMFMediaSource_EndGetEvent(source, result, &event)))
613 return hr;
615 IMFMediaEvent_GetType(event, &event_type);
617 TRACE("Got event %lu.\n", event_type);
619 switch (event_type)
621 case MENewStream:
622 hr = source_reader_new_stream_handler(reader, event);
623 break;
624 case MESourceStarted:
625 case MESourcePaused:
626 case MESourceStopped:
627 case MESourceSeeked:
628 hr = source_reader_source_state_handler(reader, event_type);
629 break;
630 case MEBufferingStarted:
631 case MEBufferingStopped:
632 case MEConnectStart:
633 case MEConnectEnd:
634 case MEExtendedType:
635 case MESourceCharacteristicsChanged:
636 case MESourceMetadataChanged:
637 case MEContentProtectionMetadata:
638 case MEDeviceThermalStateChanged:
639 if (reader->async_callback)
640 IMFSourceReaderCallback_OnEvent(reader->async_callback, MF_SOURCE_READER_MEDIASOURCE, event);
641 break;
642 default:
646 if (FAILED(hr))
647 WARN("Failed while handling %ld event, hr %#lx.\n", event_type, hr);
649 IMFMediaEvent_Release(event);
651 if (event_type != MESourceStopped)
652 IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
654 return S_OK;
657 static const IMFAsyncCallbackVtbl source_events_callback_vtbl =
659 source_reader_callback_QueryInterface,
660 source_reader_source_events_callback_AddRef,
661 source_reader_source_events_callback_Release,
662 source_reader_callback_GetParameters,
663 source_reader_source_events_callback_Invoke,
666 static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface)
668 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
669 return source_reader_addref(reader);
672 static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface)
674 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
675 return source_reader_release(reader);
678 static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info, IMFSample **out)
680 IMFMediaBuffer *buffer;
681 IMFSample *sample;
682 HRESULT hr;
684 *out = NULL;
685 if (FAILED(hr = MFCreateSample(&sample)))
686 return hr;
687 if (SUCCEEDED(hr = MFCreateAlignedMemoryBuffer(info->cbSize, info->cbAlignment, &buffer)))
689 if (SUCCEEDED(hr = IMFSample_AddBuffer(sample, buffer)))
691 *out = sample;
692 IMFSample_AddRef(sample);
694 IMFMediaBuffer_Release(buffer);
697 IMFSample_Release(sample);
698 return hr;
701 static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const GUID *attr, HRESULT *hr)
703 PROPVARIANT value;
705 PropVariantInit(&value);
706 if (SUCCEEDED(*hr) && FAILED(IMFMediaType_GetItem(dst, attr, NULL))
707 && SUCCEEDED(IMFMediaType_GetItem(src, attr, &value)))
708 *hr = IMFMediaType_SetItem(dst, attr, &value);
709 PropVariantClear(&value);
712 /* update a media type with additional attributes reported by upstream element */
713 /* also present in mf/topology_loader.c pipeline */
714 static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type)
716 HRESULT hr = S_OK;
718 /* propagate common video attributes */
719 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_SIZE, &hr);
720 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_RATE, &hr);
721 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_DEFAULT_STRIDE, &hr);
722 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_ROTATION, &hr);
723 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FIXED_SIZE_SAMPLES, &hr);
724 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_PIXEL_ASPECT_RATIO, &hr);
725 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &hr);
726 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &hr);
728 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_CHROMA_SITING, &hr);
729 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_INTERLACE_MODE, &hr);
730 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_TRANSFER_FUNCTION, &hr);
731 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_PRIMARIES, &hr);
732 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_YUV_MATRIX, &hr);
733 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_LIGHTING, &hr);
734 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_NOMINAL_RANGE, &hr);
736 /* propagate common audio attributes */
737 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_NUM_CHANNELS, &hr);
738 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &hr);
739 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &hr);
740 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &hr);
741 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &hr);
742 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_CHANNEL_MASK, &hr);
743 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &hr);
744 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &hr);
746 return hr;
749 static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream,
750 struct transform_entry *entry);
751 static HRESULT source_reader_push_transform_samples(struct source_reader *reader, struct media_stream *stream,
752 struct transform_entry *entry, IMFSample *sample)
754 HRESULT hr;
758 if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry))
759 && hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
760 return hr;
761 if (SUCCEEDED(hr = IMFTransform_ProcessInput(entry->transform, 0, sample, 0)))
762 return source_reader_pull_transform_samples(reader, stream, entry);
764 while (hr == MF_E_NOTACCEPTING);
766 return hr;
769 static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream,
770 struct transform_entry *entry)
772 MFT_OUTPUT_STREAM_INFO stream_info = {0};
773 struct transform_entry *next = NULL;
774 struct list *ptr;
775 DWORD status;
776 HRESULT hr;
778 if ((ptr = list_next(&stream->transforms, &entry->entry)))
779 next = LIST_ENTRY(ptr, struct transform_entry, entry);
781 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info)))
782 return hr;
783 stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size);
785 while (SUCCEEDED(hr))
787 MFT_OUTPUT_DATA_BUFFER out_buffer = {0};
789 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES))
790 && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample)))
791 break;
793 if (SUCCEEDED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status)))
795 if (next)
796 hr = source_reader_push_transform_samples(reader, stream, next, out_buffer.pSample);
797 else
798 hr = source_reader_queue_sample(reader, stream, out_buffer.pSample);
801 if (out_buffer.pSample)
802 IMFSample_Release(out_buffer.pSample);
803 if (out_buffer.pEvents)
804 IMFCollection_Release(out_buffer.pEvents);
807 return hr;
810 static HRESULT source_reader_drain_transform_samples(struct source_reader *reader, struct media_stream *stream,
811 struct transform_entry *entry)
813 struct transform_entry *next = NULL;
814 struct list *ptr;
815 HRESULT hr;
817 if ((ptr = list_next(&stream->transforms, &entry->entry)))
818 next = LIST_ENTRY(ptr, struct transform_entry, entry);
820 if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
821 WARN("Failed to drain transform %p, hr %#lx\n", entry->transform, hr);
822 if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry))
823 && hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
824 WARN("Failed to pull pending samples, hr %#lx.\n", hr);
826 return next ? source_reader_drain_transform_samples(reader, stream, next) : S_OK;
829 static HRESULT source_reader_flush_transform_samples(struct source_reader *reader, struct media_stream *stream,
830 struct transform_entry *entry)
832 struct transform_entry *next = NULL;
833 struct list *ptr;
834 HRESULT hr;
836 if ((ptr = list_next(&stream->transforms, &entry->entry)))
837 next = LIST_ENTRY(ptr, struct transform_entry, entry);
839 if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_FLUSH, 0)))
840 WARN("Failed to flush transform %p, hr %#lx\n", entry->transform, hr);
842 return next ? source_reader_flush_transform_samples(reader, stream, next) : S_OK;
845 static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream,
846 IMFSample *sample)
848 struct transform_entry *entry;
849 struct list *ptr;
850 HRESULT hr;
852 if (!(ptr = list_head(&stream->transforms)))
853 return source_reader_queue_sample(reader, stream, sample);
854 entry = LIST_ENTRY(ptr, struct transform_entry, entry);
856 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
857 if (SUCCEEDED(hr = source_reader_push_transform_samples(reader, stream, entry, sample))
858 || hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
859 hr = stream->requests ? source_reader_request_sample(reader, stream) : S_OK;
860 else
861 WARN("Transform failed to process output, hr %#lx.\n", hr);
863 return hr;
866 static HRESULT source_reader_media_sample_handler(struct source_reader *reader, IMFMediaStream *stream,
867 IMFMediaEvent *event)
869 IMFSample *sample;
870 unsigned int i;
871 DWORD id = 0;
872 HRESULT hr;
874 TRACE("Got new sample for stream %p.\n", stream);
876 if (FAILED(hr = media_event_get_object(event, &IID_IMFSample, (void **)&sample)))
878 WARN("Failed to get sample object, hr %#lx.\n", hr);
879 return hr;
882 if (FAILED(hr = media_stream_get_id(stream, &id)))
884 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
885 IMFSample_Release(sample);
886 return hr;
889 EnterCriticalSection(&reader->cs);
891 for (i = 0; i < reader->stream_count; ++i)
893 if (id == reader->streams[i].id)
895 /* FIXME: propagate processing errors? */
896 reader->streams[i].flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
897 hr = source_reader_process_sample(reader, &reader->streams[i], sample);
898 break;
902 if (i == reader->stream_count)
903 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id);
905 LeaveCriticalSection(&reader->cs);
907 IMFSample_Release(sample);
909 return hr;
912 static HRESULT source_reader_media_stream_state_handler(struct source_reader *reader, IMFMediaStream *stream,
913 IMFMediaEvent *event)
915 MediaEventType event_type;
916 LONGLONG timestamp;
917 PROPVARIANT value;
918 unsigned int i;
919 HRESULT hr;
920 DWORD id;
922 IMFMediaEvent_GetType(event, &event_type);
924 if (FAILED(hr = media_stream_get_id(stream, &id)))
926 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
927 return hr;
930 EnterCriticalSection(&reader->cs);
932 for (i = 0; i < reader->stream_count; ++i)
934 struct media_stream *stream = &reader->streams[i];
936 if (id == stream->id)
938 switch (event_type)
940 case MEEndOfStream:
942 struct list *ptr;
944 stream->state = STREAM_STATE_EOS;
945 stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
947 if ((ptr = list_head(&stream->transforms)))
949 struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry);
950 if (FAILED(hr = source_reader_drain_transform_samples(reader, stream, entry)))
951 WARN("Failed to drain pending samples, hr %#lx.\n", hr);
954 while (stream->requests)
955 source_reader_queue_response(reader, stream, S_OK, MF_SOURCE_READERF_ENDOFSTREAM, 0, NULL);
957 break;
959 case MEStreamSeeked:
960 case MEStreamStarted:
961 stream->state = STREAM_STATE_READY;
962 break;
963 case MEStreamStopped:
964 stream->flags |= STREAM_FLAG_STOPPED;
965 break;
966 case MEStreamTick:
967 value.vt = VT_EMPTY;
968 hr = SUCCEEDED(IMFMediaEvent_GetValue(event, &value)) && value.vt == VT_I8 ? S_OK : E_UNEXPECTED;
969 timestamp = SUCCEEDED(hr) ? value.hVal.QuadPart : 0;
970 PropVariantClear(&value);
972 source_reader_queue_response(reader, stream, hr, MF_SOURCE_READERF_STREAMTICK, timestamp, NULL);
974 break;
975 default:
979 break;
983 LeaveCriticalSection(&reader->cs);
985 if (event_type == MEStreamStopped)
986 WakeAllConditionVariable(&reader->stop_event);
988 return S_OK;
991 static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
993 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
994 MediaEventType event_type;
995 IMFMediaStream *stream;
996 IMFMediaEvent *event;
997 HRESULT hr;
999 TRACE("%p, %p.\n", iface, result);
1001 stream = (IMFMediaStream *)IMFAsyncResult_GetStateNoAddRef(result);
1003 if (FAILED(hr = IMFMediaStream_EndGetEvent(stream, result, &event)))
1004 return hr;
1006 IMFMediaEvent_GetType(event, &event_type);
1008 TRACE("Got event %lu.\n", event_type);
1010 switch (event_type)
1012 case MEMediaSample:
1013 hr = source_reader_media_sample_handler(reader, stream, event);
1014 break;
1015 case MEStreamSeeked:
1016 case MEStreamStarted:
1017 case MEStreamStopped:
1018 case MEStreamTick:
1019 case MEEndOfStream:
1020 hr = source_reader_media_stream_state_handler(reader, stream, event);
1021 break;
1022 default:
1026 if (FAILED(hr))
1027 WARN("Failed while handling %ld event, hr %#lx.\n", event_type, hr);
1029 IMFMediaEvent_Release(event);
1031 if (event_type != MEStreamStopped)
1032 IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
1034 return S_OK;
1037 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl =
1039 source_reader_callback_QueryInterface,
1040 source_reader_stream_events_callback_AddRef,
1041 source_reader_stream_events_callback_Release,
1042 source_reader_callback_GetParameters,
1043 source_reader_stream_events_callback_Invoke,
1046 static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface)
1048 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1049 return source_reader_addref(reader);
1052 static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface)
1054 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1055 return source_reader_release(reader);
1058 static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response)
1060 struct media_stream *stream;
1062 list_remove(&response->entry);
1064 if (response->stream_index < reader->stream_count)
1066 stream = &reader->streams[response->stream_index];
1067 if (stream->responses)
1068 --stream->responses;
1071 return response;
1074 static struct stream_response *media_stream_pop_response(struct source_reader *reader, struct media_stream *stream)
1076 struct stream_response *response;
1077 IMFSample *sample;
1078 HRESULT hr;
1080 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
1082 if (stream && response->stream_index != stream->index)
1083 continue;
1085 if (!stream) stream = &reader->streams[response->stream_index];
1087 if (response->sample && stream->allocator)
1089 /* Return allocation error to the caller, while keeping original response sample in for later. */
1090 if (SUCCEEDED(hr = IMFVideoSampleAllocatorEx_AllocateSample(stream->allocator, &sample)))
1092 source_reader_copy_sample_buffer(response->sample, sample);
1093 IMFSample_Release(response->sample);
1094 response->sample = sample;
1096 else
1098 if (!(response = calloc(1, sizeof(*response))))
1099 return NULL;
1101 response->status = hr;
1102 response->stream_flags = MF_SOURCE_READERF_ERROR;
1103 return response;
1107 return media_stream_detach_response(reader, response);
1110 return NULL;
1113 static void source_reader_release_response(struct stream_response *response)
1115 if (response->sample)
1116 IMFSample_Release(response->sample);
1117 free(response);
1120 static HRESULT source_reader_get_stream_selection(const struct source_reader *reader, DWORD index, BOOL *selected)
1122 IMFStreamDescriptor *sd;
1124 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, selected, &sd)))
1125 return MF_E_INVALIDSTREAMNUMBER;
1126 IMFStreamDescriptor_Release(sd);
1128 return S_OK;
1131 static HRESULT source_reader_start_source(struct source_reader *reader)
1133 BOOL selected, selection_changed = FALSE;
1134 PROPVARIANT position;
1135 HRESULT hr = S_OK;
1136 unsigned int i;
1138 for (i = 0; i < reader->stream_count; ++i)
1140 source_reader_get_stream_selection(reader, i, &selected);
1141 if (selected)
1142 reader->streams[i].flags |= STREAM_FLAG_SELECTED;
1143 else
1144 reader->streams[i].flags &= ~STREAM_FLAG_SELECTED;
1147 if (reader->source_state == SOURCE_STATE_STARTED)
1149 for (i = 0; i < reader->stream_count; ++i)
1151 selection_changed = !!(reader->streams[i].flags & STREAM_FLAG_SELECTED) ^
1152 !!(reader->streams[i].flags & STREAM_FLAG_PRESENTED);
1153 if (selection_changed)
1154 break;
1158 position.hVal.QuadPart = 0;
1159 if (reader->source_state != SOURCE_STATE_STARTED || selection_changed)
1161 position.vt = reader->source_state == SOURCE_STATE_STARTED ? VT_EMPTY : VT_I8;
1163 /* Update cached stream selection if descriptor was accepted. */
1164 if (SUCCEEDED(hr = IMFMediaSource_Start(reader->source, reader->descriptor, &GUID_NULL, &position)))
1166 for (i = 0; i < reader->stream_count; ++i)
1168 if (reader->streams[i].flags & STREAM_FLAG_SELECTED)
1169 reader->streams[i].flags |= STREAM_FLAG_PRESENTED;
1174 return hr;
1177 static BOOL source_reader_got_response_for_stream(struct source_reader *reader, struct media_stream *stream)
1179 struct stream_response *response;
1181 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
1183 if (response->stream_index == stream->index)
1184 return TRUE;
1187 return FALSE;
1190 static BOOL source_reader_get_read_result(struct source_reader *reader, struct media_stream *stream, DWORD flags,
1191 HRESULT *status, DWORD *stream_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1193 struct stream_response *response = NULL;
1194 BOOL request_sample = FALSE;
1196 if ((response = media_stream_pop_response(reader, stream)))
1198 *status = response->status;
1199 *stream_index = stream->index;
1200 *stream_flags = response->stream_flags;
1201 *timestamp = response->timestamp;
1202 *sample = response->sample;
1203 if (*sample)
1204 IMFSample_AddRef(*sample);
1206 source_reader_release_response(response);
1208 else
1210 *status = S_OK;
1211 *stream_index = stream->index;
1212 *timestamp = 0;
1213 *sample = NULL;
1215 if (stream->state == STREAM_STATE_EOS)
1217 *stream_flags = MF_SOURCE_READERF_ENDOFSTREAM;
1219 else
1221 request_sample = !(flags & MF_SOURCE_READER_CONTROLF_DRAIN);
1222 *stream_flags = 0;
1226 return !request_sample;
1229 static HRESULT source_reader_get_next_selected_stream(struct source_reader *reader, DWORD *stream_index)
1231 unsigned int i, first_selected = ~0u;
1232 BOOL selected, stream_drained;
1233 LONGLONG min_ts = MAXLONGLONG;
1235 for (i = 0; i < reader->stream_count; ++i)
1237 stream_drained = reader->streams[i].state == STREAM_STATE_EOS && !reader->streams[i].responses;
1238 selected = SUCCEEDED(source_reader_get_stream_selection(reader, i, &selected)) && selected;
1240 if (selected)
1242 if (first_selected == ~0u)
1243 first_selected = i;
1245 /* Pick the stream whose last sample had the lowest timestamp. */
1246 if (!stream_drained && reader->streams[i].last_sample_ts < min_ts)
1248 min_ts = reader->streams[i].last_sample_ts;
1249 *stream_index = i;
1254 /* If all selected streams reached EOS, use first selected. */
1255 if (first_selected != ~0u)
1257 if (min_ts == MAXLONGLONG)
1258 *stream_index = first_selected;
1261 return first_selected == ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED : S_OK;
1264 static HRESULT source_reader_get_stream_read_index(struct source_reader *reader, unsigned int index, DWORD *stream_index)
1266 BOOL selected;
1267 HRESULT hr;
1269 switch (index)
1271 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1272 *stream_index = reader->first_video_stream_index;
1273 break;
1274 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1275 *stream_index = reader->first_audio_stream_index;
1276 break;
1277 case MF_SOURCE_READER_ANY_STREAM:
1278 return source_reader_get_next_selected_stream(reader, stream_index);
1279 default:
1280 *stream_index = index;
1283 /* Can't read from deselected streams. */
1284 if (SUCCEEDED(hr = source_reader_get_stream_selection(reader, *stream_index, &selected)) && !selected)
1285 hr = MF_E_INVALIDREQUEST;
1287 return hr;
1290 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream)
1292 struct stream_response *ptr, *next;
1294 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &reader->responses, struct stream_response, entry)
1296 if (stream && stream->index != ptr->stream_index &&
1297 ptr->stream_index != MF_SOURCE_READER_FIRST_VIDEO_STREAM &&
1298 ptr->stream_index != MF_SOURCE_READER_FIRST_AUDIO_STREAM &&
1299 ptr->stream_index != MF_SOURCE_READER_ANY_STREAM)
1301 continue;
1303 media_stream_detach_response(reader, ptr);
1304 source_reader_release_response(ptr);
1308 static void source_reader_flush_stream(struct source_reader *reader, DWORD stream_index)
1310 struct media_stream *stream = &reader->streams[stream_index];
1311 struct list *ptr;
1312 HRESULT hr;
1314 source_reader_release_responses(reader, stream);
1316 if ((ptr = list_head(&stream->transforms)))
1318 struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry);
1319 if (FAILED(hr = source_reader_flush_transform_samples(reader, stream, entry)))
1320 WARN("Failed to drain pending samples, hr %#lx.\n", hr);
1323 stream->requests = 0;
1326 static HRESULT source_reader_flush(struct source_reader *reader, unsigned int index)
1328 unsigned int stream_index;
1329 HRESULT hr = S_OK;
1331 if (index == MF_SOURCE_READER_ALL_STREAMS)
1333 for (stream_index = 0; stream_index < reader->stream_count; ++stream_index)
1334 source_reader_flush_stream(reader, stream_index);
1336 else
1338 switch (index)
1340 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1341 stream_index = reader->first_video_stream_index;
1342 break;
1343 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1344 stream_index = reader->first_audio_stream_index;
1345 break;
1346 default:
1347 stream_index = index;
1350 if (stream_index < reader->stream_count)
1351 source_reader_flush_stream(reader, stream_index);
1352 else
1353 hr = MF_E_INVALIDSTREAMNUMBER;
1356 return hr;
1359 static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1361 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1362 struct media_stream *stream, stub_stream = { .requests = 1 };
1363 struct source_reader_async_command *command;
1364 struct stream_response *response;
1365 DWORD stream_index, stream_flags;
1366 BOOL report_sample = FALSE;
1367 IMFSample *sample = NULL;
1368 LONGLONG timestamp = 0;
1369 HRESULT hr, status;
1370 IUnknown *state;
1372 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
1373 return hr;
1375 command = impl_from_async_command_IUnknown(state);
1377 switch (command->op)
1379 case SOURCE_READER_ASYNC_READ:
1380 EnterCriticalSection(&reader->cs);
1382 if (SUCCEEDED(hr = source_reader_start_source(reader)))
1384 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, command->u.read.stream_index, &stream_index)))
1386 stream = &reader->streams[stream_index];
1388 if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status,
1389 &stream_index, &stream_flags, &timestamp, &sample)))
1391 stream->requests++;
1392 source_reader_request_sample(reader, stream);
1393 /* FIXME: set error stream/reader state on request failure */
1396 else
1398 stub_stream.index = command->u.read.stream_index;
1399 source_reader_queue_response(reader, &stub_stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL);
1403 LeaveCriticalSection(&reader->cs);
1405 if (report_sample)
1406 IMFSourceReaderCallback_OnReadSample(reader->async_callback, status, stream_index, stream_flags,
1407 timestamp, sample);
1409 if (sample)
1410 IMFSample_Release(sample);
1412 break;
1414 case SOURCE_READER_ASYNC_SEEK:
1416 EnterCriticalSection(&reader->cs);
1417 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, &command->u.seek.format,
1418 &command->u.seek.position)))
1420 reader->flags |= SOURCE_READER_SEEKING;
1422 LeaveCriticalSection(&reader->cs);
1424 break;
1426 case SOURCE_READER_ASYNC_SAMPLE_READY:
1428 EnterCriticalSection(&reader->cs);
1429 response = media_stream_pop_response(reader, NULL);
1430 LeaveCriticalSection(&reader->cs);
1432 if (response)
1434 IMFSourceReaderCallback_OnReadSample(reader->async_callback, response->status, response->stream_index,
1435 response->stream_flags, response->timestamp, response->sample);
1436 source_reader_release_response(response);
1439 break;
1440 case SOURCE_READER_ASYNC_FLUSH:
1441 EnterCriticalSection(&reader->cs);
1442 source_reader_flush(reader, command->u.flush.stream_index);
1443 reader->flags &= ~SOURCE_READER_FLUSHING;
1444 LeaveCriticalSection(&reader->cs);
1446 IMFSourceReaderCallback_OnFlush(reader->async_callback, command->u.flush.stream_index);
1447 break;
1448 default:
1452 IUnknown_Release(state);
1454 return S_OK;
1457 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl =
1459 source_reader_callback_QueryInterface,
1460 source_reader_async_commands_callback_AddRef,
1461 source_reader_async_commands_callback_Release,
1462 source_reader_callback_GetParameters,
1463 source_reader_async_commands_callback_Invoke,
1466 static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReaderEx *iface, REFIID riid, void **out)
1468 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1470 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1472 if (IsEqualGUID(riid, &IID_IUnknown)
1473 || IsEqualGUID(riid, &IID_IMFSourceReader)
1474 || IsEqualGUID(riid, &IID_IMFSourceReaderEx))
1476 *out = &reader->IMFSourceReaderEx_iface;
1478 else
1480 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
1481 *out = NULL;
1482 return E_NOINTERFACE;
1485 IUnknown_AddRef((IUnknown*)*out);
1486 return S_OK;
1489 static ULONG WINAPI src_reader_AddRef(IMFSourceReaderEx *iface)
1491 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1492 ULONG refcount = InterlockedIncrement(&reader->public_refcount);
1494 TRACE("%p, refcount %lu.\n", iface, refcount);
1496 return refcount;
1499 static BOOL source_reader_is_source_stopped(const struct source_reader *reader)
1501 unsigned int i;
1503 if (reader->source_state != SOURCE_STATE_STOPPED)
1504 return FALSE;
1506 for (i = 0; i < reader->stream_count; ++i)
1508 if (reader->streams[i].stream && !(reader->streams[i].flags & STREAM_FLAG_STOPPED))
1509 return FALSE;
1512 return TRUE;
1515 static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface)
1517 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1518 ULONG refcount = InterlockedDecrement(&reader->public_refcount);
1519 unsigned int i;
1521 TRACE("%p, refcount %lu.\n", iface, refcount);
1523 if (!refcount)
1525 if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE)
1526 IMFMediaSource_Shutdown(reader->source);
1527 else if (SUCCEEDED(IMFMediaSource_Stop(reader->source)))
1529 EnterCriticalSection(&reader->cs);
1531 while (!source_reader_is_source_stopped(reader))
1533 SleepConditionVariableCS(&reader->stop_event, &reader->cs, INFINITE);
1536 LeaveCriticalSection(&reader->cs);
1539 for (i = 0; i < reader->stream_count; ++i)
1541 struct media_stream *stream = &reader->streams[i];
1542 IMFVideoSampleAllocatorCallback *callback;
1544 if (!stream->allocator)
1545 continue;
1547 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream->allocator, &IID_IMFVideoSampleAllocatorCallback,
1548 (void **)&callback)))
1550 IMFVideoSampleAllocatorCallback_SetCallback(callback, NULL);
1551 IMFVideoSampleAllocatorCallback_Release(callback);
1555 source_reader_release(reader);
1558 return refcount;
1561 static HRESULT WINAPI src_reader_GetStreamSelection(IMFSourceReaderEx *iface, DWORD index, BOOL *selected)
1563 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1565 TRACE("%p, %#lx, %p.\n", iface, index, selected);
1567 switch (index)
1569 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1570 index = reader->first_video_stream_index;
1571 break;
1572 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1573 index = reader->first_audio_stream_index;
1574 break;
1575 default:
1579 return source_reader_get_stream_selection(reader, index, selected);
1582 static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReaderEx *iface, DWORD index, BOOL selection)
1584 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1585 HRESULT hr = S_OK;
1586 BOOL selection_changed = FALSE, selected;
1587 unsigned int i;
1589 TRACE("%p, %#lx, %d.\n", iface, index, selection);
1591 selection = !!selection;
1593 EnterCriticalSection(&reader->cs);
1595 if (index == MF_SOURCE_READER_ALL_STREAMS)
1597 for (i = 0; i < reader->stream_count; ++i)
1599 if (!selection_changed)
1601 source_reader_get_stream_selection(reader, i, &selected);
1602 selection_changed = !!(selected ^ selection);
1605 if (selection)
1606 IMFPresentationDescriptor_SelectStream(reader->descriptor, i);
1607 else
1608 IMFPresentationDescriptor_DeselectStream(reader->descriptor, i);
1611 else
1613 switch (index)
1615 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1616 index = reader->first_video_stream_index;
1617 break;
1618 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1619 index = reader->first_audio_stream_index;
1620 break;
1621 default:
1625 source_reader_get_stream_selection(reader, index, &selected);
1626 selection_changed = !!(selected ^ selection);
1628 if (selection)
1629 hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
1630 else
1631 hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
1634 if (selection_changed)
1636 for (i = 0; i < reader->stream_count; ++i)
1638 reader->streams[i].last_sample_ts = 0;
1642 LeaveCriticalSection(&reader->cs);
1644 return SUCCEEDED(hr) ? S_OK : MF_E_INVALIDSTREAMNUMBER;
1647 static HRESULT source_reader_get_native_media_type(struct source_reader *reader, DWORD index, DWORD type_index,
1648 IMFMediaType **type)
1650 IMFMediaTypeHandler *handler;
1651 IMFStreamDescriptor *sd;
1652 IMFMediaType *src_type;
1653 BOOL selected;
1654 HRESULT hr;
1656 switch (index)
1658 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1659 index = reader->first_video_stream_index;
1660 break;
1661 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1662 index = reader->first_audio_stream_index;
1663 break;
1664 default:
1668 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1669 return MF_E_INVALIDSTREAMNUMBER;
1671 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
1672 IMFStreamDescriptor_Release(sd);
1673 if (FAILED(hr))
1674 return hr;
1676 if (type_index == MF_SOURCE_READER_CURRENT_TYPE_INDEX)
1677 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &src_type);
1678 else
1679 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, type_index, &src_type);
1680 IMFMediaTypeHandler_Release(handler);
1682 if (SUCCEEDED(hr))
1684 if (SUCCEEDED(hr = MFCreateMediaType(type)))
1685 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)*type);
1686 IMFMediaType_Release(src_type);
1689 return hr;
1692 static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReaderEx *iface, DWORD index, DWORD type_index,
1693 IMFMediaType **type)
1695 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1697 TRACE("%p, %#lx, %#lx, %p.\n", iface, index, type_index, type);
1699 return source_reader_get_native_media_type(reader, index, type_index, type);
1702 static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReaderEx *iface, DWORD index, IMFMediaType **type)
1704 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1705 HRESULT hr;
1707 TRACE("%p, %#lx, %p.\n", iface, index, type);
1709 switch (index)
1711 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1712 index = reader->first_video_stream_index;
1713 break;
1714 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1715 index = reader->first_audio_stream_index;
1716 break;
1717 default:
1721 if (index >= reader->stream_count)
1722 return MF_E_INVALIDSTREAMNUMBER;
1724 if (FAILED(hr = MFCreateMediaType(type)))
1725 return hr;
1727 EnterCriticalSection(&reader->cs);
1729 hr = IMFMediaType_CopyAllItems(reader->streams[index].current, (IMFAttributes *)*type);
1731 LeaveCriticalSection(&reader->cs);
1733 return hr;
1736 static HRESULT source_reader_get_source_type_handler(struct source_reader *reader, DWORD index,
1737 IMFMediaTypeHandler **handler)
1739 IMFStreamDescriptor *sd;
1740 BOOL selected;
1741 HRESULT hr;
1743 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1744 return hr;
1746 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, handler);
1747 IMFStreamDescriptor_Release(sd);
1749 return hr;
1752 static HRESULT source_reader_set_compatible_media_type(struct source_reader *reader, DWORD index, IMFMediaType *type)
1754 struct media_stream *stream = &reader->streams[index];
1755 struct transform_entry *entry, *next;
1756 IMFMediaTypeHandler *type_handler;
1757 IMFMediaType *native_type;
1758 BOOL type_set = FALSE;
1759 unsigned int i = 0;
1760 DWORD flags;
1761 HRESULT hr;
1763 if (FAILED(hr = IMFMediaType_IsEqual(type, stream->current, &flags)))
1764 return hr;
1766 if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES))
1767 return MF_E_INVALIDMEDIATYPE;
1769 /* No need for a decoder or type change. */
1770 if (flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)
1771 return S_OK;
1773 if (stream->transform_service)
1775 IMFTransform_Release(stream->transform_service);
1776 stream->transform_service = NULL;
1778 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry)
1780 list_remove(&entry->entry);
1781 transform_entry_destroy(entry);
1784 if (FAILED(hr = source_reader_get_source_type_handler(reader, index, &type_handler)))
1785 return hr;
1787 while (!type_set && IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, i++, &native_type) == S_OK)
1789 static const DWORD compare_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_DATA;
1791 if (SUCCEEDED(IMFMediaType_IsEqual(native_type, type, &flags)) && (flags & compare_flags) == compare_flags)
1793 if ((type_set = SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler, native_type))))
1794 IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)stream->current);
1797 IMFMediaType_Release(native_type);
1800 IMFMediaTypeHandler_Release(type_handler);
1802 return type_set ? S_OK : S_FALSE;
1805 static HRESULT source_reader_create_sample_allocator_attributes(const struct source_reader *reader,
1806 IMFAttributes **attributes)
1808 UINT32 shared = 0, shared_without_mutex = 0;
1809 HRESULT hr;
1811 if (FAILED(hr = MFCreateAttributes(attributes, 1)))
1812 return hr;
1814 IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared);
1815 IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex);
1817 if (shared_without_mutex)
1818 hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE);
1819 else if (shared)
1820 hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED, TRUE);
1822 return hr;
1825 static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index)
1827 struct media_stream *stream = &reader->streams[index];
1828 IMFAttributes *attributes = NULL;
1829 GUID major = { 0 };
1830 HRESULT hr;
1832 IMFMediaType_GetMajorType(stream->current, &major);
1833 if (!IsEqualGUID(&major, &MFMediaType_Video))
1834 return S_OK;
1836 if (!(reader->flags & SOURCE_READER_HAS_DEVICE_MANAGER))
1837 return S_OK;
1839 if (!stream->allocator)
1841 if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&stream->allocator)))
1843 WARN("Failed to create sample allocator, hr %#lx.\n", hr);
1844 return hr;
1848 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream->allocator);
1849 if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(stream->allocator, reader->device_manager)))
1851 WARN("Failed to set device manager, hr %#lx.\n", hr);
1852 return hr;
1855 if (FAILED(hr = source_reader_create_sample_allocator_attributes(reader, &attributes)))
1856 WARN("Failed to create allocator attributes, hr %#lx.\n", hr);
1858 if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8,
1859 attributes, stream->current)))
1861 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr);
1864 if (attributes)
1865 IMFAttributes_Release(attributes);
1867 return hr;
1870 static BOOL source_reader_allow_video_processor(struct source_reader *reader, BOOL *advanced)
1872 UINT32 value;
1874 *advanced = FALSE;
1875 if (!reader->attributes)
1876 return FALSE;
1878 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, &value)))
1879 *advanced = value;
1880 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, &value)))
1881 return value || *advanced;
1883 return *advanced;
1886 static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL decoder, BOOL allow_processor,
1887 IMFMediaType *input_type, IMFMediaType *output_type, struct transform_entry **out)
1889 MFT_REGISTER_TYPE_INFO in_type, out_type;
1890 struct transform_entry *entry;
1891 GUID *classes, category;
1892 IMFTransform *transform;
1893 UINT i, count;
1894 HRESULT hr;
1896 if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &in_type.guidMajorType))
1897 || FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype)))
1898 return hr;
1899 if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType))
1900 || FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype)))
1901 return hr;
1903 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video))
1904 category = decoder ? MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_PROCESSOR;
1905 else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio))
1906 category = decoder ? MFT_CATEGORY_AUDIO_DECODER : MFT_CATEGORY_AUDIO_EFFECT;
1907 else
1908 return MF_E_TOPO_CODEC_NOT_FOUND;
1910 if (!(entry = calloc(1, sizeof(*entry))))
1911 return E_OUTOFMEMORY;
1912 list_init(&entry->entry);
1913 entry->category = category;
1915 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio))
1916 IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT,
1917 &entry->min_buffer_size);
1919 count = 0;
1920 if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, allow_processor ? NULL : &out_type, NULL, &classes, &count)))
1922 if (!count)
1923 return MF_E_TOPO_CODEC_NOT_FOUND;
1925 for (i = 0; i < count; i++)
1927 IMFMediaType *media_type;
1929 if (FAILED(hr = CoCreateInstance(&classes[i], NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform)))
1930 break;
1931 if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0))
1932 && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type)))
1934 if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type))
1935 && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0)) && allow_processor
1936 && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type)))
1938 struct transform_entry *converter;
1940 if (SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0))
1941 && SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type))
1942 && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, media_type, output_type, &converter)))
1943 list_add_tail(&entry->entry, &converter->entry);
1945 IMFMediaType_Release(media_type);
1948 if (SUCCEEDED(hr))
1950 entry->transform = transform;
1951 *out = entry;
1952 return S_OK;
1956 IMFTransform_Release(transform);
1959 CoTaskMemFree(classes);
1962 free(entry);
1963 return hr;
1966 static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type)
1968 BOOL enable_advanced, allow_processor;
1969 struct media_stream *stream = &reader->streams[index];
1970 IMFMediaType *input_type;
1971 unsigned int i = 0;
1972 HRESULT hr;
1974 allow_processor = source_reader_allow_video_processor(reader, &enable_advanced);
1976 while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type)))
1978 struct transform_entry *entry;
1980 /* first, try to append a single processor, then try again with a decoder and a processor */
1981 if ((allow_processor && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, input_type, output_type, &entry)))
1982 || SUCCEEDED(hr = source_reader_create_transform(reader, TRUE, allow_processor, input_type, output_type, &entry)))
1984 struct list *ptr = list_head(&entry->entry);
1985 struct transform_entry *service = ptr ? LIST_ENTRY(ptr, struct transform_entry, entry) : entry;
1986 IMFMediaTypeHandler *type_handler;
1988 if (enable_advanced)
1990 /* when advanced video processing is enabled, converters are exposed as stream transform service */
1991 stream->transform_service = service->transform;
1992 IMFTransform_AddRef(stream->transform_service);
1994 else
1996 /* when advanced video processing is disabled, only decoders are exposed as stream transform service */
1997 if (IsEqualGUID(&entry->category, &MFT_CATEGORY_AUDIO_DECODER)
1998 || IsEqualGUID(&entry->category, &MFT_CATEGORY_VIDEO_DECODER))
2000 stream->transform_service = entry->transform;
2001 IMFTransform_AddRef(stream->transform_service);
2003 /* converters are hidden from the stream transforms */
2004 if (service != entry)
2005 service->hidden = TRUE;
2007 else
2009 /* converters are hidden from the stream transforms */
2010 entry->hidden = TRUE;
2014 /* move any additional transforms that have been created */
2015 list_move_head(&stream->transforms, &entry->entry);
2016 list_add_head(&stream->transforms, &entry->entry);
2018 if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler)))
2020 if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type)))
2021 WARN("Failed to set current input media type, hr %#lx\n", hr);
2022 IMFMediaTypeHandler_Release(type_handler);
2025 if (FAILED(hr = IMFTransform_GetOutputCurrentType(service->transform, 0, &output_type)))
2026 WARN("Failed to get decoder output media type, hr %#lx\n", hr);
2027 else
2029 IMFMediaType_CopyAllItems(output_type, (IMFAttributes *)stream->current);
2030 IMFMediaType_Release(output_type);
2033 IMFMediaType_Release(input_type);
2034 return S_OK;
2037 IMFMediaType_Release(input_type);
2040 return MF_E_TOPO_CODEC_NOT_FOUND;
2043 static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, DWORD index, DWORD *reserved,
2044 IMFMediaType *type)
2046 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2047 HRESULT hr;
2049 TRACE("%p, %#lx, %p, %p.\n", iface, index, reserved, type);
2051 switch (index)
2053 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2054 index = reader->first_video_stream_index;
2055 break;
2056 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2057 index = reader->first_audio_stream_index;
2058 break;
2059 default:
2063 if (index >= reader->stream_count)
2064 return MF_E_INVALIDSTREAMNUMBER;
2066 /* FIXME: setting the output type while streaming should trigger a flush */
2068 EnterCriticalSection(&reader->cs);
2070 hr = source_reader_set_compatible_media_type(reader, index, type);
2071 if (hr == S_FALSE)
2072 hr = source_reader_create_decoder_for_stream(reader, index, type);
2073 if (SUCCEEDED(hr))
2074 hr = source_reader_setup_sample_allocator(reader, index);
2076 LeaveCriticalSection(&reader->cs);
2078 return hr;
2081 static HRESULT WINAPI src_reader_SetCurrentPosition(IMFSourceReaderEx *iface, REFGUID format, REFPROPVARIANT position)
2083 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2084 struct source_reader_async_command *command;
2085 unsigned int i;
2086 DWORD flags;
2087 HRESULT hr;
2089 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), position);
2091 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
2092 return hr;
2094 if (!(flags & MFMEDIASOURCE_CAN_SEEK))
2095 return MF_E_INVALIDREQUEST;
2097 EnterCriticalSection(&reader->cs);
2099 /* Check if we got pending requests. */
2100 for (i = 0; i < reader->stream_count; ++i)
2102 if (reader->streams[i].requests)
2104 hr = MF_E_INVALIDREQUEST;
2105 break;
2109 if (SUCCEEDED(hr))
2111 for (i = 0; i < reader->stream_count; ++i)
2113 reader->streams[i].last_sample_ts = 0;
2116 if (reader->async_callback)
2118 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK, &command)))
2120 command->u.seek.format = *format;
2121 PropVariantCopy(&command->u.seek.position, position);
2123 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2124 IUnknown_Release(&command->IUnknown_iface);
2127 else
2129 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, format, position)))
2131 reader->flags |= SOURCE_READER_SEEKING;
2132 while (reader->flags & SOURCE_READER_SEEKING)
2134 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
2140 LeaveCriticalSection(&reader->cs);
2142 return hr;
2145 static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD index, DWORD flags, DWORD *actual_index,
2146 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2148 struct media_stream *stream;
2149 DWORD actual_index_tmp;
2150 LONGLONG timestamp_tmp;
2151 DWORD stream_index;
2152 HRESULT hr = S_OK;
2154 if (!stream_flags || !sample)
2155 return E_POINTER;
2157 *sample = NULL;
2159 if (!timestamp)
2160 timestamp = &timestamp_tmp;
2162 if (!actual_index)
2163 actual_index = &actual_index_tmp;
2165 if (SUCCEEDED(hr = source_reader_start_source(reader)))
2167 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, index, &stream_index)))
2169 *actual_index = stream_index;
2171 stream = &reader->streams[stream_index];
2173 if (!source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
2174 timestamp, sample))
2176 while (!source_reader_got_response_for_stream(reader, stream) && stream->state != STREAM_STATE_EOS)
2178 stream->requests++;
2179 if (FAILED(hr = source_reader_request_sample(reader, stream)))
2180 WARN("Failed to request a sample, hr %#lx.\n", hr);
2181 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
2183 *stream_flags = MF_SOURCE_READERF_ERROR;
2184 *timestamp = 0;
2185 break;
2187 SleepConditionVariableCS(&reader->sample_event, &reader->cs, INFINITE);
2189 if (SUCCEEDED(hr))
2190 source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
2191 timestamp, sample);
2194 else
2196 *actual_index = index;
2197 *stream_flags = MF_SOURCE_READERF_ERROR;
2198 *timestamp = 0;
2202 TRACE("Stream %lu, got sample %p, flags %#lx.\n", *actual_index, *sample, *stream_flags);
2204 return hr;
2207 static HRESULT source_reader_read_sample_async(struct source_reader *reader, unsigned int index, unsigned int flags,
2208 DWORD *actual_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2210 struct source_reader_async_command *command;
2211 HRESULT hr;
2213 if (actual_index || stream_flags || timestamp || sample)
2214 return E_INVALIDARG;
2216 if (reader->flags & SOURCE_READER_FLUSHING)
2217 hr = MF_E_NOTACCEPTING;
2218 else
2220 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_READ, &command)))
2222 command->u.read.stream_index = index;
2223 command->u.read.flags = flags;
2225 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2226 IUnknown_Release(&command->IUnknown_iface);
2230 return hr;
2233 static HRESULT WINAPI src_reader_ReadSample(IMFSourceReaderEx *iface, DWORD index, DWORD flags, DWORD *actual_index,
2234 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2236 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2237 HRESULT hr;
2239 TRACE("%p, %#lx, %#lx, %p, %p, %p, %p\n", iface, index, flags, actual_index, stream_flags, timestamp, sample);
2241 EnterCriticalSection(&reader->cs);
2243 while (reader->flags & SOURCE_READER_SEEKING)
2245 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
2248 if (reader->async_callback)
2249 hr = source_reader_read_sample_async(reader, index, flags, actual_index, stream_flags, timestamp, sample);
2250 else
2251 hr = source_reader_read_sample(reader, index, flags, actual_index, stream_flags, timestamp, sample);
2253 LeaveCriticalSection(&reader->cs);
2255 return hr;
2258 static HRESULT source_reader_flush_async(struct source_reader *reader, unsigned int index)
2260 struct source_reader_async_command *command;
2261 unsigned int stream_index;
2262 HRESULT hr;
2264 if (reader->flags & SOURCE_READER_FLUSHING)
2265 return MF_E_INVALIDREQUEST;
2267 switch (index)
2269 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2270 stream_index = reader->first_video_stream_index;
2271 break;
2272 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2273 stream_index = reader->first_audio_stream_index;
2274 break;
2275 default:
2276 stream_index = index;
2279 reader->flags |= SOURCE_READER_FLUSHING;
2281 if (stream_index != MF_SOURCE_READER_ALL_STREAMS && stream_index >= reader->stream_count)
2282 return MF_E_INVALIDSTREAMNUMBER;
2284 if (FAILED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH, &command)))
2285 return hr;
2287 command->u.flush.stream_index = stream_index;
2289 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2290 IUnknown_Release(&command->IUnknown_iface);
2292 return hr;
2295 static HRESULT WINAPI src_reader_Flush(IMFSourceReaderEx *iface, DWORD index)
2297 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2298 HRESULT hr;
2300 TRACE("%p, %#lx.\n", iface, index);
2302 EnterCriticalSection(&reader->cs);
2304 if (reader->async_callback)
2305 hr = source_reader_flush_async(reader, index);
2306 else
2307 hr = source_reader_flush(reader, index);
2309 LeaveCriticalSection(&reader->cs);
2311 return hr;
2314 static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, DWORD index, REFGUID service,
2315 REFIID riid, void **object)
2317 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2318 struct media_stream *stream = &reader->streams[index];
2319 IUnknown *obj = NULL;
2320 HRESULT hr = S_OK;
2322 TRACE("%p, %#lx, %s, %s, %p\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object);
2324 EnterCriticalSection(&reader->cs);
2326 switch (index)
2328 case MF_SOURCE_READER_MEDIASOURCE:
2329 obj = (IUnknown *)reader->source;
2330 break;
2331 default:
2332 if (index == MF_SOURCE_READER_FIRST_VIDEO_STREAM)
2333 index = reader->first_video_stream_index;
2334 else if (index == MF_SOURCE_READER_FIRST_AUDIO_STREAM)
2335 index = reader->first_audio_stream_index;
2337 if (index >= reader->stream_count)
2338 hr = MF_E_INVALIDSTREAMNUMBER;
2339 else if (!(obj = (IUnknown *)stream->transform_service))
2340 hr = E_NOINTERFACE;
2341 break;
2344 if (obj)
2345 IUnknown_AddRef(obj);
2347 LeaveCriticalSection(&reader->cs);
2349 if (obj)
2351 if (IsEqualGUID(service, &GUID_NULL))
2353 hr = IUnknown_QueryInterface(obj, riid, object);
2355 else
2357 IMFGetService *gs;
2359 hr = IUnknown_QueryInterface(obj, &IID_IMFGetService, (void **)&gs);
2360 if (SUCCEEDED(hr))
2362 hr = IMFGetService_GetService(gs, service, riid, object);
2363 IMFGetService_Release(gs);
2368 if (obj)
2369 IUnknown_Release(obj);
2371 return hr;
2374 static HRESULT WINAPI src_reader_GetPresentationAttribute(IMFSourceReaderEx *iface, DWORD index,
2375 REFGUID guid, PROPVARIANT *value)
2377 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2378 IMFStreamDescriptor *sd;
2379 BOOL selected;
2380 HRESULT hr;
2382 TRACE("%p, %#lx, %s, %p.\n", iface, index, debugstr_guid(guid), value);
2384 switch (index)
2386 case MF_SOURCE_READER_MEDIASOURCE:
2387 if (IsEqualGUID(guid, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS))
2389 DWORD flags;
2391 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
2392 return hr;
2394 value->vt = VT_UI4;
2395 value->ulVal = flags;
2396 return S_OK;
2398 else
2400 return IMFPresentationDescriptor_GetItem(reader->descriptor, guid, value);
2402 break;
2403 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2404 index = reader->first_video_stream_index;
2405 break;
2406 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2407 index = reader->first_audio_stream_index;
2408 break;
2409 default:
2413 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
2414 return hr;
2416 hr = IMFStreamDescriptor_GetItem(sd, guid, value);
2417 IMFStreamDescriptor_Release(sd);
2419 return hr;
2422 static HRESULT WINAPI src_reader_SetNativeMediaType(IMFSourceReaderEx *iface, DWORD stream_index,
2423 IMFMediaType *media_type, DWORD *stream_flags)
2425 FIXME("%p, %#lx, %p, %p.\n", iface, stream_index, media_type, stream_flags);
2427 return E_NOTIMPL;
2430 static HRESULT WINAPI src_reader_AddTransformForStream(IMFSourceReaderEx *iface, DWORD stream_index,
2431 IUnknown *transform)
2433 FIXME("%p, %#lx, %p.\n", iface, stream_index, transform);
2435 return E_NOTIMPL;
2438 static HRESULT WINAPI src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx *iface, DWORD stream_index)
2440 FIXME("%p, %#lx.\n", iface, stream_index);
2442 return E_NOTIMPL;
2445 static struct transform_entry *get_transform_at_index(struct media_stream *stream, UINT index)
2447 struct transform_entry *entry;
2449 LIST_FOR_EACH_ENTRY(entry, &stream->transforms, struct transform_entry, entry)
2450 if (!entry->hidden && !index--)
2451 return entry;
2453 return NULL;
2456 static HRESULT WINAPI src_reader_GetTransformForStream(IMFSourceReaderEx *iface, DWORD stream_index,
2457 DWORD transform_index, GUID *category, IMFTransform **transform)
2459 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2460 struct transform_entry *entry;
2461 HRESULT hr;
2463 TRACE("%p, %#lx, %#lx, %p, %p.\n", iface, stream_index, transform_index, category, transform);
2465 EnterCriticalSection(&reader->cs);
2467 if (stream_index == MF_SOURCE_READER_FIRST_VIDEO_STREAM)
2468 stream_index = reader->first_video_stream_index;
2469 else if (stream_index == MF_SOURCE_READER_FIRST_AUDIO_STREAM)
2470 stream_index = reader->first_audio_stream_index;
2472 if (stream_index >= reader->stream_count)
2473 hr = MF_E_INVALIDSTREAMNUMBER;
2474 else if (!(entry = get_transform_at_index(&reader->streams[stream_index], transform_index)))
2475 hr = MF_E_INVALIDINDEX;
2476 else
2478 *category = entry->category;
2479 *transform = entry->transform;
2480 IMFTransform_AddRef(*transform);
2481 hr = S_OK;
2484 LeaveCriticalSection(&reader->cs);
2486 return hr;
2489 static const IMFSourceReaderExVtbl srcreader_vtbl =
2491 src_reader_QueryInterface,
2492 src_reader_AddRef,
2493 src_reader_Release,
2494 src_reader_GetStreamSelection,
2495 src_reader_SetStreamSelection,
2496 src_reader_GetNativeMediaType,
2497 src_reader_GetCurrentMediaType,
2498 src_reader_SetCurrentMediaType,
2499 src_reader_SetCurrentPosition,
2500 src_reader_ReadSample,
2501 src_reader_Flush,
2502 src_reader_GetServiceForStream,
2503 src_reader_GetPresentationAttribute,
2504 src_reader_SetNativeMediaType,
2505 src_reader_AddTransformForStream,
2506 src_reader_RemoveAllTransformsForStream,
2507 src_reader_GetTransformForStream,
2510 static DWORD reader_get_first_stream_index(IMFPresentationDescriptor *descriptor, const GUID *major)
2512 DWORD count, i;
2513 BOOL selected;
2514 HRESULT hr;
2515 GUID guid;
2517 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count)))
2518 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2520 for (i = 0; i < count; ++i)
2522 IMFMediaTypeHandler *handler;
2523 IMFStreamDescriptor *sd;
2525 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i, &selected, &sd)))
2527 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2528 IMFStreamDescriptor_Release(sd);
2529 if (SUCCEEDED(hr))
2531 hr = IMFMediaTypeHandler_GetMajorType(handler, &guid);
2532 IMFMediaTypeHandler_Release(handler);
2533 if (FAILED(hr))
2535 WARN("Failed to get stream major type, hr %#lx.\n", hr);
2536 continue;
2539 if (IsEqualGUID(&guid, major))
2541 return i;
2547 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2550 static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttributes *attributes,
2551 BOOL shutdown_on_release, REFIID riid, void **out)
2553 struct source_reader *object;
2554 unsigned int i;
2555 HRESULT hr;
2557 object = calloc(1, sizeof(*object));
2558 if (!object)
2559 return E_OUTOFMEMORY;
2561 object->IMFSourceReaderEx_iface.lpVtbl = &srcreader_vtbl;
2562 object->source_events_callback.lpVtbl = &source_events_callback_vtbl;
2563 object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl;
2564 object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl;
2565 object->public_refcount = 1;
2566 object->refcount = 1;
2567 list_init(&object->responses);
2568 if (shutdown_on_release)
2569 object->flags |= SOURCE_READER_SHUTDOWN_ON_RELEASE;
2570 object->source = source;
2571 IMFMediaSource_AddRef(object->source);
2572 InitializeCriticalSection(&object->cs);
2573 InitializeConditionVariable(&object->sample_event);
2574 InitializeConditionVariable(&object->state_event);
2575 InitializeConditionVariable(&object->stop_event);
2577 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor)))
2578 goto failed;
2580 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(object->descriptor, &object->stream_count)))
2581 goto failed;
2583 if (!(object->streams = calloc(object->stream_count, sizeof(*object->streams))))
2585 hr = E_OUTOFMEMORY;
2586 goto failed;
2589 /* Set initial current media types. */
2590 for (i = 0; i < object->stream_count; ++i)
2592 IMFMediaTypeHandler *handler;
2593 IMFStreamDescriptor *sd;
2594 IMFMediaType *src_type;
2595 BOOL selected;
2597 list_init(&object->streams[i].transforms);
2599 if (FAILED(hr = MFCreateMediaType(&object->streams[i].current)))
2600 break;
2602 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(object->descriptor, i, &selected, &sd)))
2603 break;
2605 if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &object->streams[i].id)))
2606 WARN("Failed to get stream identifier, hr %#lx.\n", hr);
2608 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2609 IMFStreamDescriptor_Release(sd);
2610 if (FAILED(hr))
2611 break;
2613 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &src_type);
2614 IMFMediaTypeHandler_Release(handler);
2615 if (FAILED(hr))
2616 break;
2618 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)object->streams[i].current);
2619 IMFMediaType_Release(src_type);
2620 if (FAILED(hr))
2621 break;
2623 object->streams[i].reader = object;
2624 object->streams[i].index = i;
2627 if (FAILED(hr))
2628 goto failed;
2630 /* At least one major type has to be set. */
2631 object->first_audio_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Audio);
2632 object->first_video_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Video);
2634 if (object->first_audio_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX &&
2635 object->first_video_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX)
2637 hr = MF_E_ATTRIBUTENOTFOUND;
2640 if (FAILED(hr = IMFMediaSource_BeginGetEvent(object->source, &object->source_events_callback,
2641 (IUnknown *)object->source)))
2643 goto failed;
2646 if (attributes)
2648 object->attributes = attributes;
2649 IMFAttributes_AddRef(object->attributes);
2651 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_ASYNC_CALLBACK, &IID_IMFSourceReaderCallback,
2652 (void **)&object->async_callback);
2653 if (object->async_callback)
2654 TRACE("Using async callback %p.\n", object->async_callback);
2656 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, &IID_IUnknown, (void **)&object->device_manager);
2657 if (object->device_manager)
2659 IUnknown *unk = NULL;
2661 if (SUCCEEDED(IUnknown_QueryInterface(object->device_manager, &IID_IMFDXGIDeviceManager, (void **)&unk)))
2662 object->flags |= SOURCE_READER_DXGI_DEVICE_MANAGER;
2663 else if (SUCCEEDED(IUnknown_QueryInterface(object->device_manager, &IID_IDirect3DDeviceManager9, (void **)&unk)))
2664 object->flags |= SOURCE_READER_D3D9_DEVICE_MANAGER;
2666 if (!(object->flags & (SOURCE_READER_HAS_DEVICE_MANAGER)))
2668 WARN("Unknown device manager.\n");
2669 IUnknown_Release(object->device_manager);
2670 object->device_manager = NULL;
2673 if (unk)
2674 IUnknown_Release(unk);
2678 if (FAILED(hr = MFLockSharedWorkQueue(L"", 0, NULL, &object->queue)))
2679 WARN("Failed to acquired shared queue, hr %#lx.\n", hr);
2681 if (SUCCEEDED(hr))
2682 hr = IMFSourceReaderEx_QueryInterface(&object->IMFSourceReaderEx_iface, riid, out);
2684 failed:
2685 IMFSourceReaderEx_Release(&object->IMFSourceReaderEx_iface);
2686 return hr;
2689 static HRESULT create_source_reader_from_stream(IMFByteStream *stream, IMFAttributes *attributes,
2690 REFIID riid, void **out)
2692 IPropertyStore *props = NULL;
2693 IMFSourceResolver *resolver;
2694 MF_OBJECT_TYPE obj_type;
2695 IMFMediaSource *source;
2696 HRESULT hr;
2698 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2699 return hr;
2701 if (attributes)
2702 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2703 (void **)&props);
2705 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE
2706 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, props, &obj_type, (IUnknown **)&source);
2707 IMFSourceResolver_Release(resolver);
2708 if (props)
2709 IPropertyStore_Release(props);
2710 if (FAILED(hr))
2711 return hr;
2713 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2714 IMFMediaSource_Release(source);
2715 return hr;
2718 static HRESULT create_source_reader_from_url(const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2720 IPropertyStore *props = NULL;
2721 IMFSourceResolver *resolver;
2722 IUnknown *object = NULL;
2723 MF_OBJECT_TYPE obj_type;
2724 IMFMediaSource *source;
2725 HRESULT hr;
2727 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2728 return hr;
2730 if (attributes)
2731 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2732 (void **)&props);
2734 hr = IMFSourceResolver_CreateObjectFromURL(resolver, url, MF_RESOLUTION_MEDIASOURCE, props, &obj_type,
2735 &object);
2736 if (SUCCEEDED(hr))
2738 switch (obj_type)
2740 case MF_OBJECT_BYTESTREAM:
2741 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, (IMFByteStream *)object, NULL,
2742 MF_RESOLUTION_MEDIASOURCE, props, &obj_type, (IUnknown **)&source);
2743 break;
2744 case MF_OBJECT_MEDIASOURCE:
2745 source = (IMFMediaSource *)object;
2746 IMFMediaSource_AddRef(source);
2747 break;
2748 default:
2749 WARN("Unknown object type %d.\n", obj_type);
2750 hr = E_UNEXPECTED;
2752 IUnknown_Release(object);
2755 IMFSourceResolver_Release(resolver);
2756 if (props)
2757 IPropertyStore_Release(props);
2758 if (FAILED(hr))
2759 return hr;
2761 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2762 IMFMediaSource_Release(source);
2763 return hr;
2766 static HRESULT create_source_reader_from_object(IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2768 IMFMediaSource *source = NULL;
2769 IMFByteStream *stream = NULL;
2770 HRESULT hr;
2772 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSource, (void **)&source);
2773 if (FAILED(hr))
2774 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2776 if (source)
2778 UINT32 disconnect = 0;
2780 if (attributes)
2781 IMFAttributes_GetUINT32(attributes, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN, &disconnect);
2782 hr = create_source_reader_from_source(source, attributes, !disconnect, riid, out);
2784 else if (stream)
2785 hr = create_source_reader_from_stream(stream, attributes, riid, out);
2787 if (source)
2788 IMFMediaSource_Release(source);
2789 if (stream)
2790 IMFByteStream_Release(stream);
2792 return hr;
2795 /***********************************************************************
2796 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2798 HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes,
2799 IMFSourceReader **reader)
2801 TRACE("%p, %p, %p.\n", stream, attributes, reader);
2803 return create_source_reader_from_object((IUnknown *)stream, attributes, &IID_IMFSourceReader, (void **)reader);
2806 /***********************************************************************
2807 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2809 HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes,
2810 IMFSourceReader **reader)
2812 TRACE("%p, %p, %p.\n", source, attributes, reader);
2814 return create_source_reader_from_object((IUnknown *)source, attributes, &IID_IMFSourceReader, (void **)reader);
2817 /***********************************************************************
2818 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2820 HRESULT WINAPI MFCreateSourceReaderFromURL(const WCHAR *url, IMFAttributes *attributes, IMFSourceReader **reader)
2822 TRACE("%s, %p, %p.\n", debugstr_w(url), attributes, reader);
2824 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, (void **)reader);
2827 static HRESULT WINAPI readwrite_factory_QueryInterface(IMFReadWriteClassFactory *iface, REFIID riid, void **out)
2829 if (IsEqualIID(riid, &IID_IMFReadWriteClassFactory) ||
2830 IsEqualIID(riid, &IID_IUnknown))
2832 *out = iface;
2833 IMFReadWriteClassFactory_AddRef(iface);
2834 return S_OK;
2837 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
2838 *out = NULL;
2839 return E_NOINTERFACE;
2842 static ULONG WINAPI readwrite_factory_AddRef(IMFReadWriteClassFactory *iface)
2844 return 2;
2847 static ULONG WINAPI readwrite_factory_Release(IMFReadWriteClassFactory *iface)
2849 return 1;
2852 static HRESULT WINAPI readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2853 const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2855 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid), debugstr_w(url), attributes, debugstr_guid(riid), out);
2857 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2859 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, out);
2861 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
2863 return create_sink_writer_from_url(url, NULL, attributes, riid, out);
2866 FIXME("Unsupported %s.\n", debugstr_guid(clsid));
2868 return E_NOTIMPL;
2871 static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2872 IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2874 HRESULT hr;
2876 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid), unk, attributes, debugstr_guid(riid), out);
2878 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2880 return create_source_reader_from_object(unk, attributes, riid, out);
2882 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
2884 IMFByteStream *stream = NULL;
2885 IMFMediaSink *sink = NULL;
2887 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2888 if (FAILED(hr))
2889 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSink, (void **)&sink);
2891 if (stream)
2892 hr = create_sink_writer_from_url(NULL, stream, attributes, riid, out);
2893 else if (sink)
2894 hr = create_sink_writer_from_sink(sink, attributes, riid, out);
2896 if (sink)
2897 IMFMediaSink_Release(sink);
2898 if (stream)
2899 IMFByteStream_Release(stream);
2901 return hr;
2903 else
2905 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2906 *out = NULL;
2907 return E_FAIL;
2911 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl =
2913 readwrite_factory_QueryInterface,
2914 readwrite_factory_AddRef,
2915 readwrite_factory_Release,
2916 readwrite_factory_CreateInstanceFromURL,
2917 readwrite_factory_CreateInstanceFromObject,
2920 static IMFReadWriteClassFactory readwrite_factory = { &readwrite_factory_vtbl };
2922 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
2924 TRACE("%s, %p.\n", debugstr_guid(riid), out);
2926 if (IsEqualGUID(riid, &IID_IClassFactory) ||
2927 IsEqualGUID(riid, &IID_IUnknown))
2929 IClassFactory_AddRef(iface);
2930 *out = iface;
2931 return S_OK;
2934 WARN("interface %s not implemented\n", debugstr_guid(riid));
2935 *out = NULL;
2936 return E_NOINTERFACE;
2939 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
2941 return 2;
2944 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
2946 return 1;
2949 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out)
2951 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), out);
2953 *out = NULL;
2955 if (outer)
2956 return CLASS_E_NOAGGREGATION;
2958 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory, riid, out);
2961 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
2963 FIXME("%d.\n", dolock);
2964 return S_OK;
2967 static const IClassFactoryVtbl classfactoryvtbl =
2969 classfactory_QueryInterface,
2970 classfactory_AddRef,
2971 classfactory_Release,
2972 classfactory_CreateInstance,
2973 classfactory_LockServer,
2976 static IClassFactory classfactory = { &classfactoryvtbl };
2978 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
2980 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), out);
2982 if (IsEqualGUID(clsid, &CLSID_MFReadWriteClassFactory))
2983 return IClassFactory_QueryInterface(&classfactory, riid, out);
2985 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2986 *out = NULL;
2987 return CLASS_E_CLASSNOTAVAILABLE;