include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / mfreadwrite / reader.c
blob28858339d08312a06b58bb330c4338b9be18c7b7
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 DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8);
46 struct stream_response
48 struct list entry;
49 HRESULT status;
50 DWORD stream_index;
51 DWORD stream_flags;
52 LONGLONG timestamp;
53 IMFSample *sample;
56 enum media_stream_state
58 STREAM_STATE_READY = 0,
59 STREAM_STATE_EOS,
62 enum media_source_state
64 SOURCE_STATE_STOPPED = 0,
65 SOURCE_STATE_STARTED,
68 enum media_stream_flags
70 STREAM_FLAG_SAMPLE_REQUESTED = 0x1, /* Protects from making multiple sample requests. */
71 STREAM_FLAG_SELECTED = 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
72 STREAM_FLAG_PRESENTED = 0x4, /* Set if stream was selected last time Start() was called. */
73 STREAM_FLAG_STOPPED = 0x8, /* Received MEStreamStopped */
76 struct transform_entry
78 struct list entry;
79 IMFTransform *transform;
80 unsigned int min_buffer_size;
81 UINT32 pending_flags;
82 GUID category;
83 BOOL hidden;
84 BOOL attributes_initialized;
87 struct media_stream
89 IMFMediaStream *stream;
90 IMFMediaType *current;
91 struct list transforms;
92 IMFVideoSampleAllocatorEx *allocator;
93 IMFTransform *transform_service;
94 DWORD id;
95 unsigned int index;
96 enum media_stream_state state;
97 unsigned int flags;
98 unsigned int requests;
99 unsigned int responses;
100 LONGLONG last_sample_ts;
101 struct source_reader *reader;
104 enum source_reader_async_op
106 SOURCE_READER_ASYNC_READ,
107 SOURCE_READER_ASYNC_SEEK,
108 SOURCE_READER_ASYNC_FLUSH,
109 SOURCE_READER_ASYNC_SAMPLE_READY,
112 struct source_reader_async_command
114 IUnknown IUnknown_iface;
115 LONG refcount;
116 enum source_reader_async_op op;
117 union
119 struct
121 unsigned int flags;
122 unsigned int stream_index;
123 } read;
124 struct
126 GUID format;
127 PROPVARIANT position;
128 } seek;
129 struct
131 unsigned int stream_index;
132 } flush;
133 struct
135 unsigned int stream_index;
136 } sample;
137 struct
139 unsigned int stream_index;
140 } sa;
141 } u;
144 enum source_reader_flags
146 SOURCE_READER_FLUSHING = 0x1,
147 SOURCE_READER_SEEKING = 0x2,
148 SOURCE_READER_SHUTDOWN_ON_RELEASE = 0x4,
149 SOURCE_READER_D3D9_DEVICE_MANAGER = 0x8,
150 SOURCE_READER_DXGI_DEVICE_MANAGER = 0x10,
151 SOURCE_READER_HAS_DEVICE_MANAGER = SOURCE_READER_D3D9_DEVICE_MANAGER | SOURCE_READER_DXGI_DEVICE_MANAGER,
154 struct source_reader
156 IMFSourceReaderEx IMFSourceReaderEx_iface;
157 IMFAsyncCallback source_events_callback;
158 IMFAsyncCallback stream_events_callback;
159 IMFAsyncCallback async_commands_callback;
160 LONG refcount;
161 LONG public_refcount;
162 IMFMediaSource *source;
163 IMFPresentationDescriptor *descriptor;
164 IMFSourceReaderCallback *async_callback;
165 IMFAttributes *attributes;
166 IUnknown *device_manager;
167 unsigned int first_audio_stream_index;
168 unsigned int first_video_stream_index;
169 DWORD stream_count;
170 unsigned int flags;
171 DWORD queue;
172 enum media_source_state source_state;
173 struct media_stream *streams;
174 struct list responses;
175 CRITICAL_SECTION cs;
176 CONDITION_VARIABLE sample_event;
177 CONDITION_VARIABLE state_event;
178 CONDITION_VARIABLE stop_event;
181 static inline struct source_reader *impl_from_IMFSourceReaderEx(IMFSourceReaderEx *iface)
183 return CONTAINING_RECORD(iface, struct source_reader, IMFSourceReaderEx_iface);
186 static struct source_reader *impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
188 return CONTAINING_RECORD(iface, struct source_reader, source_events_callback);
191 static struct source_reader *impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
193 return CONTAINING_RECORD(iface, struct source_reader, stream_events_callback);
196 static struct source_reader *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
198 return CONTAINING_RECORD(iface, struct source_reader, async_commands_callback);
201 static struct source_reader_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
203 return CONTAINING_RECORD(iface, struct source_reader_async_command, IUnknown_iface);
206 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream);
208 static ULONG source_reader_addref(struct source_reader *reader)
210 return InterlockedIncrement(&reader->refcount);
213 static void transform_entry_destroy(struct transform_entry *entry)
215 IMFTransform_Release(entry->transform);
216 free(entry);
219 static void media_stream_destroy(struct media_stream *stream)
221 struct transform_entry *entry, *next;
223 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry)
225 list_remove(&entry->entry);
226 transform_entry_destroy(entry);
229 if (stream->transform_service)
230 IMFTransform_Release(stream->transform_service);
231 if (stream->stream)
232 IMFMediaStream_Release(stream->stream);
233 if (stream->current)
234 IMFMediaType_Release(stream->current);
235 if (stream->allocator)
236 IMFVideoSampleAllocatorEx_Release(stream->allocator);
239 static ULONG source_reader_release(struct source_reader *reader)
241 ULONG refcount = InterlockedDecrement(&reader->refcount);
242 unsigned int i;
244 if (!refcount)
246 if (reader->device_manager)
247 IUnknown_Release(reader->device_manager);
248 if (reader->async_callback)
249 IMFSourceReaderCallback_Release(reader->async_callback);
250 if (reader->descriptor)
251 IMFPresentationDescriptor_Release(reader->descriptor);
252 if (reader->attributes)
253 IMFAttributes_Release(reader->attributes);
254 IMFMediaSource_Release(reader->source);
256 for (i = 0; i < reader->stream_count; ++i)
258 struct media_stream *stream = &reader->streams[i];
259 media_stream_destroy(stream);
261 source_reader_release_responses(reader, NULL);
262 free(reader->streams);
263 DeleteCriticalSection(&reader->cs);
264 free(reader);
267 return refcount;
270 static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
272 if (IsEqualIID(riid, &IID_IUnknown))
274 *obj = iface;
275 IUnknown_AddRef(iface);
276 return S_OK;
279 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
280 *obj = NULL;
281 return E_NOINTERFACE;
284 static ULONG WINAPI source_reader_async_command_AddRef(IUnknown *iface)
286 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
287 return InterlockedIncrement(&command->refcount);
290 static ULONG WINAPI source_reader_async_command_Release(IUnknown *iface)
292 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
293 ULONG refcount = InterlockedIncrement(&command->refcount);
295 if (!refcount)
297 if (command->op == SOURCE_READER_ASYNC_SEEK)
298 PropVariantClear(&command->u.seek.position);
299 free(command);
302 return refcount;
305 static const IUnknownVtbl source_reader_async_command_vtbl =
307 source_reader_async_command_QueryInterface,
308 source_reader_async_command_AddRef,
309 source_reader_async_command_Release,
312 static HRESULT source_reader_create_async_op(enum source_reader_async_op op, struct source_reader_async_command **ret)
314 struct source_reader_async_command *command;
316 if (!(command = calloc(1, sizeof(*command))))
317 return E_OUTOFMEMORY;
319 command->IUnknown_iface.lpVtbl = &source_reader_async_command_vtbl;
320 command->op = op;
322 *ret = command;
324 return S_OK;
327 static HRESULT media_event_get_object(IMFMediaEvent *event, REFIID riid, void **obj)
329 PROPVARIANT value;
330 HRESULT hr;
332 PropVariantInit(&value);
333 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
335 WARN("Failed to get event value, hr %#lx.\n", hr);
336 return hr;
339 if (value.vt != VT_UNKNOWN || !value.punkVal)
341 WARN("Unexpected value type %d.\n", value.vt);
342 PropVariantClear(&value);
343 return E_UNEXPECTED;
346 hr = IUnknown_QueryInterface(value.punkVal, riid, obj);
347 PropVariantClear(&value);
348 if (FAILED(hr))
350 WARN("Unexpected object type.\n");
351 return hr;
354 return hr;
357 static HRESULT media_stream_get_id(IMFMediaStream *stream, DWORD *id)
359 IMFStreamDescriptor *sd;
360 HRESULT hr;
362 if (SUCCEEDED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
364 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, id);
365 IMFStreamDescriptor_Release(sd);
368 return hr;
371 static HRESULT WINAPI source_reader_callback_QueryInterface(IMFAsyncCallback *iface,
372 REFIID riid, void **obj)
374 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
376 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
377 IsEqualIID(riid, &IID_IUnknown))
379 *obj = iface;
380 IMFAsyncCallback_AddRef(iface);
381 return S_OK;
384 WARN("Unsupported %s.\n", debugstr_guid(riid));
385 *obj = NULL;
386 return E_NOINTERFACE;
389 static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface)
391 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
392 return source_reader_addref(reader);
395 static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface)
397 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
398 return source_reader_release(reader);
401 static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface,
402 DWORD *flags, DWORD *queue)
404 return E_NOTIMPL;
407 static void source_reader_response_ready(struct source_reader *reader, struct stream_response *response)
409 struct source_reader_async_command *command;
410 struct media_stream *stream = &reader->streams[response->stream_index];
411 HRESULT hr;
413 if (!stream->requests)
414 return;
416 if (reader->async_callback)
418 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY, &command)))
420 command->u.sample.stream_index = stream->index;
421 if (FAILED(hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface)))
422 WARN("Failed to submit async result, hr %#lx.\n", hr);
423 IUnknown_Release(&command->IUnknown_iface);
426 else
427 WakeAllConditionVariable(&reader->sample_event);
429 stream->requests--;
432 static void source_reader_copy_sample_buffer(IMFSample *src, IMFSample *dst)
434 IMFMediaBuffer *buffer;
435 LONGLONG time;
436 DWORD flags;
437 HRESULT hr;
439 IMFSample_CopyAllItems(src, (IMFAttributes *)dst);
441 IMFSample_SetSampleDuration(dst, 0);
442 IMFSample_SetSampleTime(dst, 0);
443 IMFSample_SetSampleFlags(dst, 0);
445 if (SUCCEEDED(IMFSample_GetSampleDuration(src, &time)))
446 IMFSample_SetSampleDuration(dst, time);
448 if (SUCCEEDED(IMFSample_GetSampleTime(src, &time)))
449 IMFSample_SetSampleTime(dst, time);
451 if (SUCCEEDED(IMFSample_GetSampleFlags(src, &flags)))
452 IMFSample_SetSampleFlags(dst, flags);
454 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src, NULL)))
456 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst, 0, &buffer)))
458 if (FAILED(hr = IMFSample_CopyToBuffer(src, buffer)))
459 WARN("Failed to copy a buffer, hr %#lx.\n", hr);
460 IMFMediaBuffer_Release(buffer);
465 static HRESULT source_reader_queue_response(struct source_reader *reader, struct media_stream *stream, HRESULT status,
466 DWORD stream_flags, LONGLONG timestamp, IMFSample *sample)
468 struct stream_response *response;
470 if (!(response = calloc(1, sizeof(*response))))
471 return E_OUTOFMEMORY;
473 response->status = status;
474 response->stream_index = stream->index;
475 response->stream_flags = stream_flags;
476 response->timestamp = timestamp;
477 response->sample = sample;
478 if (response->sample)
479 IMFSample_AddRef(response->sample);
481 list_add_tail(&reader->responses, &response->entry);
482 stream->responses++;
484 source_reader_response_ready(reader, response);
486 stream->last_sample_ts = timestamp;
488 return S_OK;
491 static HRESULT source_reader_queue_sample(struct source_reader *reader, struct media_stream *stream,
492 UINT flags, IMFSample *sample)
494 LONGLONG timestamp = 0;
496 if (FAILED(IMFSample_GetSampleTime(sample, &timestamp)))
497 WARN("Sample time wasn't set.\n");
499 return source_reader_queue_response(reader, stream, S_OK, flags, timestamp, sample);
502 static HRESULT source_reader_request_sample(struct source_reader *reader, struct media_stream *stream)
504 HRESULT hr = S_OK;
506 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
508 if (FAILED(hr = IMFMediaStream_RequestSample(stream->stream, NULL)))
509 WARN("Sample request failed, hr %#lx.\n", hr);
510 else
512 stream->flags |= STREAM_FLAG_SAMPLE_REQUESTED;
516 return hr;
519 static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IMFMediaEvent *event)
521 IMFMediaStream *stream;
522 unsigned int i;
523 DWORD id = 0;
524 HRESULT hr;
526 if (FAILED(hr = media_event_get_object(event, &IID_IMFMediaStream, (void **)&stream)))
528 WARN("Failed to get stream object, hr %#lx.\n", hr);
529 return hr;
532 TRACE("Got new stream %p.\n", stream);
534 if (FAILED(hr = media_stream_get_id(stream, &id)))
536 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
537 IMFMediaStream_Release(stream);
538 return hr;
541 EnterCriticalSection(&reader->cs);
543 for (i = 0; i < reader->stream_count; ++i)
545 if (id == reader->streams[i].id)
547 if (!reader->streams[i].stream)
549 reader->streams[i].stream = stream;
550 IMFMediaStream_AddRef(reader->streams[i].stream);
551 if (FAILED(hr = IMFMediaStream_BeginGetEvent(stream, &reader->stream_events_callback,
552 (IUnknown *)stream)))
554 WARN("Failed to subscribe to stream events, hr %#lx.\n", hr);
557 if (reader->streams[i].requests)
558 if (FAILED(source_reader_request_sample(reader, &reader->streams[i])))
559 WakeAllConditionVariable(&reader->sample_event);
561 break;
565 if (i == reader->stream_count)
566 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id);
568 LeaveCriticalSection(&reader->cs);
570 IMFMediaStream_Release(stream);
572 return hr;
575 static HRESULT source_reader_source_state_handler(struct source_reader *reader, MediaEventType event_type)
577 EnterCriticalSection(&reader->cs);
579 switch (event_type)
581 case MESourceStarted:
582 reader->source_state = SOURCE_STATE_STARTED;
583 reader->flags &= ~SOURCE_READER_SEEKING;
584 break;
585 case MESourceStopped:
586 reader->source_state = SOURCE_STATE_STOPPED;
587 reader->flags &= ~SOURCE_READER_SEEKING;
588 break;
589 case MESourceSeeked:
590 reader->flags &= ~SOURCE_READER_SEEKING;
591 break;
592 default:
593 WARN("Unhandled event %ld.\n", event_type);
596 LeaveCriticalSection(&reader->cs);
598 WakeAllConditionVariable(&reader->state_event);
599 if (event_type == MESourceStopped)
600 WakeAllConditionVariable(&reader->stop_event);
602 return S_OK;
605 static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
607 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
608 MediaEventType event_type;
609 IMFMediaSource *source;
610 IMFMediaEvent *event;
611 HRESULT hr;
613 TRACE("%p, %p.\n", iface, result);
615 source = (IMFMediaSource *)IMFAsyncResult_GetStateNoAddRef(result);
617 if (FAILED(hr = IMFMediaSource_EndGetEvent(source, result, &event)))
618 return hr;
620 IMFMediaEvent_GetType(event, &event_type);
622 TRACE("Got event %lu.\n", event_type);
624 switch (event_type)
626 case MENewStream:
627 hr = source_reader_new_stream_handler(reader, event);
628 break;
629 case MESourceStarted:
630 case MESourcePaused:
631 case MESourceStopped:
632 case MESourceSeeked:
633 hr = source_reader_source_state_handler(reader, event_type);
634 break;
635 case MEBufferingStarted:
636 case MEBufferingStopped:
637 case MEConnectStart:
638 case MEConnectEnd:
639 case MEExtendedType:
640 case MESourceCharacteristicsChanged:
641 case MESourceMetadataChanged:
642 case MEContentProtectionMetadata:
643 case MEDeviceThermalStateChanged:
644 if (reader->async_callback)
645 IMFSourceReaderCallback_OnEvent(reader->async_callback, MF_SOURCE_READER_MEDIASOURCE, event);
646 break;
647 default:
651 if (FAILED(hr))
652 WARN("Failed while handling %ld event, hr %#lx.\n", event_type, hr);
654 IMFMediaEvent_Release(event);
656 if (event_type != MESourceStopped)
657 IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
659 return S_OK;
662 static const IMFAsyncCallbackVtbl source_events_callback_vtbl =
664 source_reader_callback_QueryInterface,
665 source_reader_source_events_callback_AddRef,
666 source_reader_source_events_callback_Release,
667 source_reader_callback_GetParameters,
668 source_reader_source_events_callback_Invoke,
671 static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface)
673 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
674 return source_reader_addref(reader);
677 static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface)
679 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
680 return source_reader_release(reader);
683 static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info, IMFSample **out)
685 IMFMediaBuffer *buffer;
686 IMFSample *sample;
687 HRESULT hr;
689 *out = NULL;
690 if (FAILED(hr = MFCreateSample(&sample)))
691 return hr;
692 if (SUCCEEDED(hr = MFCreateAlignedMemoryBuffer(info->cbSize, info->cbAlignment, &buffer)))
694 if (SUCCEEDED(hr = IMFSample_AddBuffer(sample, buffer)))
696 *out = sample;
697 IMFSample_AddRef(sample);
699 IMFMediaBuffer_Release(buffer);
702 IMFSample_Release(sample);
703 return hr;
706 static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const GUID *attr, HRESULT *hr)
708 PROPVARIANT value;
710 PropVariantInit(&value);
711 if (SUCCEEDED(*hr) && FAILED(IMFMediaType_GetItem(dst, attr, NULL))
712 && SUCCEEDED(IMFMediaType_GetItem(src, attr, &value)))
713 *hr = IMFMediaType_SetItem(dst, attr, &value);
714 PropVariantClear(&value);
717 /* update a media type with additional attributes reported by upstream element */
718 /* also present in mf/topology_loader.c pipeline */
719 static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type)
721 HRESULT hr = S_OK;
723 /* propagate common video attributes */
724 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_SIZE, &hr);
725 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_RATE, &hr);
726 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_DEFAULT_STRIDE, &hr);
727 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_ROTATION, &hr);
728 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FIXED_SIZE_SAMPLES, &hr);
729 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_PIXEL_ASPECT_RATIO, &hr);
730 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &hr);
731 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &hr);
733 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_CHROMA_SITING, &hr);
734 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_INTERLACE_MODE, &hr);
735 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_TRANSFER_FUNCTION, &hr);
736 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_PRIMARIES, &hr);
737 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_YUV_MATRIX, &hr);
738 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_LIGHTING, &hr);
739 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_NOMINAL_RANGE, &hr);
741 /* propagate common audio attributes */
742 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_NUM_CHANNELS, &hr);
743 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &hr);
744 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &hr);
745 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &hr);
746 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &hr);
747 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_CHANNEL_MASK, &hr);
748 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &hr);
749 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &hr);
751 return hr;
754 static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream,
755 struct transform_entry *entry);
756 static HRESULT source_reader_push_transform_samples(struct source_reader *reader, struct media_stream *stream,
757 struct transform_entry *entry, IMFSample *sample)
759 HRESULT hr;
763 if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry))
764 && hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
765 return hr;
766 if (SUCCEEDED(hr = IMFTransform_ProcessInput(entry->transform, 0, sample, 0)))
767 return source_reader_pull_transform_samples(reader, stream, entry);
769 while (hr == MF_E_NOTACCEPTING);
771 return hr;
774 /* update the transform output type while keeping subtype which matches the desired type */
775 static HRESULT set_matching_transform_output_type(IMFTransform *transform, IMFMediaType *old_output_type)
777 IMFMediaType *new_output_type;
778 GUID subtype, desired;
779 UINT i = 0;
780 HRESULT hr;
782 IMFMediaType_GetGUID(old_output_type, &MF_MT_SUBTYPE, &desired);
784 /* find an available output type matching the desired subtype */
785 while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, i++, &new_output_type)))
787 IMFMediaType_GetGUID(new_output_type, &MF_MT_SUBTYPE, &subtype);
788 if (IsEqualGUID(&subtype, &desired) && SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, new_output_type, 0)))
790 IMFMediaType_Release(new_output_type);
791 return S_OK;
793 IMFMediaType_Release(new_output_type);
796 return hr;
799 /* update the transform output type while keeping subtype which matches the old output type */
800 static HRESULT transform_entry_update_output_type(struct transform_entry *entry, IMFMediaType *old_output_type)
802 HRESULT hr;
804 if (SUCCEEDED(hr = set_matching_transform_output_type(entry->transform, old_output_type)))
805 entry->pending_flags |= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED;
807 return hr;
810 /* update the transform input type while keeping an output type which matches the current output subtype */
811 static HRESULT transform_entry_update_input_type(struct transform_entry *entry, IMFMediaType *input_type)
813 IMFMediaType *old_output_type, *new_output_type;
814 HRESULT hr;
816 if (FAILED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &old_output_type)))
817 return hr;
818 if (FAILED(hr = IMFTransform_SetInputType(entry->transform, 0, input_type, 0)))
819 return hr;
821 /* check if transform output type is still valid or if we need to update it as well */
822 if (FAILED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &new_output_type)))
823 hr = transform_entry_update_output_type(entry, old_output_type);
824 else
825 IMFMediaType_Release(new_output_type);
827 IMFMediaType_Release(old_output_type);
828 return hr;
831 static void transform_entry_initialize_attributes(struct source_reader *reader, struct transform_entry *entry)
833 IMFAttributes *attributes;
835 if (SUCCEEDED(IMFTransform_GetAttributes(entry->transform, &attributes)))
837 if (FAILED(IMFAttributes_GetItem(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, NULL)))
838 IMFAttributes_SetUINT32(attributes, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, 6);
840 IMFAttributes_Release(attributes);
843 if (SUCCEEDED(IMFTransform_GetOutputStreamAttributes(entry->transform, 0, &attributes)))
845 UINT32 shared, shared_without_mutex, bind_flags;
847 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared)))
848 IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_SHARED, shared);
849 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex)))
850 IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, shared_without_mutex);
851 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_D3D11_BIND_FLAGS, &bind_flags)))
852 IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, bind_flags);
853 else if ((reader->flags & SOURCE_READER_DXGI_DEVICE_MANAGER) && FAILED(IMFAttributes_GetItem(attributes, &MF_SA_D3D11_BINDFLAGS, NULL)))
854 IMFAttributes_SetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, 1024);
856 IMFAttributes_Release(attributes);
860 static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream,
861 struct transform_entry *entry)
863 MFT_OUTPUT_STREAM_INFO stream_info = {0};
864 struct transform_entry *next = NULL;
865 struct list *ptr;
866 DWORD status;
867 HRESULT hr;
869 if ((ptr = list_next(&stream->transforms, &entry->entry)))
870 next = LIST_ENTRY(ptr, struct transform_entry, entry);
872 if (!entry->attributes_initialized)
874 transform_entry_initialize_attributes(reader, entry);
875 entry->attributes_initialized = TRUE;
878 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info)))
879 return hr;
880 stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size);
882 while (SUCCEEDED(hr))
884 MFT_OUTPUT_DATA_BUFFER out_buffer = {0};
885 IMFMediaType *media_type;
887 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES))
888 && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample)))
889 break;
891 if (SUCCEEDED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status)))
893 /* propagate upstream type to the transform input type */
894 if ((entry->pending_flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
895 && SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &media_type)))
897 if (!next)
898 hr = IMFMediaType_CopyAllItems(media_type, (IMFAttributes *)stream->current);
899 else
900 hr = transform_entry_update_input_type(next, media_type);
901 IMFMediaType_Release(media_type);
904 if (FAILED(hr))
905 source_reader_queue_response(reader, stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL);
906 else if (next)
907 hr = source_reader_push_transform_samples(reader, stream, next, out_buffer.pSample);
908 else
909 hr = source_reader_queue_sample(reader, stream, entry->pending_flags, out_buffer.pSample);
911 entry->pending_flags = 0;
914 if (hr == MF_E_TRANSFORM_STREAM_CHANGE && SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &media_type)))
916 hr = transform_entry_update_output_type(entry, media_type);
917 IMFMediaType_Release(media_type);
919 if (SUCCEEDED(hr))
921 hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info);
922 stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size);
926 if (out_buffer.pSample)
927 IMFSample_Release(out_buffer.pSample);
928 if (out_buffer.pEvents)
929 IMFCollection_Release(out_buffer.pEvents);
932 return hr;
935 static HRESULT source_reader_drain_transform_samples(struct source_reader *reader, struct media_stream *stream,
936 struct transform_entry *entry)
938 struct transform_entry *next = NULL;
939 struct list *ptr;
940 HRESULT hr;
942 if ((ptr = list_next(&stream->transforms, &entry->entry)))
943 next = LIST_ENTRY(ptr, struct transform_entry, entry);
945 if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
946 WARN("Failed to drain transform %p, hr %#lx\n", entry->transform, hr);
947 if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry))
948 && hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
949 WARN("Failed to pull pending samples, hr %#lx.\n", hr);
951 return next ? source_reader_drain_transform_samples(reader, stream, next) : S_OK;
954 static HRESULT source_reader_flush_transform_samples(struct source_reader *reader, struct media_stream *stream,
955 struct transform_entry *entry)
957 struct transform_entry *next = NULL;
958 struct list *ptr;
959 HRESULT hr;
961 if ((ptr = list_next(&stream->transforms, &entry->entry)))
962 next = LIST_ENTRY(ptr, struct transform_entry, entry);
964 if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_FLUSH, 0)))
965 WARN("Failed to flush transform %p, hr %#lx\n", entry->transform, hr);
967 return next ? source_reader_flush_transform_samples(reader, stream, next) : S_OK;
970 static HRESULT source_reader_notify_transform(struct source_reader *reader, struct media_stream *stream,
971 struct transform_entry *entry, UINT message)
973 struct transform_entry *next = NULL;
974 struct list *ptr;
975 HRESULT hr;
977 if ((ptr = list_next(&stream->transforms, &entry->entry)))
978 next = LIST_ENTRY(ptr, struct transform_entry, entry);
980 if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, message, 0)))
981 WARN("Failed to notify transform %p message %#x, hr %#lx\n", entry->transform, message, hr);
983 return next ? source_reader_notify_transform(reader, stream, next, message) : S_OK;
986 static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream,
987 IMFSample *sample)
989 struct transform_entry *entry;
990 struct list *ptr;
991 HRESULT hr;
993 if (!(ptr = list_head(&stream->transforms)))
994 return source_reader_queue_sample(reader, stream, 0, sample);
995 entry = LIST_ENTRY(ptr, struct transform_entry, entry);
997 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
998 if (SUCCEEDED(hr = source_reader_push_transform_samples(reader, stream, entry, sample))
999 || hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
1000 hr = stream->requests ? source_reader_request_sample(reader, stream) : S_OK;
1001 else
1002 WARN("Transform failed to process output, hr %#lx.\n", hr);
1004 return hr;
1007 static HRESULT source_reader_media_sample_handler(struct source_reader *reader, IMFMediaStream *stream,
1008 IMFMediaEvent *event)
1010 IMFSample *sample;
1011 unsigned int i;
1012 DWORD id = 0;
1013 HRESULT hr;
1015 TRACE("Got new sample for stream %p.\n", stream);
1017 if (FAILED(hr = media_event_get_object(event, &IID_IMFSample, (void **)&sample)))
1019 WARN("Failed to get sample object, hr %#lx.\n", hr);
1020 return hr;
1023 if (FAILED(hr = media_stream_get_id(stream, &id)))
1025 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
1026 IMFSample_Release(sample);
1027 return hr;
1030 EnterCriticalSection(&reader->cs);
1032 for (i = 0; i < reader->stream_count; ++i)
1034 if (id == reader->streams[i].id)
1036 /* FIXME: propagate processing errors? */
1037 reader->streams[i].flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
1038 hr = source_reader_process_sample(reader, &reader->streams[i], sample);
1039 break;
1043 if (i == reader->stream_count)
1044 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id);
1046 LeaveCriticalSection(&reader->cs);
1048 IMFSample_Release(sample);
1050 return hr;
1053 static HRESULT source_reader_media_stream_state_handler(struct source_reader *reader, IMFMediaStream *stream,
1054 IMFMediaEvent *event)
1056 MediaEventType event_type;
1057 LONGLONG timestamp;
1058 PROPVARIANT value;
1059 struct list *ptr;
1060 unsigned int i;
1061 HRESULT hr;
1062 DWORD id;
1064 IMFMediaEvent_GetType(event, &event_type);
1066 if (FAILED(hr = media_stream_get_id(stream, &id)))
1068 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
1069 return hr;
1072 EnterCriticalSection(&reader->cs);
1074 for (i = 0; i < reader->stream_count; ++i)
1076 struct media_stream *stream = &reader->streams[i];
1078 if (id == stream->id)
1080 switch (event_type)
1082 case MEEndOfStream:
1083 stream->state = STREAM_STATE_EOS;
1084 stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
1086 if ((ptr = list_head(&stream->transforms)))
1088 struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry);
1089 if (FAILED(hr = source_reader_drain_transform_samples(reader, stream, entry)))
1090 WARN("Failed to drain pending samples, hr %#lx.\n", hr);
1093 while (stream->requests)
1094 source_reader_queue_response(reader, stream, S_OK, MF_SOURCE_READERF_ENDOFSTREAM, 0, NULL);
1096 break;
1097 case MEStreamSeeked:
1098 case MEStreamStarted:
1099 stream->state = STREAM_STATE_READY;
1101 if ((ptr = list_head(&stream->transforms)))
1103 struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry);
1104 if (FAILED(hr = source_reader_notify_transform(reader, stream, entry, MFT_MESSAGE_NOTIFY_START_OF_STREAM)))
1105 WARN("Failed to notify transforms of stream start, hr %#lx.\n", hr);
1107 break;
1108 case MEStreamStopped:
1109 stream->flags |= STREAM_FLAG_STOPPED;
1110 break;
1111 case MEStreamTick:
1112 value.vt = VT_EMPTY;
1113 hr = SUCCEEDED(IMFMediaEvent_GetValue(event, &value)) && value.vt == VT_I8 ? S_OK : E_UNEXPECTED;
1114 timestamp = SUCCEEDED(hr) ? value.hVal.QuadPart : 0;
1115 PropVariantClear(&value);
1117 source_reader_queue_response(reader, stream, hr, MF_SOURCE_READERF_STREAMTICK, timestamp, NULL);
1119 break;
1120 default:
1124 break;
1128 LeaveCriticalSection(&reader->cs);
1130 if (event_type == MEStreamStopped)
1131 WakeAllConditionVariable(&reader->stop_event);
1133 return S_OK;
1136 static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1138 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
1139 MediaEventType event_type;
1140 IMFMediaStream *stream;
1141 IMFMediaEvent *event;
1142 HRESULT hr;
1144 TRACE("%p, %p.\n", iface, result);
1146 stream = (IMFMediaStream *)IMFAsyncResult_GetStateNoAddRef(result);
1148 if (FAILED(hr = IMFMediaStream_EndGetEvent(stream, result, &event)))
1149 return hr;
1151 IMFMediaEvent_GetType(event, &event_type);
1153 TRACE("Got event %lu.\n", event_type);
1155 switch (event_type)
1157 case MEMediaSample:
1158 hr = source_reader_media_sample_handler(reader, stream, event);
1159 break;
1160 case MEStreamSeeked:
1161 case MEStreamStarted:
1162 case MEStreamStopped:
1163 case MEStreamTick:
1164 case MEEndOfStream:
1165 hr = source_reader_media_stream_state_handler(reader, stream, event);
1166 break;
1167 default:
1171 if (FAILED(hr))
1172 WARN("Failed while handling %ld event, hr %#lx.\n", event_type, hr);
1174 IMFMediaEvent_Release(event);
1176 if (event_type != MEStreamStopped)
1177 IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
1179 return S_OK;
1182 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl =
1184 source_reader_callback_QueryInterface,
1185 source_reader_stream_events_callback_AddRef,
1186 source_reader_stream_events_callback_Release,
1187 source_reader_callback_GetParameters,
1188 source_reader_stream_events_callback_Invoke,
1191 static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface)
1193 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1194 return source_reader_addref(reader);
1197 static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface)
1199 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1200 return source_reader_release(reader);
1203 static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response)
1205 struct media_stream *stream;
1207 list_remove(&response->entry);
1209 if (response->stream_index < reader->stream_count)
1211 stream = &reader->streams[response->stream_index];
1212 if (stream->responses)
1213 --stream->responses;
1216 return response;
1219 static struct stream_response *media_stream_pop_response(struct source_reader *reader, struct media_stream *stream)
1221 struct stream_response *response;
1222 IMFSample *sample;
1223 HRESULT hr;
1225 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
1227 if (stream && response->stream_index != stream->index)
1228 continue;
1230 if (!stream) stream = &reader->streams[response->stream_index];
1232 if (response->sample && stream->allocator)
1234 /* Return allocation error to the caller, while keeping original response sample in for later. */
1235 if (SUCCEEDED(hr = IMFVideoSampleAllocatorEx_AllocateSample(stream->allocator, &sample)))
1237 source_reader_copy_sample_buffer(response->sample, sample);
1238 IMFSample_Release(response->sample);
1239 response->sample = sample;
1241 else
1243 if (!(response = calloc(1, sizeof(*response))))
1244 return NULL;
1246 response->status = hr;
1247 response->stream_flags = MF_SOURCE_READERF_ERROR;
1248 return response;
1252 return media_stream_detach_response(reader, response);
1255 return NULL;
1258 static void source_reader_release_response(struct stream_response *response)
1260 if (response->sample)
1261 IMFSample_Release(response->sample);
1262 free(response);
1265 static HRESULT source_reader_get_stream_selection(const struct source_reader *reader, DWORD index, BOOL *selected)
1267 IMFStreamDescriptor *sd;
1269 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, selected, &sd)))
1270 return MF_E_INVALIDSTREAMNUMBER;
1271 IMFStreamDescriptor_Release(sd);
1273 return S_OK;
1276 static HRESULT source_reader_start_source(struct source_reader *reader)
1278 BOOL selected, selection_changed = FALSE;
1279 PROPVARIANT position;
1280 HRESULT hr = S_OK;
1281 unsigned int i;
1283 for (i = 0; i < reader->stream_count; ++i)
1285 source_reader_get_stream_selection(reader, i, &selected);
1286 if (selected)
1287 reader->streams[i].flags |= STREAM_FLAG_SELECTED;
1288 else
1289 reader->streams[i].flags &= ~STREAM_FLAG_SELECTED;
1292 if (reader->source_state == SOURCE_STATE_STARTED)
1294 for (i = 0; i < reader->stream_count; ++i)
1296 selection_changed = !!(reader->streams[i].flags & STREAM_FLAG_SELECTED) ^
1297 !!(reader->streams[i].flags & STREAM_FLAG_PRESENTED);
1298 if (selection_changed)
1299 break;
1303 position.hVal.QuadPart = 0;
1304 if (reader->source_state != SOURCE_STATE_STARTED || selection_changed)
1306 position.vt = reader->source_state == SOURCE_STATE_STARTED ? VT_EMPTY : VT_I8;
1308 /* Update cached stream selection if descriptor was accepted. */
1309 if (SUCCEEDED(hr = IMFMediaSource_Start(reader->source, reader->descriptor, &GUID_NULL, &position)))
1311 for (i = 0; i < reader->stream_count; ++i)
1313 if (reader->streams[i].flags & STREAM_FLAG_SELECTED)
1314 reader->streams[i].flags |= STREAM_FLAG_PRESENTED;
1319 return hr;
1322 static BOOL source_reader_got_response_for_stream(struct source_reader *reader, struct media_stream *stream)
1324 struct stream_response *response;
1326 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
1328 if (response->stream_index == stream->index)
1329 return TRUE;
1332 return FALSE;
1335 static BOOL source_reader_get_read_result(struct source_reader *reader, struct media_stream *stream, DWORD flags,
1336 HRESULT *status, DWORD *stream_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1338 struct stream_response *response = NULL;
1339 BOOL request_sample = FALSE;
1341 if ((response = media_stream_pop_response(reader, stream)))
1343 *status = response->status;
1344 *stream_index = stream->index;
1345 *stream_flags = response->stream_flags;
1346 *timestamp = response->timestamp;
1347 *sample = response->sample;
1348 if (*sample)
1349 IMFSample_AddRef(*sample);
1351 source_reader_release_response(response);
1353 else
1355 *status = S_OK;
1356 *stream_index = stream->index;
1357 *timestamp = 0;
1358 *sample = NULL;
1360 if (stream->state == STREAM_STATE_EOS)
1362 *stream_flags = MF_SOURCE_READERF_ENDOFSTREAM;
1364 else
1366 request_sample = !(flags & MF_SOURCE_READER_CONTROLF_DRAIN);
1367 *stream_flags = 0;
1371 return !request_sample;
1374 static HRESULT source_reader_get_next_selected_stream(struct source_reader *reader, DWORD *stream_index)
1376 unsigned int i, first_selected = ~0u;
1377 BOOL selected, stream_drained;
1378 LONGLONG min_ts = MAXLONGLONG;
1380 for (i = 0; i < reader->stream_count; ++i)
1382 stream_drained = reader->streams[i].state == STREAM_STATE_EOS && !reader->streams[i].responses;
1383 selected = SUCCEEDED(source_reader_get_stream_selection(reader, i, &selected)) && selected;
1385 if (selected)
1387 if (first_selected == ~0u)
1388 first_selected = i;
1390 /* Pick the stream whose last sample had the lowest timestamp. */
1391 if (!stream_drained && reader->streams[i].last_sample_ts < min_ts)
1393 min_ts = reader->streams[i].last_sample_ts;
1394 *stream_index = i;
1399 /* If all selected streams reached EOS, use first selected. */
1400 if (first_selected != ~0u)
1402 if (min_ts == MAXLONGLONG)
1403 *stream_index = first_selected;
1406 return first_selected == ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED : S_OK;
1409 static HRESULT source_reader_get_stream_read_index(struct source_reader *reader, unsigned int index, DWORD *stream_index)
1411 BOOL selected;
1412 HRESULT hr;
1414 switch (index)
1416 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1417 *stream_index = reader->first_video_stream_index;
1418 break;
1419 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1420 *stream_index = reader->first_audio_stream_index;
1421 break;
1422 case MF_SOURCE_READER_ANY_STREAM:
1423 return source_reader_get_next_selected_stream(reader, stream_index);
1424 default:
1425 *stream_index = index;
1428 /* Can't read from deselected streams. */
1429 if (SUCCEEDED(hr = source_reader_get_stream_selection(reader, *stream_index, &selected)) && !selected)
1430 hr = MF_E_INVALIDREQUEST;
1432 return hr;
1435 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream)
1437 struct stream_response *ptr, *next;
1439 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &reader->responses, struct stream_response, entry)
1441 if (stream && stream->index != ptr->stream_index &&
1442 ptr->stream_index != MF_SOURCE_READER_FIRST_VIDEO_STREAM &&
1443 ptr->stream_index != MF_SOURCE_READER_FIRST_AUDIO_STREAM &&
1444 ptr->stream_index != MF_SOURCE_READER_ANY_STREAM)
1446 continue;
1448 media_stream_detach_response(reader, ptr);
1449 source_reader_release_response(ptr);
1453 static void source_reader_flush_stream(struct source_reader *reader, DWORD stream_index)
1455 struct media_stream *stream = &reader->streams[stream_index];
1456 struct list *ptr;
1457 HRESULT hr;
1459 source_reader_release_responses(reader, stream);
1461 if ((ptr = list_head(&stream->transforms)))
1463 struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry);
1464 if (FAILED(hr = source_reader_flush_transform_samples(reader, stream, entry)))
1465 WARN("Failed to drain pending samples, hr %#lx.\n", hr);
1468 stream->requests = 0;
1471 static HRESULT source_reader_flush(struct source_reader *reader, unsigned int index)
1473 unsigned int stream_index;
1474 HRESULT hr = S_OK;
1476 if (index == MF_SOURCE_READER_ALL_STREAMS)
1478 for (stream_index = 0; stream_index < reader->stream_count; ++stream_index)
1479 source_reader_flush_stream(reader, stream_index);
1481 else
1483 switch (index)
1485 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1486 stream_index = reader->first_video_stream_index;
1487 break;
1488 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1489 stream_index = reader->first_audio_stream_index;
1490 break;
1491 default:
1492 stream_index = index;
1495 if (stream_index < reader->stream_count)
1496 source_reader_flush_stream(reader, stream_index);
1497 else
1498 hr = MF_E_INVALIDSTREAMNUMBER;
1501 return hr;
1504 static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1506 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1507 struct media_stream *stream, stub_stream = { .requests = 1 };
1508 struct source_reader_async_command *command;
1509 struct stream_response *response;
1510 DWORD stream_index, stream_flags;
1511 BOOL report_sample = FALSE;
1512 IMFSample *sample = NULL;
1513 LONGLONG timestamp = 0;
1514 HRESULT hr, status;
1515 IUnknown *state;
1517 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
1518 return hr;
1520 command = impl_from_async_command_IUnknown(state);
1522 switch (command->op)
1524 case SOURCE_READER_ASYNC_READ:
1525 EnterCriticalSection(&reader->cs);
1527 if (SUCCEEDED(hr = source_reader_start_source(reader)))
1529 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, command->u.read.stream_index, &stream_index)))
1531 stream = &reader->streams[stream_index];
1533 if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status,
1534 &stream_index, &stream_flags, &timestamp, &sample)))
1536 stream->requests++;
1537 source_reader_request_sample(reader, stream);
1538 /* FIXME: set error stream/reader state on request failure */
1541 else
1543 stub_stream.index = command->u.read.stream_index;
1544 source_reader_queue_response(reader, &stub_stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL);
1548 LeaveCriticalSection(&reader->cs);
1550 if (report_sample)
1551 IMFSourceReaderCallback_OnReadSample(reader->async_callback, status, stream_index, stream_flags,
1552 timestamp, sample);
1554 if (sample)
1555 IMFSample_Release(sample);
1557 break;
1559 case SOURCE_READER_ASYNC_SEEK:
1561 EnterCriticalSection(&reader->cs);
1562 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, &command->u.seek.format,
1563 &command->u.seek.position)))
1565 reader->flags |= SOURCE_READER_SEEKING;
1567 LeaveCriticalSection(&reader->cs);
1569 break;
1571 case SOURCE_READER_ASYNC_SAMPLE_READY:
1573 EnterCriticalSection(&reader->cs);
1574 response = media_stream_pop_response(reader, NULL);
1575 LeaveCriticalSection(&reader->cs);
1577 if (response)
1579 IMFSourceReaderCallback_OnReadSample(reader->async_callback, response->status, response->stream_index,
1580 response->stream_flags, response->timestamp, response->sample);
1581 source_reader_release_response(response);
1584 break;
1585 case SOURCE_READER_ASYNC_FLUSH:
1586 EnterCriticalSection(&reader->cs);
1587 source_reader_flush(reader, command->u.flush.stream_index);
1588 reader->flags &= ~SOURCE_READER_FLUSHING;
1589 LeaveCriticalSection(&reader->cs);
1591 IMFSourceReaderCallback_OnFlush(reader->async_callback, command->u.flush.stream_index);
1592 break;
1593 default:
1597 IUnknown_Release(state);
1599 return S_OK;
1602 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl =
1604 source_reader_callback_QueryInterface,
1605 source_reader_async_commands_callback_AddRef,
1606 source_reader_async_commands_callback_Release,
1607 source_reader_callback_GetParameters,
1608 source_reader_async_commands_callback_Invoke,
1611 static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReaderEx *iface, REFIID riid, void **out)
1613 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1615 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1617 if (IsEqualGUID(riid, &IID_IUnknown)
1618 || IsEqualGUID(riid, &IID_IMFSourceReader)
1619 || IsEqualGUID(riid, &IID_IMFSourceReaderEx))
1621 *out = &reader->IMFSourceReaderEx_iface;
1623 else
1625 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
1626 *out = NULL;
1627 return E_NOINTERFACE;
1630 IUnknown_AddRef((IUnknown*)*out);
1631 return S_OK;
1634 static ULONG WINAPI src_reader_AddRef(IMFSourceReaderEx *iface)
1636 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1637 ULONG refcount = InterlockedIncrement(&reader->public_refcount);
1639 TRACE("%p, refcount %lu.\n", iface, refcount);
1641 return refcount;
1644 static BOOL source_reader_is_source_stopped(const struct source_reader *reader)
1646 unsigned int i;
1648 if (reader->source_state != SOURCE_STATE_STOPPED)
1649 return FALSE;
1651 for (i = 0; i < reader->stream_count; ++i)
1653 if (reader->streams[i].stream && !(reader->streams[i].flags & STREAM_FLAG_STOPPED))
1654 return FALSE;
1657 return TRUE;
1660 static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface)
1662 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1663 ULONG refcount = InterlockedDecrement(&reader->public_refcount);
1664 unsigned int i;
1666 TRACE("%p, refcount %lu.\n", iface, refcount);
1668 if (!refcount)
1670 if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE)
1671 IMFMediaSource_Shutdown(reader->source);
1672 else if (SUCCEEDED(IMFMediaSource_Stop(reader->source)))
1674 EnterCriticalSection(&reader->cs);
1676 while (!source_reader_is_source_stopped(reader))
1678 SleepConditionVariableCS(&reader->stop_event, &reader->cs, INFINITE);
1681 LeaveCriticalSection(&reader->cs);
1684 for (i = 0; i < reader->stream_count; ++i)
1686 struct media_stream *stream = &reader->streams[i];
1687 IMFVideoSampleAllocatorCallback *callback;
1689 if (!stream->allocator)
1690 continue;
1692 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream->allocator, &IID_IMFVideoSampleAllocatorCallback,
1693 (void **)&callback)))
1695 IMFVideoSampleAllocatorCallback_SetCallback(callback, NULL);
1696 IMFVideoSampleAllocatorCallback_Release(callback);
1700 MFUnlockWorkQueue(reader->queue);
1701 source_reader_release(reader);
1704 return refcount;
1707 static HRESULT WINAPI src_reader_GetStreamSelection(IMFSourceReaderEx *iface, DWORD index, BOOL *selected)
1709 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1711 TRACE("%p, %#lx, %p.\n", iface, index, selected);
1713 switch (index)
1715 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1716 index = reader->first_video_stream_index;
1717 break;
1718 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1719 index = reader->first_audio_stream_index;
1720 break;
1721 default:
1725 return source_reader_get_stream_selection(reader, index, selected);
1728 static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReaderEx *iface, DWORD index, BOOL selection)
1730 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1731 HRESULT hr = S_OK;
1732 BOOL selection_changed = FALSE, selected;
1733 unsigned int i;
1735 TRACE("%p, %#lx, %d.\n", iface, index, selection);
1737 selection = !!selection;
1739 EnterCriticalSection(&reader->cs);
1741 if (index == MF_SOURCE_READER_ALL_STREAMS)
1743 for (i = 0; i < reader->stream_count; ++i)
1745 if (!selection_changed)
1747 source_reader_get_stream_selection(reader, i, &selected);
1748 selection_changed = !!(selected ^ selection);
1751 if (selection)
1752 IMFPresentationDescriptor_SelectStream(reader->descriptor, i);
1753 else
1754 IMFPresentationDescriptor_DeselectStream(reader->descriptor, i);
1757 else
1759 switch (index)
1761 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1762 index = reader->first_video_stream_index;
1763 break;
1764 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1765 index = reader->first_audio_stream_index;
1766 break;
1767 default:
1771 source_reader_get_stream_selection(reader, index, &selected);
1772 selection_changed = !!(selected ^ selection);
1774 if (selection)
1775 hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
1776 else
1777 hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
1780 if (selection_changed)
1782 for (i = 0; i < reader->stream_count; ++i)
1784 reader->streams[i].last_sample_ts = 0;
1788 LeaveCriticalSection(&reader->cs);
1790 return SUCCEEDED(hr) ? S_OK : MF_E_INVALIDSTREAMNUMBER;
1793 static HRESULT source_reader_get_native_media_type(struct source_reader *reader, DWORD index, DWORD type_index,
1794 IMFMediaType **type)
1796 IMFMediaTypeHandler *handler;
1797 IMFStreamDescriptor *sd;
1798 IMFMediaType *src_type;
1799 BOOL selected;
1800 HRESULT hr;
1802 switch (index)
1804 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1805 index = reader->first_video_stream_index;
1806 break;
1807 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1808 index = reader->first_audio_stream_index;
1809 break;
1810 default:
1814 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1815 return MF_E_INVALIDSTREAMNUMBER;
1817 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
1818 IMFStreamDescriptor_Release(sd);
1819 if (FAILED(hr))
1820 return hr;
1822 if (type_index == MF_SOURCE_READER_CURRENT_TYPE_INDEX)
1823 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &src_type);
1824 else
1825 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, type_index, &src_type);
1826 IMFMediaTypeHandler_Release(handler);
1828 if (SUCCEEDED(hr))
1830 if (SUCCEEDED(hr = MFCreateMediaType(type)))
1831 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)*type);
1832 IMFMediaType_Release(src_type);
1835 return hr;
1838 static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReaderEx *iface, DWORD index, DWORD type_index,
1839 IMFMediaType **type)
1841 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1843 TRACE("%p, %#lx, %#lx, %p.\n", iface, index, type_index, type);
1845 return source_reader_get_native_media_type(reader, index, type_index, type);
1848 static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReaderEx *iface, DWORD index, IMFMediaType **type)
1850 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1851 HRESULT hr;
1853 TRACE("%p, %#lx, %p.\n", iface, index, type);
1855 switch (index)
1857 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1858 index = reader->first_video_stream_index;
1859 break;
1860 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1861 index = reader->first_audio_stream_index;
1862 break;
1863 default:
1867 if (index >= reader->stream_count)
1868 return MF_E_INVALIDSTREAMNUMBER;
1870 if (FAILED(hr = MFCreateMediaType(type)))
1871 return hr;
1873 EnterCriticalSection(&reader->cs);
1875 hr = IMFMediaType_CopyAllItems(reader->streams[index].current, (IMFAttributes *)*type);
1877 LeaveCriticalSection(&reader->cs);
1879 return hr;
1882 static HRESULT source_reader_get_source_type_handler(struct source_reader *reader, DWORD index,
1883 IMFMediaTypeHandler **handler)
1885 IMFStreamDescriptor *sd;
1886 BOOL selected;
1887 HRESULT hr;
1889 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1890 return hr;
1892 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, handler);
1893 IMFStreamDescriptor_Release(sd);
1895 return hr;
1898 static HRESULT source_reader_set_compatible_media_type(struct source_reader *reader, DWORD index, IMFMediaType *type)
1900 struct media_stream *stream = &reader->streams[index];
1901 struct transform_entry *entry, *next;
1902 IMFMediaTypeHandler *type_handler;
1903 IMFMediaType *native_type;
1904 BOOL type_set = FALSE;
1905 unsigned int i = 0;
1906 DWORD flags;
1907 HRESULT hr;
1909 if (FAILED(hr = IMFMediaType_IsEqual(type, stream->current, &flags)))
1910 return hr;
1912 if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES))
1913 return MF_E_INVALIDMEDIATYPE;
1915 /* No need for a decoder or type change. */
1916 if (flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)
1917 return S_OK;
1919 if (stream->transform_service)
1921 IMFTransform_Release(stream->transform_service);
1922 stream->transform_service = NULL;
1924 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry)
1926 list_remove(&entry->entry);
1927 transform_entry_destroy(entry);
1930 if (FAILED(hr = source_reader_get_source_type_handler(reader, index, &type_handler)))
1931 return hr;
1933 while (!type_set && IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, i++, &native_type) == S_OK)
1935 static const DWORD compare_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_DATA;
1937 if (SUCCEEDED(IMFMediaType_IsEqual(native_type, type, &flags)) && (flags & compare_flags) == compare_flags)
1939 if ((type_set = SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler, native_type))))
1940 IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)stream->current);
1943 IMFMediaType_Release(native_type);
1946 IMFMediaTypeHandler_Release(type_handler);
1948 return type_set ? S_OK : S_FALSE;
1951 static HRESULT source_reader_create_sample_allocator_attributes(const struct source_reader *reader,
1952 IMFAttributes **attributes)
1954 UINT32 shared = 0, shared_without_mutex = 0;
1955 HRESULT hr;
1957 if (FAILED(hr = MFCreateAttributes(attributes, 1)))
1958 return hr;
1960 IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared);
1961 IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex);
1963 if (shared_without_mutex)
1964 hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE);
1965 else if (shared)
1966 hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED, TRUE);
1968 return hr;
1971 static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index)
1973 struct media_stream *stream = &reader->streams[index];
1974 IMFAttributes *attributes = NULL;
1975 GUID major = { 0 };
1976 HRESULT hr;
1978 IMFMediaType_GetMajorType(stream->current, &major);
1979 if (!IsEqualGUID(&major, &MFMediaType_Video))
1980 return S_OK;
1982 if (!(reader->flags & SOURCE_READER_HAS_DEVICE_MANAGER))
1983 return S_OK;
1985 if (!stream->allocator)
1987 if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&stream->allocator)))
1989 WARN("Failed to create sample allocator, hr %#lx.\n", hr);
1990 return hr;
1994 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream->allocator);
1995 if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(stream->allocator, reader->device_manager)))
1997 WARN("Failed to set device manager, hr %#lx.\n", hr);
1998 return hr;
2001 if (FAILED(hr = source_reader_create_sample_allocator_attributes(reader, &attributes)))
2002 WARN("Failed to create allocator attributes, hr %#lx.\n", hr);
2004 if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8,
2005 attributes, stream->current)))
2007 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr);
2010 if (attributes)
2011 IMFAttributes_Release(attributes);
2013 return hr;
2016 static BOOL source_reader_allow_video_processor(struct source_reader *reader, BOOL *advanced)
2018 UINT32 value;
2020 *advanced = FALSE;
2021 if (!reader->attributes)
2022 return FALSE;
2024 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, &value)))
2025 *advanced = value;
2026 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, &value)))
2027 return value || *advanced;
2029 return *advanced;
2032 static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL decoder, BOOL allow_processor,
2033 IMFMediaType *input_type, IMFMediaType *output_type, struct transform_entry **out)
2035 MFT_REGISTER_TYPE_INFO in_type, out_type;
2036 struct transform_entry *entry;
2037 IMFActivate **activates;
2038 GUID category;
2039 IMFTransform *transform;
2040 UINT i, count;
2041 HRESULT hr;
2043 if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &in_type.guidMajorType))
2044 || FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype)))
2045 return hr;
2046 if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType))
2047 || FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype)))
2048 return hr;
2050 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video))
2051 category = decoder ? MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_PROCESSOR;
2052 else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio))
2053 category = decoder ? MFT_CATEGORY_AUDIO_DECODER : MFT_CATEGORY_AUDIO_EFFECT;
2054 else
2055 return MF_E_TOPO_CODEC_NOT_FOUND;
2057 if (!(entry = calloc(1, sizeof(*entry))))
2058 return E_OUTOFMEMORY;
2059 list_init(&entry->entry);
2060 entry->category = category;
2062 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)
2063 && SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size)))
2065 UINT32 bytes_per_second;
2067 if (SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second)))
2068 entry->min_buffer_size = max(entry->min_buffer_size, bytes_per_second);
2071 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video) && IsEqualGUID(&out_type.guidSubtype, &MFVideoFormat_ABGR32)
2072 && IsEqualGUID(&category, &MFT_CATEGORY_VIDEO_PROCESSOR))
2074 /* The video processor isn't registered for MFVideoFormat_ABGR32, and native even only supports that format when
2075 * D3D-enabled, we still want to instantiate a video processor in such case, so fixup the subtype for MFTEnumEx.
2077 WARN("Fixing up MFVideoFormat_ABGR32 subtype for the video processor\n");
2078 out_type.guidSubtype = MFVideoFormat_RGB32;
2082 count = 0;
2083 if (SUCCEEDED(hr = MFTEnumEx(category, 0, &in_type, allow_processor ? NULL : &out_type, &activates, &count)))
2085 if (!count)
2087 free(entry);
2088 return MF_E_TOPO_CODEC_NOT_FOUND;
2091 for (i = 0; i < count; i++)
2093 IMFAttributes *attributes;
2094 IMFMediaType *media_type;
2096 if (FAILED(hr = IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void **)&transform)))
2097 continue;
2099 if (!reader->device_manager || FAILED(IMFTransform_GetAttributes(transform, &attributes)))
2100 entry->attributes_initialized = TRUE;
2101 else
2103 UINT32 d3d_aware = FALSE;
2105 if (reader->flags & SOURCE_READER_DXGI_DEVICE_MANAGER)
2107 if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_AWARE, &d3d_aware)) && d3d_aware)
2108 IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)reader->device_manager);
2110 else if (reader->flags & SOURCE_READER_D3D9_DEVICE_MANAGER)
2112 if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D_AWARE, &d3d_aware)) && d3d_aware)
2113 IMFTransform_ProcessMessage(transform, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)reader->device_manager);
2116 entry->attributes_initialized = !d3d_aware;
2117 IMFAttributes_Release(attributes);
2120 if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0))
2121 && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type)))
2123 if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type))
2124 && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0))
2125 && FAILED(hr = set_matching_transform_output_type(transform, output_type)) && allow_processor
2126 && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type)))
2128 struct transform_entry *converter;
2130 if (SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0))
2131 && SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type))
2132 && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, media_type, output_type, &converter)))
2133 list_add_tail(&entry->entry, &converter->entry);
2135 IMFMediaType_Release(media_type);
2138 if (SUCCEEDED(hr))
2140 entry->transform = transform;
2141 *out = entry;
2142 break;
2146 IMFTransform_Release(transform);
2149 for (i = 0; i < count; ++i)
2150 IMFActivate_Release(activates[i]);
2151 CoTaskMemFree(activates);
2154 if (FAILED(hr))
2155 free(entry);
2156 return hr;
2159 static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type)
2161 BOOL enable_advanced, allow_processor;
2162 struct media_stream *stream = &reader->streams[index];
2163 IMFMediaType *input_type;
2164 unsigned int i = 0;
2165 HRESULT hr;
2167 allow_processor = source_reader_allow_video_processor(reader, &enable_advanced);
2169 while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type)))
2171 struct transform_entry *entry;
2173 /* first, try to append a single processor, then try again with a decoder and a processor */
2174 if ((allow_processor && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, input_type, output_type, &entry)))
2175 || SUCCEEDED(hr = source_reader_create_transform(reader, TRUE, allow_processor, input_type, output_type, &entry)))
2177 struct list *ptr = list_head(&entry->entry);
2178 struct transform_entry *service = ptr ? LIST_ENTRY(ptr, struct transform_entry, entry) : entry;
2179 IMFMediaTypeHandler *type_handler;
2181 if (enable_advanced)
2183 /* when advanced video processing is enabled, converters are exposed as stream transform service */
2184 stream->transform_service = service->transform;
2185 IMFTransform_AddRef(stream->transform_service);
2187 else
2189 /* when advanced video processing is disabled, only decoders are exposed as stream transform service */
2190 if (IsEqualGUID(&entry->category, &MFT_CATEGORY_AUDIO_DECODER)
2191 || IsEqualGUID(&entry->category, &MFT_CATEGORY_VIDEO_DECODER))
2193 stream->transform_service = entry->transform;
2194 IMFTransform_AddRef(stream->transform_service);
2196 /* converters are hidden from the stream transforms */
2197 if (service != entry)
2198 service->hidden = TRUE;
2200 else
2202 /* converters are hidden from the stream transforms */
2203 entry->hidden = TRUE;
2207 /* move any additional transforms that have been created */
2208 list_move_head(&stream->transforms, &entry->entry);
2209 list_add_head(&stream->transforms, &entry->entry);
2211 if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler)))
2213 if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type)))
2214 WARN("Failed to set current input media type, hr %#lx\n", hr);
2215 IMFMediaTypeHandler_Release(type_handler);
2218 if (FAILED(hr = IMFTransform_GetOutputCurrentType(service->transform, 0, &output_type)))
2219 WARN("Failed to get decoder output media type, hr %#lx\n", hr);
2220 else
2222 IMFMediaType_CopyAllItems(output_type, (IMFAttributes *)stream->current);
2223 IMFMediaType_Release(output_type);
2226 IMFMediaType_Release(input_type);
2227 return S_OK;
2230 IMFMediaType_Release(input_type);
2233 return MF_E_TOPO_CODEC_NOT_FOUND;
2236 static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, DWORD index, DWORD *reserved,
2237 IMFMediaType *type)
2239 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2240 HRESULT hr;
2242 TRACE("%p, %#lx, %p, %p.\n", iface, index, reserved, type);
2244 switch (index)
2246 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2247 index = reader->first_video_stream_index;
2248 break;
2249 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2250 index = reader->first_audio_stream_index;
2251 break;
2252 default:
2256 if (index >= reader->stream_count)
2257 return MF_E_INVALIDSTREAMNUMBER;
2259 /* FIXME: setting the output type while streaming should trigger a flush */
2261 EnterCriticalSection(&reader->cs);
2263 hr = source_reader_set_compatible_media_type(reader, index, type);
2264 if (hr == S_FALSE)
2265 hr = source_reader_create_decoder_for_stream(reader, index, type);
2266 if (SUCCEEDED(hr))
2267 hr = source_reader_setup_sample_allocator(reader, index);
2269 LeaveCriticalSection(&reader->cs);
2271 return hr;
2274 static HRESULT WINAPI src_reader_SetCurrentPosition(IMFSourceReaderEx *iface, REFGUID format, REFPROPVARIANT position)
2276 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2277 struct source_reader_async_command *command;
2278 unsigned int i;
2279 DWORD flags;
2280 HRESULT hr;
2282 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), position);
2284 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
2285 return hr;
2287 if (!(flags & MFMEDIASOURCE_CAN_SEEK))
2288 return MF_E_INVALIDREQUEST;
2290 EnterCriticalSection(&reader->cs);
2292 /* Check if we got pending requests. */
2293 for (i = 0; i < reader->stream_count; ++i)
2295 if (reader->streams[i].requests)
2297 hr = MF_E_INVALIDREQUEST;
2298 break;
2302 if (SUCCEEDED(hr))
2304 for (i = 0; i < reader->stream_count; ++i)
2306 reader->streams[i].last_sample_ts = 0;
2309 if (reader->async_callback)
2311 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK, &command)))
2313 command->u.seek.format = *format;
2314 PropVariantCopy(&command->u.seek.position, position);
2316 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2317 IUnknown_Release(&command->IUnknown_iface);
2320 else
2322 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, format, position)))
2324 reader->flags |= SOURCE_READER_SEEKING;
2325 while (reader->flags & SOURCE_READER_SEEKING)
2327 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
2333 LeaveCriticalSection(&reader->cs);
2335 return hr;
2338 static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD index, DWORD flags, DWORD *actual_index,
2339 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2341 struct media_stream *stream;
2342 DWORD actual_index_tmp;
2343 LONGLONG timestamp_tmp;
2344 DWORD stream_index;
2345 HRESULT hr = S_OK;
2347 if (!stream_flags || !sample)
2348 return E_POINTER;
2350 *sample = NULL;
2352 if (!timestamp)
2353 timestamp = &timestamp_tmp;
2355 if (!actual_index)
2356 actual_index = &actual_index_tmp;
2358 if (SUCCEEDED(hr = source_reader_start_source(reader)))
2360 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, index, &stream_index)))
2362 *actual_index = stream_index;
2364 stream = &reader->streams[stream_index];
2366 if (!source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
2367 timestamp, sample))
2369 while (!source_reader_got_response_for_stream(reader, stream) && stream->state != STREAM_STATE_EOS)
2371 stream->requests++;
2372 if (FAILED(hr = source_reader_request_sample(reader, stream)))
2373 WARN("Failed to request a sample, hr %#lx.\n", hr);
2374 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
2376 *stream_flags = MF_SOURCE_READERF_ERROR;
2377 *timestamp = 0;
2378 break;
2380 SleepConditionVariableCS(&reader->sample_event, &reader->cs, INFINITE);
2382 if (SUCCEEDED(hr))
2383 source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
2384 timestamp, sample);
2387 else
2389 *actual_index = index;
2390 *stream_flags = MF_SOURCE_READERF_ERROR;
2391 *timestamp = 0;
2395 TRACE("Stream %lu, got sample %p, flags %#lx.\n", *actual_index, *sample, *stream_flags);
2397 return hr;
2400 static HRESULT source_reader_read_sample_async(struct source_reader *reader, unsigned int index, unsigned int flags,
2401 DWORD *actual_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2403 struct source_reader_async_command *command;
2404 HRESULT hr;
2406 if (actual_index || stream_flags || timestamp || sample)
2407 return E_INVALIDARG;
2409 if (reader->flags & SOURCE_READER_FLUSHING)
2410 hr = MF_E_NOTACCEPTING;
2411 else
2413 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_READ, &command)))
2415 command->u.read.stream_index = index;
2416 command->u.read.flags = flags;
2418 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2419 IUnknown_Release(&command->IUnknown_iface);
2423 return hr;
2426 static HRESULT WINAPI src_reader_ReadSample(IMFSourceReaderEx *iface, DWORD index, DWORD flags, DWORD *actual_index,
2427 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2429 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2430 HRESULT hr;
2432 TRACE("%p, %#lx, %#lx, %p, %p, %p, %p\n", iface, index, flags, actual_index, stream_flags, timestamp, sample);
2434 EnterCriticalSection(&reader->cs);
2436 while (reader->flags & SOURCE_READER_SEEKING)
2438 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
2441 if (reader->async_callback)
2442 hr = source_reader_read_sample_async(reader, index, flags, actual_index, stream_flags, timestamp, sample);
2443 else
2444 hr = source_reader_read_sample(reader, index, flags, actual_index, stream_flags, timestamp, sample);
2446 LeaveCriticalSection(&reader->cs);
2448 return hr;
2451 static HRESULT source_reader_flush_async(struct source_reader *reader, unsigned int index)
2453 struct source_reader_async_command *command;
2454 unsigned int stream_index;
2455 HRESULT hr;
2457 if (reader->flags & SOURCE_READER_FLUSHING)
2458 return MF_E_INVALIDREQUEST;
2460 switch (index)
2462 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2463 stream_index = reader->first_video_stream_index;
2464 break;
2465 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2466 stream_index = reader->first_audio_stream_index;
2467 break;
2468 default:
2469 stream_index = index;
2472 reader->flags |= SOURCE_READER_FLUSHING;
2474 if (stream_index != MF_SOURCE_READER_ALL_STREAMS && stream_index >= reader->stream_count)
2475 return MF_E_INVALIDSTREAMNUMBER;
2477 if (FAILED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH, &command)))
2478 return hr;
2480 command->u.flush.stream_index = stream_index;
2482 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2483 IUnknown_Release(&command->IUnknown_iface);
2485 return hr;
2488 static HRESULT WINAPI src_reader_Flush(IMFSourceReaderEx *iface, DWORD index)
2490 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2491 HRESULT hr;
2493 TRACE("%p, %#lx.\n", iface, index);
2495 EnterCriticalSection(&reader->cs);
2497 if (reader->async_callback)
2498 hr = source_reader_flush_async(reader, index);
2499 else
2500 hr = source_reader_flush(reader, index);
2502 LeaveCriticalSection(&reader->cs);
2504 return hr;
2507 static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, DWORD index, REFGUID service,
2508 REFIID riid, void **object)
2510 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2511 IUnknown *obj = NULL;
2512 HRESULT hr = S_OK;
2514 TRACE("%p, %#lx, %s, %s, %p\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object);
2516 EnterCriticalSection(&reader->cs);
2518 switch (index)
2520 case MF_SOURCE_READER_MEDIASOURCE:
2521 obj = (IUnknown *)reader->source;
2522 break;
2523 default:
2524 if (index == MF_SOURCE_READER_FIRST_VIDEO_STREAM)
2525 index = reader->first_video_stream_index;
2526 else if (index == MF_SOURCE_READER_FIRST_AUDIO_STREAM)
2527 index = reader->first_audio_stream_index;
2529 if (index >= reader->stream_count)
2530 hr = MF_E_INVALIDSTREAMNUMBER;
2531 else if (!(obj = (IUnknown *)reader->streams[index].transform_service))
2532 hr = E_NOINTERFACE;
2533 break;
2536 if (obj)
2537 IUnknown_AddRef(obj);
2539 LeaveCriticalSection(&reader->cs);
2541 if (obj)
2543 if (IsEqualGUID(service, &GUID_NULL))
2545 hr = IUnknown_QueryInterface(obj, riid, object);
2547 else
2549 IMFGetService *gs;
2551 hr = IUnknown_QueryInterface(obj, &IID_IMFGetService, (void **)&gs);
2552 if (SUCCEEDED(hr))
2554 hr = IMFGetService_GetService(gs, service, riid, object);
2555 IMFGetService_Release(gs);
2560 if (obj)
2561 IUnknown_Release(obj);
2563 return hr;
2566 static HRESULT WINAPI src_reader_GetPresentationAttribute(IMFSourceReaderEx *iface, DWORD index,
2567 REFGUID guid, PROPVARIANT *value)
2569 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2570 IMFStreamDescriptor *sd;
2571 BOOL selected;
2572 HRESULT hr;
2574 TRACE("%p, %#lx, %s, %p.\n", iface, index, debugstr_guid(guid), value);
2576 switch (index)
2578 case MF_SOURCE_READER_MEDIASOURCE:
2579 if (IsEqualGUID(guid, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS))
2581 DWORD flags;
2583 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
2584 return hr;
2586 value->vt = VT_UI4;
2587 value->ulVal = flags;
2588 return S_OK;
2590 else
2592 return IMFPresentationDescriptor_GetItem(reader->descriptor, guid, value);
2594 break;
2595 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2596 index = reader->first_video_stream_index;
2597 break;
2598 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2599 index = reader->first_audio_stream_index;
2600 break;
2601 default:
2605 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
2606 return hr;
2608 hr = IMFStreamDescriptor_GetItem(sd, guid, value);
2609 IMFStreamDescriptor_Release(sd);
2611 return hr;
2614 static HRESULT WINAPI src_reader_SetNativeMediaType(IMFSourceReaderEx *iface, DWORD stream_index,
2615 IMFMediaType *media_type, DWORD *stream_flags)
2617 FIXME("%p, %#lx, %p, %p.\n", iface, stream_index, media_type, stream_flags);
2619 return E_NOTIMPL;
2622 static HRESULT WINAPI src_reader_AddTransformForStream(IMFSourceReaderEx *iface, DWORD stream_index,
2623 IUnknown *transform)
2625 FIXME("%p, %#lx, %p.\n", iface, stream_index, transform);
2627 return E_NOTIMPL;
2630 static HRESULT WINAPI src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx *iface, DWORD stream_index)
2632 FIXME("%p, %#lx.\n", iface, stream_index);
2634 return E_NOTIMPL;
2637 static struct transform_entry *get_transform_at_index(struct media_stream *stream, UINT index)
2639 struct transform_entry *entry;
2641 LIST_FOR_EACH_ENTRY(entry, &stream->transforms, struct transform_entry, entry)
2642 if (!entry->hidden && !index--)
2643 return entry;
2645 return NULL;
2648 static HRESULT WINAPI src_reader_GetTransformForStream(IMFSourceReaderEx *iface, DWORD stream_index,
2649 DWORD transform_index, GUID *category, IMFTransform **transform)
2651 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2652 struct transform_entry *entry;
2653 HRESULT hr;
2655 TRACE("%p, %#lx, %#lx, %p, %p.\n", iface, stream_index, transform_index, category, transform);
2657 if (!transform)
2658 return E_POINTER;
2660 EnterCriticalSection(&reader->cs);
2662 if (stream_index == MF_SOURCE_READER_FIRST_VIDEO_STREAM)
2663 stream_index = reader->first_video_stream_index;
2664 else if (stream_index == MF_SOURCE_READER_FIRST_AUDIO_STREAM)
2665 stream_index = reader->first_audio_stream_index;
2667 if (stream_index >= reader->stream_count)
2668 hr = MF_E_INVALIDSTREAMNUMBER;
2669 else if (!(entry = get_transform_at_index(&reader->streams[stream_index], transform_index)))
2670 hr = MF_E_INVALIDINDEX;
2671 else
2673 if (category)
2674 *category = entry->category;
2675 *transform = entry->transform;
2676 IMFTransform_AddRef(*transform);
2677 hr = S_OK;
2680 LeaveCriticalSection(&reader->cs);
2682 return hr;
2685 static const IMFSourceReaderExVtbl srcreader_vtbl =
2687 src_reader_QueryInterface,
2688 src_reader_AddRef,
2689 src_reader_Release,
2690 src_reader_GetStreamSelection,
2691 src_reader_SetStreamSelection,
2692 src_reader_GetNativeMediaType,
2693 src_reader_GetCurrentMediaType,
2694 src_reader_SetCurrentMediaType,
2695 src_reader_SetCurrentPosition,
2696 src_reader_ReadSample,
2697 src_reader_Flush,
2698 src_reader_GetServiceForStream,
2699 src_reader_GetPresentationAttribute,
2700 src_reader_SetNativeMediaType,
2701 src_reader_AddTransformForStream,
2702 src_reader_RemoveAllTransformsForStream,
2703 src_reader_GetTransformForStream,
2706 static DWORD reader_get_first_stream_index(IMFPresentationDescriptor *descriptor, const GUID *major)
2708 DWORD count, i;
2709 BOOL selected;
2710 HRESULT hr;
2711 GUID guid;
2713 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count)))
2714 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2716 for (i = 0; i < count; ++i)
2718 IMFMediaTypeHandler *handler;
2719 IMFStreamDescriptor *sd;
2721 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i, &selected, &sd)))
2723 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2724 IMFStreamDescriptor_Release(sd);
2725 if (SUCCEEDED(hr))
2727 hr = IMFMediaTypeHandler_GetMajorType(handler, &guid);
2728 IMFMediaTypeHandler_Release(handler);
2729 if (FAILED(hr))
2731 WARN("Failed to get stream major type, hr %#lx.\n", hr);
2732 continue;
2735 if (IsEqualGUID(&guid, major))
2737 return i;
2743 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2746 static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttributes *attributes,
2747 BOOL shutdown_on_release, REFIID riid, void **out)
2749 struct source_reader *object;
2750 unsigned int i;
2751 HRESULT hr;
2753 object = calloc(1, sizeof(*object));
2754 if (!object)
2755 return E_OUTOFMEMORY;
2757 object->IMFSourceReaderEx_iface.lpVtbl = &srcreader_vtbl;
2758 object->source_events_callback.lpVtbl = &source_events_callback_vtbl;
2759 object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl;
2760 object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl;
2761 object->public_refcount = 1;
2762 object->refcount = 1;
2763 list_init(&object->responses);
2764 if (shutdown_on_release)
2765 object->flags |= SOURCE_READER_SHUTDOWN_ON_RELEASE;
2766 object->source = source;
2767 IMFMediaSource_AddRef(object->source);
2768 InitializeCriticalSection(&object->cs);
2769 InitializeConditionVariable(&object->sample_event);
2770 InitializeConditionVariable(&object->state_event);
2771 InitializeConditionVariable(&object->stop_event);
2773 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor)))
2774 goto failed;
2776 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(object->descriptor, &object->stream_count)))
2777 goto failed;
2779 if (!(object->streams = calloc(object->stream_count, sizeof(*object->streams))))
2781 hr = E_OUTOFMEMORY;
2782 goto failed;
2785 /* Set initial current media types. */
2786 for (i = 0; i < object->stream_count; ++i)
2788 IMFMediaTypeHandler *handler;
2789 IMFStreamDescriptor *sd;
2790 IMFMediaType *src_type;
2791 BOOL selected;
2793 list_init(&object->streams[i].transforms);
2795 if (FAILED(hr = MFCreateMediaType(&object->streams[i].current)))
2796 break;
2798 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(object->descriptor, i, &selected, &sd)))
2799 break;
2801 if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &object->streams[i].id)))
2802 WARN("Failed to get stream identifier, hr %#lx.\n", hr);
2804 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2805 IMFStreamDescriptor_Release(sd);
2806 if (FAILED(hr))
2807 break;
2809 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &src_type);
2810 IMFMediaTypeHandler_Release(handler);
2811 if (FAILED(hr))
2812 break;
2814 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)object->streams[i].current);
2815 IMFMediaType_Release(src_type);
2816 if (FAILED(hr))
2817 break;
2819 object->streams[i].reader = object;
2820 object->streams[i].index = i;
2823 if (FAILED(hr))
2824 goto failed;
2826 /* At least one major type has to be set. */
2827 object->first_audio_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Audio);
2828 object->first_video_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Video);
2830 if (object->first_audio_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX &&
2831 object->first_video_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX)
2833 hr = MF_E_ATTRIBUTENOTFOUND;
2836 if (FAILED(hr = IMFMediaSource_BeginGetEvent(object->source, &object->source_events_callback,
2837 (IUnknown *)object->source)))
2839 goto failed;
2842 if (attributes)
2844 object->attributes = attributes;
2845 IMFAttributes_AddRef(object->attributes);
2847 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_ASYNC_CALLBACK, &IID_IMFSourceReaderCallback,
2848 (void **)&object->async_callback);
2849 if (object->async_callback)
2850 TRACE("Using async callback %p.\n", object->async_callback);
2852 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, &IID_IUnknown, (void **)&object->device_manager);
2853 if (object->device_manager)
2855 IUnknown *unk = NULL;
2857 if (SUCCEEDED(IUnknown_QueryInterface(object->device_manager, &IID_IMFDXGIDeviceManager, (void **)&unk)))
2858 object->flags |= SOURCE_READER_DXGI_DEVICE_MANAGER;
2859 else if (SUCCEEDED(IUnknown_QueryInterface(object->device_manager, &IID_IDirect3DDeviceManager9, (void **)&unk)))
2860 object->flags |= SOURCE_READER_D3D9_DEVICE_MANAGER;
2862 if (!(object->flags & (SOURCE_READER_HAS_DEVICE_MANAGER)))
2864 WARN("Unknown device manager.\n");
2865 IUnknown_Release(object->device_manager);
2866 object->device_manager = NULL;
2869 if (unk)
2870 IUnknown_Release(unk);
2874 if (FAILED(hr = MFLockSharedWorkQueue(L"", 0, NULL, &object->queue)))
2875 WARN("Failed to acquired shared queue, hr %#lx.\n", hr);
2877 if (SUCCEEDED(hr))
2878 hr = IMFSourceReaderEx_QueryInterface(&object->IMFSourceReaderEx_iface, riid, out);
2880 failed:
2881 IMFSourceReaderEx_Release(&object->IMFSourceReaderEx_iface);
2882 return hr;
2885 static HRESULT create_source_reader_from_stream(IMFByteStream *stream, IMFAttributes *attributes,
2886 REFIID riid, void **out)
2888 IPropertyStore *props = NULL;
2889 IMFSourceResolver *resolver;
2890 MF_OBJECT_TYPE obj_type;
2891 IMFMediaSource *source;
2892 HRESULT hr;
2894 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2895 return hr;
2897 if (attributes)
2898 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2899 (void **)&props);
2901 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE
2902 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, props, &obj_type, (IUnknown **)&source);
2903 IMFSourceResolver_Release(resolver);
2904 if (props)
2905 IPropertyStore_Release(props);
2906 if (FAILED(hr))
2907 return hr;
2909 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2910 IMFMediaSource_Release(source);
2911 return hr;
2914 static HRESULT create_source_reader_from_url(const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2916 IPropertyStore *props = NULL;
2917 IMFSourceResolver *resolver;
2918 IUnknown *object = NULL;
2919 MF_OBJECT_TYPE obj_type;
2920 IMFMediaSource *source;
2921 HRESULT hr;
2923 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2924 return hr;
2926 if (attributes)
2927 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2928 (void **)&props);
2930 hr = IMFSourceResolver_CreateObjectFromURL(resolver, url, MF_RESOLUTION_MEDIASOURCE, props, &obj_type,
2931 &object);
2932 if (SUCCEEDED(hr))
2934 switch (obj_type)
2936 case MF_OBJECT_BYTESTREAM:
2937 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, (IMFByteStream *)object, NULL,
2938 MF_RESOLUTION_MEDIASOURCE, props, &obj_type, (IUnknown **)&source);
2939 break;
2940 case MF_OBJECT_MEDIASOURCE:
2941 source = (IMFMediaSource *)object;
2942 IMFMediaSource_AddRef(source);
2943 break;
2944 default:
2945 WARN("Unknown object type %d.\n", obj_type);
2946 hr = E_UNEXPECTED;
2948 IUnknown_Release(object);
2951 IMFSourceResolver_Release(resolver);
2952 if (props)
2953 IPropertyStore_Release(props);
2954 if (FAILED(hr))
2955 return hr;
2957 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2958 IMFMediaSource_Release(source);
2959 return hr;
2962 static HRESULT create_source_reader_from_object(IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2964 IMFMediaSource *source = NULL;
2965 IMFByteStream *stream = NULL;
2966 HRESULT hr;
2968 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSource, (void **)&source);
2969 if (FAILED(hr))
2970 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2972 if (source)
2974 UINT32 disconnect = 0;
2976 if (attributes)
2977 IMFAttributes_GetUINT32(attributes, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN, &disconnect);
2978 hr = create_source_reader_from_source(source, attributes, !disconnect, riid, out);
2980 else if (stream)
2981 hr = create_source_reader_from_stream(stream, attributes, riid, out);
2983 if (source)
2984 IMFMediaSource_Release(source);
2985 if (stream)
2986 IMFByteStream_Release(stream);
2988 return hr;
2991 /***********************************************************************
2992 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2994 HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes,
2995 IMFSourceReader **reader)
2997 TRACE("%p, %p, %p.\n", stream, attributes, reader);
2999 return create_source_reader_from_object((IUnknown *)stream, attributes, &IID_IMFSourceReader, (void **)reader);
3002 /***********************************************************************
3003 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
3005 HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes,
3006 IMFSourceReader **reader)
3008 TRACE("%p, %p, %p.\n", source, attributes, reader);
3010 return create_source_reader_from_object((IUnknown *)source, attributes, &IID_IMFSourceReader, (void **)reader);
3013 /***********************************************************************
3014 * MFCreateSourceReaderFromURL (mfreadwrite.@)
3016 HRESULT WINAPI MFCreateSourceReaderFromURL(const WCHAR *url, IMFAttributes *attributes, IMFSourceReader **reader)
3018 TRACE("%s, %p, %p.\n", debugstr_w(url), attributes, reader);
3020 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, (void **)reader);
3023 static HRESULT WINAPI readwrite_factory_QueryInterface(IMFReadWriteClassFactory *iface, REFIID riid, void **out)
3025 if (IsEqualIID(riid, &IID_IMFReadWriteClassFactory) ||
3026 IsEqualIID(riid, &IID_IUnknown))
3028 *out = iface;
3029 IMFReadWriteClassFactory_AddRef(iface);
3030 return S_OK;
3033 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
3034 *out = NULL;
3035 return E_NOINTERFACE;
3038 static ULONG WINAPI readwrite_factory_AddRef(IMFReadWriteClassFactory *iface)
3040 return 2;
3043 static ULONG WINAPI readwrite_factory_Release(IMFReadWriteClassFactory *iface)
3045 return 1;
3048 static HRESULT WINAPI readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory *iface, REFCLSID clsid,
3049 const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
3051 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid), debugstr_w(url), attributes, debugstr_guid(riid), out);
3053 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
3055 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, out);
3057 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
3059 return create_sink_writer_from_url(url, NULL, attributes, riid, out);
3062 FIXME("Unsupported %s.\n", debugstr_guid(clsid));
3064 return E_NOTIMPL;
3067 static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory *iface, REFCLSID clsid,
3068 IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
3070 HRESULT hr;
3072 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid), unk, attributes, debugstr_guid(riid), out);
3074 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
3076 return create_source_reader_from_object(unk, attributes, riid, out);
3078 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
3080 IMFByteStream *stream = NULL;
3081 IMFMediaSink *sink = NULL;
3083 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
3084 if (FAILED(hr))
3085 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSink, (void **)&sink);
3087 if (stream)
3088 hr = create_sink_writer_from_url(NULL, stream, attributes, riid, out);
3089 else if (sink)
3090 hr = create_sink_writer_from_sink(sink, attributes, riid, out);
3092 if (sink)
3093 IMFMediaSink_Release(sink);
3094 if (stream)
3095 IMFByteStream_Release(stream);
3097 return hr;
3099 else
3101 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
3102 *out = NULL;
3103 return E_FAIL;
3107 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl =
3109 readwrite_factory_QueryInterface,
3110 readwrite_factory_AddRef,
3111 readwrite_factory_Release,
3112 readwrite_factory_CreateInstanceFromURL,
3113 readwrite_factory_CreateInstanceFromObject,
3116 static IMFReadWriteClassFactory readwrite_factory = { &readwrite_factory_vtbl };
3118 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
3120 TRACE("%s, %p.\n", debugstr_guid(riid), out);
3122 if (IsEqualGUID(riid, &IID_IClassFactory) ||
3123 IsEqualGUID(riid, &IID_IUnknown))
3125 IClassFactory_AddRef(iface);
3126 *out = iface;
3127 return S_OK;
3130 WARN("interface %s not implemented\n", debugstr_guid(riid));
3131 *out = NULL;
3132 return E_NOINTERFACE;
3135 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
3137 return 2;
3140 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
3142 return 1;
3145 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out)
3147 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), out);
3149 *out = NULL;
3151 if (outer)
3152 return CLASS_E_NOAGGREGATION;
3154 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory, riid, out);
3157 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
3159 FIXME("%d.\n", dolock);
3160 return S_OK;
3163 static const IClassFactoryVtbl classfactoryvtbl =
3165 classfactory_QueryInterface,
3166 classfactory_AddRef,
3167 classfactory_Release,
3168 classfactory_CreateInstance,
3169 classfactory_LockServer,
3172 static IClassFactory classfactory = { &classfactoryvtbl };
3174 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
3176 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), out);
3178 if (IsEqualGUID(clsid, &CLSID_MFReadWriteClassFactory))
3179 return IClassFactory_QueryInterface(&classfactory, riid, out);
3181 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
3182 *out = NULL;
3183 return CLASS_E_CLASSNOTAVAILABLE;