mfreadwrite/reader: Use MFTEnumEx to enumerate stream transforms.
[wine.git] / dlls / mfreadwrite / reader.c
blob2baa3810ee0dddfbdd8bdf366117dda36b887175
1 /*
3 * Copyright 2014 Austin English
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
22 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "ole2.h"
26 #include "rpcproxy.h"
28 #undef INITGUID
29 #include <guiddef.h>
30 #include "mfapi.h"
31 #include "mfidl.h"
32 #include "mfreadwrite.h"
33 #include "d3d9.h"
34 #include "initguid.h"
35 #include "dxva2api.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 #include "mf_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
44 struct stream_response
46 struct list entry;
47 HRESULT status;
48 DWORD stream_index;
49 DWORD stream_flags;
50 LONGLONG timestamp;
51 IMFSample *sample;
54 enum media_stream_state
56 STREAM_STATE_READY = 0,
57 STREAM_STATE_EOS,
60 enum media_source_state
62 SOURCE_STATE_STOPPED = 0,
63 SOURCE_STATE_STARTED,
66 enum media_stream_flags
68 STREAM_FLAG_SAMPLE_REQUESTED = 0x1, /* Protects from making multiple sample requests. */
69 STREAM_FLAG_SELECTED = 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
70 STREAM_FLAG_PRESENTED = 0x4, /* Set if stream was selected last time Start() was called. */
71 STREAM_FLAG_STOPPED = 0x8, /* Received MEStreamStopped */
74 struct transform_entry
76 struct list entry;
77 IMFTransform *transform;
78 unsigned int min_buffer_size;
79 UINT32 pending_flags;
80 GUID category;
81 BOOL hidden;
84 struct media_stream
86 IMFMediaStream *stream;
87 IMFMediaType *current;
88 struct list transforms;
89 IMFVideoSampleAllocatorEx *allocator;
90 IMFTransform *transform_service;
91 DWORD id;
92 unsigned int index;
93 enum media_stream_state state;
94 unsigned int flags;
95 unsigned int requests;
96 unsigned int responses;
97 LONGLONG last_sample_ts;
98 struct source_reader *reader;
101 enum source_reader_async_op
103 SOURCE_READER_ASYNC_READ,
104 SOURCE_READER_ASYNC_SEEK,
105 SOURCE_READER_ASYNC_FLUSH,
106 SOURCE_READER_ASYNC_SAMPLE_READY,
109 struct source_reader_async_command
111 IUnknown IUnknown_iface;
112 LONG refcount;
113 enum source_reader_async_op op;
114 union
116 struct
118 unsigned int flags;
119 unsigned int stream_index;
120 } read;
121 struct
123 GUID format;
124 PROPVARIANT position;
125 } seek;
126 struct
128 unsigned int stream_index;
129 } flush;
130 struct
132 unsigned int stream_index;
133 } sample;
134 struct
136 unsigned int stream_index;
137 } sa;
138 } u;
141 enum source_reader_flags
143 SOURCE_READER_FLUSHING = 0x1,
144 SOURCE_READER_SEEKING = 0x2,
145 SOURCE_READER_SHUTDOWN_ON_RELEASE = 0x4,
146 SOURCE_READER_D3D9_DEVICE_MANAGER = 0x8,
147 SOURCE_READER_DXGI_DEVICE_MANAGER = 0x10,
148 SOURCE_READER_HAS_DEVICE_MANAGER = SOURCE_READER_D3D9_DEVICE_MANAGER | SOURCE_READER_DXGI_DEVICE_MANAGER,
151 struct source_reader
153 IMFSourceReaderEx IMFSourceReaderEx_iface;
154 IMFAsyncCallback source_events_callback;
155 IMFAsyncCallback stream_events_callback;
156 IMFAsyncCallback async_commands_callback;
157 LONG refcount;
158 LONG public_refcount;
159 IMFMediaSource *source;
160 IMFPresentationDescriptor *descriptor;
161 IMFSourceReaderCallback *async_callback;
162 IMFAttributes *attributes;
163 IUnknown *device_manager;
164 unsigned int first_audio_stream_index;
165 unsigned int first_video_stream_index;
166 DWORD stream_count;
167 unsigned int flags;
168 DWORD queue;
169 enum media_source_state source_state;
170 struct media_stream *streams;
171 struct list responses;
172 CRITICAL_SECTION cs;
173 CONDITION_VARIABLE sample_event;
174 CONDITION_VARIABLE state_event;
175 CONDITION_VARIABLE stop_event;
178 static inline struct source_reader *impl_from_IMFSourceReaderEx(IMFSourceReaderEx *iface)
180 return CONTAINING_RECORD(iface, struct source_reader, IMFSourceReaderEx_iface);
183 static struct source_reader *impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
185 return CONTAINING_RECORD(iface, struct source_reader, source_events_callback);
188 static struct source_reader *impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
190 return CONTAINING_RECORD(iface, struct source_reader, stream_events_callback);
193 static struct source_reader *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
195 return CONTAINING_RECORD(iface, struct source_reader, async_commands_callback);
198 static struct source_reader_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
200 return CONTAINING_RECORD(iface, struct source_reader_async_command, IUnknown_iface);
203 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream);
205 static ULONG source_reader_addref(struct source_reader *reader)
207 return InterlockedIncrement(&reader->refcount);
210 static void transform_entry_destroy(struct transform_entry *entry)
212 IMFTransform_Release(entry->transform);
213 free(entry);
216 static void media_stream_destroy(struct media_stream *stream)
218 struct transform_entry *entry, *next;
220 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry)
222 list_remove(&entry->entry);
223 transform_entry_destroy(entry);
226 if (stream->stream)
227 IMFMediaStream_Release(stream->stream);
228 if (stream->current)
229 IMFMediaType_Release(stream->current);
230 if (stream->allocator)
231 IMFVideoSampleAllocatorEx_Release(stream->allocator);
234 static ULONG source_reader_release(struct source_reader *reader)
236 ULONG refcount = InterlockedDecrement(&reader->refcount);
237 unsigned int i;
239 if (!refcount)
241 if (reader->device_manager)
242 IUnknown_Release(reader->device_manager);
243 if (reader->async_callback)
244 IMFSourceReaderCallback_Release(reader->async_callback);
245 if (reader->descriptor)
246 IMFPresentationDescriptor_Release(reader->descriptor);
247 if (reader->attributes)
248 IMFAttributes_Release(reader->attributes);
249 IMFMediaSource_Release(reader->source);
251 for (i = 0; i < reader->stream_count; ++i)
253 struct media_stream *stream = &reader->streams[i];
254 media_stream_destroy(stream);
256 source_reader_release_responses(reader, NULL);
257 free(reader->streams);
258 MFUnlockWorkQueue(reader->queue);
259 DeleteCriticalSection(&reader->cs);
260 free(reader);
263 return refcount;
266 static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
268 if (IsEqualIID(riid, &IID_IUnknown))
270 *obj = iface;
271 IUnknown_AddRef(iface);
272 return S_OK;
275 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
276 *obj = NULL;
277 return E_NOINTERFACE;
280 static ULONG WINAPI source_reader_async_command_AddRef(IUnknown *iface)
282 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
283 return InterlockedIncrement(&command->refcount);
286 static ULONG WINAPI source_reader_async_command_Release(IUnknown *iface)
288 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
289 ULONG refcount = InterlockedIncrement(&command->refcount);
291 if (!refcount)
293 if (command->op == SOURCE_READER_ASYNC_SEEK)
294 PropVariantClear(&command->u.seek.position);
295 free(command);
298 return refcount;
301 static const IUnknownVtbl source_reader_async_command_vtbl =
303 source_reader_async_command_QueryInterface,
304 source_reader_async_command_AddRef,
305 source_reader_async_command_Release,
308 static HRESULT source_reader_create_async_op(enum source_reader_async_op op, struct source_reader_async_command **ret)
310 struct source_reader_async_command *command;
312 if (!(command = calloc(1, sizeof(*command))))
313 return E_OUTOFMEMORY;
315 command->IUnknown_iface.lpVtbl = &source_reader_async_command_vtbl;
316 command->op = op;
318 *ret = command;
320 return S_OK;
323 static HRESULT media_event_get_object(IMFMediaEvent *event, REFIID riid, void **obj)
325 PROPVARIANT value;
326 HRESULT hr;
328 PropVariantInit(&value);
329 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
331 WARN("Failed to get event value, hr %#lx.\n", hr);
332 return hr;
335 if (value.vt != VT_UNKNOWN || !value.punkVal)
337 WARN("Unexpected value type %d.\n", value.vt);
338 PropVariantClear(&value);
339 return E_UNEXPECTED;
342 hr = IUnknown_QueryInterface(value.punkVal, riid, obj);
343 PropVariantClear(&value);
344 if (FAILED(hr))
346 WARN("Unexpected object type.\n");
347 return hr;
350 return hr;
353 static HRESULT media_stream_get_id(IMFMediaStream *stream, DWORD *id)
355 IMFStreamDescriptor *sd;
356 HRESULT hr;
358 if (SUCCEEDED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
360 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, id);
361 IMFStreamDescriptor_Release(sd);
364 return hr;
367 static HRESULT WINAPI source_reader_callback_QueryInterface(IMFAsyncCallback *iface,
368 REFIID riid, void **obj)
370 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
372 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
373 IsEqualIID(riid, &IID_IUnknown))
375 *obj = iface;
376 IMFAsyncCallback_AddRef(iface);
377 return S_OK;
380 WARN("Unsupported %s.\n", debugstr_guid(riid));
381 *obj = NULL;
382 return E_NOINTERFACE;
385 static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface)
387 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
388 return source_reader_addref(reader);
391 static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface)
393 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
394 return source_reader_release(reader);
397 static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface,
398 DWORD *flags, DWORD *queue)
400 return E_NOTIMPL;
403 static void source_reader_response_ready(struct source_reader *reader, struct stream_response *response)
405 struct source_reader_async_command *command;
406 struct media_stream *stream = &reader->streams[response->stream_index];
407 HRESULT hr;
409 if (!stream->requests)
410 return;
412 if (reader->async_callback)
414 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY, &command)))
416 command->u.sample.stream_index = stream->index;
417 if (FAILED(hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface)))
418 WARN("Failed to submit async result, hr %#lx.\n", hr);
419 IUnknown_Release(&command->IUnknown_iface);
422 else
423 WakeAllConditionVariable(&reader->sample_event);
425 stream->requests--;
428 static void source_reader_copy_sample_buffer(IMFSample *src, IMFSample *dst)
430 IMFMediaBuffer *buffer;
431 LONGLONG time;
432 DWORD flags;
433 HRESULT hr;
435 IMFSample_CopyAllItems(src, (IMFAttributes *)dst);
437 IMFSample_SetSampleDuration(dst, 0);
438 IMFSample_SetSampleTime(dst, 0);
439 IMFSample_SetSampleFlags(dst, 0);
441 if (SUCCEEDED(IMFSample_GetSampleDuration(src, &time)))
442 IMFSample_SetSampleDuration(dst, time);
444 if (SUCCEEDED(IMFSample_GetSampleTime(src, &time)))
445 IMFSample_SetSampleTime(dst, time);
447 if (SUCCEEDED(IMFSample_GetSampleFlags(src, &flags)))
448 IMFSample_SetSampleFlags(dst, flags);
450 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src, NULL)))
452 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst, 0, &buffer)))
454 if (FAILED(hr = IMFSample_CopyToBuffer(src, buffer)))
455 WARN("Failed to copy a buffer, hr %#lx.\n", hr);
456 IMFMediaBuffer_Release(buffer);
461 static HRESULT source_reader_queue_response(struct source_reader *reader, struct media_stream *stream, HRESULT status,
462 DWORD stream_flags, LONGLONG timestamp, IMFSample *sample)
464 struct stream_response *response;
466 if (!(response = calloc(1, sizeof(*response))))
467 return E_OUTOFMEMORY;
469 response->status = status;
470 response->stream_index = stream->index;
471 response->stream_flags = stream_flags;
472 response->timestamp = timestamp;
473 response->sample = sample;
474 if (response->sample)
475 IMFSample_AddRef(response->sample);
477 list_add_tail(&reader->responses, &response->entry);
478 stream->responses++;
480 source_reader_response_ready(reader, response);
482 stream->last_sample_ts = timestamp;
484 return S_OK;
487 static HRESULT source_reader_queue_sample(struct source_reader *reader, struct media_stream *stream,
488 UINT flags, IMFSample *sample)
490 LONGLONG timestamp = 0;
492 if (FAILED(IMFSample_GetSampleTime(sample, &timestamp)))
493 WARN("Sample time wasn't set.\n");
495 return source_reader_queue_response(reader, stream, S_OK, flags, timestamp, sample);
498 static HRESULT source_reader_request_sample(struct source_reader *reader, struct media_stream *stream)
500 HRESULT hr = S_OK;
502 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
504 if (FAILED(hr = IMFMediaStream_RequestSample(stream->stream, NULL)))
505 WARN("Sample request failed, hr %#lx.\n", hr);
506 else
508 stream->flags |= STREAM_FLAG_SAMPLE_REQUESTED;
512 return hr;
515 static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IMFMediaEvent *event)
517 IMFMediaStream *stream;
518 unsigned int i;
519 DWORD id = 0;
520 HRESULT hr;
522 if (FAILED(hr = media_event_get_object(event, &IID_IMFMediaStream, (void **)&stream)))
524 WARN("Failed to get stream object, hr %#lx.\n", hr);
525 return hr;
528 TRACE("Got new stream %p.\n", stream);
530 if (FAILED(hr = media_stream_get_id(stream, &id)))
532 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
533 IMFMediaStream_Release(stream);
534 return hr;
537 EnterCriticalSection(&reader->cs);
539 for (i = 0; i < reader->stream_count; ++i)
541 if (id == reader->streams[i].id)
543 if (!reader->streams[i].stream)
545 reader->streams[i].stream = stream;
546 IMFMediaStream_AddRef(reader->streams[i].stream);
547 if (FAILED(hr = IMFMediaStream_BeginGetEvent(stream, &reader->stream_events_callback,
548 (IUnknown *)stream)))
550 WARN("Failed to subscribe to stream events, hr %#lx.\n", hr);
553 if (reader->streams[i].requests)
554 if (FAILED(source_reader_request_sample(reader, &reader->streams[i])))
555 WakeAllConditionVariable(&reader->sample_event);
557 break;
561 if (i == reader->stream_count)
562 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id);
564 LeaveCriticalSection(&reader->cs);
566 IMFMediaStream_Release(stream);
568 return hr;
571 static HRESULT source_reader_source_state_handler(struct source_reader *reader, MediaEventType event_type)
573 EnterCriticalSection(&reader->cs);
575 switch (event_type)
577 case MESourceStarted:
578 reader->source_state = SOURCE_STATE_STARTED;
579 reader->flags &= ~SOURCE_READER_SEEKING;
580 break;
581 case MESourceStopped:
582 reader->source_state = SOURCE_STATE_STOPPED;
583 reader->flags &= ~SOURCE_READER_SEEKING;
584 break;
585 case MESourceSeeked:
586 reader->flags &= ~SOURCE_READER_SEEKING;
587 break;
588 default:
589 WARN("Unhandled event %ld.\n", event_type);
592 LeaveCriticalSection(&reader->cs);
594 WakeAllConditionVariable(&reader->state_event);
595 if (event_type == MESourceStopped)
596 WakeAllConditionVariable(&reader->stop_event);
598 return S_OK;
601 static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
603 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
604 MediaEventType event_type;
605 IMFMediaSource *source;
606 IMFMediaEvent *event;
607 HRESULT hr;
609 TRACE("%p, %p.\n", iface, result);
611 source = (IMFMediaSource *)IMFAsyncResult_GetStateNoAddRef(result);
613 if (FAILED(hr = IMFMediaSource_EndGetEvent(source, result, &event)))
614 return hr;
616 IMFMediaEvent_GetType(event, &event_type);
618 TRACE("Got event %lu.\n", event_type);
620 switch (event_type)
622 case MENewStream:
623 hr = source_reader_new_stream_handler(reader, event);
624 break;
625 case MESourceStarted:
626 case MESourcePaused:
627 case MESourceStopped:
628 case MESourceSeeked:
629 hr = source_reader_source_state_handler(reader, event_type);
630 break;
631 case MEBufferingStarted:
632 case MEBufferingStopped:
633 case MEConnectStart:
634 case MEConnectEnd:
635 case MEExtendedType:
636 case MESourceCharacteristicsChanged:
637 case MESourceMetadataChanged:
638 case MEContentProtectionMetadata:
639 case MEDeviceThermalStateChanged:
640 if (reader->async_callback)
641 IMFSourceReaderCallback_OnEvent(reader->async_callback, MF_SOURCE_READER_MEDIASOURCE, event);
642 break;
643 default:
647 if (FAILED(hr))
648 WARN("Failed while handling %ld event, hr %#lx.\n", event_type, hr);
650 IMFMediaEvent_Release(event);
652 if (event_type != MESourceStopped)
653 IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
655 return S_OK;
658 static const IMFAsyncCallbackVtbl source_events_callback_vtbl =
660 source_reader_callback_QueryInterface,
661 source_reader_source_events_callback_AddRef,
662 source_reader_source_events_callback_Release,
663 source_reader_callback_GetParameters,
664 source_reader_source_events_callback_Invoke,
667 static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface)
669 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
670 return source_reader_addref(reader);
673 static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface)
675 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
676 return source_reader_release(reader);
679 static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info, IMFSample **out)
681 IMFMediaBuffer *buffer;
682 IMFSample *sample;
683 HRESULT hr;
685 *out = NULL;
686 if (FAILED(hr = MFCreateSample(&sample)))
687 return hr;
688 if (SUCCEEDED(hr = MFCreateAlignedMemoryBuffer(info->cbSize, info->cbAlignment, &buffer)))
690 if (SUCCEEDED(hr = IMFSample_AddBuffer(sample, buffer)))
692 *out = sample;
693 IMFSample_AddRef(sample);
695 IMFMediaBuffer_Release(buffer);
698 IMFSample_Release(sample);
699 return hr;
702 static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const GUID *attr, HRESULT *hr)
704 PROPVARIANT value;
706 PropVariantInit(&value);
707 if (SUCCEEDED(*hr) && FAILED(IMFMediaType_GetItem(dst, attr, NULL))
708 && SUCCEEDED(IMFMediaType_GetItem(src, attr, &value)))
709 *hr = IMFMediaType_SetItem(dst, attr, &value);
710 PropVariantClear(&value);
713 /* update a media type with additional attributes reported by upstream element */
714 /* also present in mf/topology_loader.c pipeline */
715 static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type)
717 HRESULT hr = S_OK;
719 /* propagate common video attributes */
720 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_SIZE, &hr);
721 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_RATE, &hr);
722 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_DEFAULT_STRIDE, &hr);
723 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_ROTATION, &hr);
724 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FIXED_SIZE_SAMPLES, &hr);
725 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_PIXEL_ASPECT_RATIO, &hr);
726 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &hr);
727 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &hr);
729 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_CHROMA_SITING, &hr);
730 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_INTERLACE_MODE, &hr);
731 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_TRANSFER_FUNCTION, &hr);
732 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_PRIMARIES, &hr);
733 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_YUV_MATRIX, &hr);
734 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_LIGHTING, &hr);
735 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_NOMINAL_RANGE, &hr);
737 /* propagate common audio attributes */
738 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_NUM_CHANNELS, &hr);
739 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &hr);
740 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &hr);
741 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &hr);
742 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &hr);
743 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_CHANNEL_MASK, &hr);
744 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &hr);
745 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &hr);
747 return hr;
750 static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream,
751 struct transform_entry *entry);
752 static HRESULT source_reader_push_transform_samples(struct source_reader *reader, struct media_stream *stream,
753 struct transform_entry *entry, IMFSample *sample)
755 HRESULT hr;
759 if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry))
760 && hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
761 return hr;
762 if (SUCCEEDED(hr = IMFTransform_ProcessInput(entry->transform, 0, sample, 0)))
763 return source_reader_pull_transform_samples(reader, stream, entry);
765 while (hr == MF_E_NOTACCEPTING);
767 return hr;
770 static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream,
771 struct transform_entry *entry)
773 MFT_OUTPUT_STREAM_INFO stream_info = {0};
774 struct transform_entry *next = NULL;
775 struct list *ptr;
776 DWORD status;
777 HRESULT hr;
779 if ((ptr = list_next(&stream->transforms, &entry->entry)))
780 next = LIST_ENTRY(ptr, struct transform_entry, entry);
782 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info)))
783 return hr;
784 stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size);
786 while (SUCCEEDED(hr))
788 MFT_OUTPUT_DATA_BUFFER out_buffer = {0};
789 IMFMediaType *output_type, *media_type;
791 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES))
792 && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample)))
793 break;
795 if (SUCCEEDED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status)))
797 if ((entry->pending_flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
798 && SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(entry->transform, 0, &output_type)))
800 if (!next)
801 hr = IMFMediaType_CopyAllItems(output_type, (IMFAttributes *)stream->current);
802 else if (SUCCEEDED(hr = IMFTransform_SetInputType(next->transform, 0, output_type, 0)))
804 /* check if transform output type is still valid or if we need to reset it as well */
805 if (FAILED(hr = IMFTransform_GetOutputCurrentType(next->transform, 0, &media_type))
806 && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(next->transform, 0, 0, &output_type)))
808 next->pending_flags |= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED;
809 hr = IMFTransform_SetOutputType(entry->transform, 0, media_type, 0);
810 IMFMediaType_Release(media_type);
813 IMFMediaType_Release(output_type);
816 if (FAILED(hr))
817 source_reader_queue_response(reader, stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL);
818 else if (next)
819 hr = source_reader_push_transform_samples(reader, stream, next, out_buffer.pSample);
820 else
821 hr = source_reader_queue_sample(reader, stream, entry->pending_flags, out_buffer.pSample);
823 entry->pending_flags = 0;
826 if (hr == MF_E_TRANSFORM_STREAM_CHANGE && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(entry->transform, 0, 0, &output_type)))
828 hr = IMFTransform_SetOutputType(entry->transform, 0, output_type, 0);
829 IMFMediaType_Release(output_type);
831 if (SUCCEEDED(hr))
833 hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info);
834 stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size);
835 entry->pending_flags |= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED;
839 if (out_buffer.pSample)
840 IMFSample_Release(out_buffer.pSample);
841 if (out_buffer.pEvents)
842 IMFCollection_Release(out_buffer.pEvents);
845 return hr;
848 static HRESULT source_reader_drain_transform_samples(struct source_reader *reader, struct media_stream *stream,
849 struct transform_entry *entry)
851 struct transform_entry *next = NULL;
852 struct list *ptr;
853 HRESULT hr;
855 if ((ptr = list_next(&stream->transforms, &entry->entry)))
856 next = LIST_ENTRY(ptr, struct transform_entry, entry);
858 if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
859 WARN("Failed to drain transform %p, hr %#lx\n", entry->transform, hr);
860 if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry))
861 && hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
862 WARN("Failed to pull pending samples, hr %#lx.\n", hr);
864 return next ? source_reader_drain_transform_samples(reader, stream, next) : S_OK;
867 static HRESULT source_reader_flush_transform_samples(struct source_reader *reader, struct media_stream *stream,
868 struct transform_entry *entry)
870 struct transform_entry *next = NULL;
871 struct list *ptr;
872 HRESULT hr;
874 if ((ptr = list_next(&stream->transforms, &entry->entry)))
875 next = LIST_ENTRY(ptr, struct transform_entry, entry);
877 if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_FLUSH, 0)))
878 WARN("Failed to flush transform %p, hr %#lx\n", entry->transform, hr);
880 return next ? source_reader_flush_transform_samples(reader, stream, next) : S_OK;
883 static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream,
884 IMFSample *sample)
886 struct transform_entry *entry;
887 struct list *ptr;
888 HRESULT hr;
890 if (!(ptr = list_head(&stream->transforms)))
891 return source_reader_queue_sample(reader, stream, 0, sample);
892 entry = LIST_ENTRY(ptr, struct transform_entry, entry);
894 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
895 if (SUCCEEDED(hr = source_reader_push_transform_samples(reader, stream, entry, sample))
896 || hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
897 hr = stream->requests ? source_reader_request_sample(reader, stream) : S_OK;
898 else
899 WARN("Transform failed to process output, hr %#lx.\n", hr);
901 return hr;
904 static HRESULT source_reader_media_sample_handler(struct source_reader *reader, IMFMediaStream *stream,
905 IMFMediaEvent *event)
907 IMFSample *sample;
908 unsigned int i;
909 DWORD id = 0;
910 HRESULT hr;
912 TRACE("Got new sample for stream %p.\n", stream);
914 if (FAILED(hr = media_event_get_object(event, &IID_IMFSample, (void **)&sample)))
916 WARN("Failed to get sample object, hr %#lx.\n", hr);
917 return hr;
920 if (FAILED(hr = media_stream_get_id(stream, &id)))
922 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
923 IMFSample_Release(sample);
924 return hr;
927 EnterCriticalSection(&reader->cs);
929 for (i = 0; i < reader->stream_count; ++i)
931 if (id == reader->streams[i].id)
933 /* FIXME: propagate processing errors? */
934 reader->streams[i].flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
935 hr = source_reader_process_sample(reader, &reader->streams[i], sample);
936 break;
940 if (i == reader->stream_count)
941 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id);
943 LeaveCriticalSection(&reader->cs);
945 IMFSample_Release(sample);
947 return hr;
950 static HRESULT source_reader_media_stream_state_handler(struct source_reader *reader, IMFMediaStream *stream,
951 IMFMediaEvent *event)
953 MediaEventType event_type;
954 LONGLONG timestamp;
955 PROPVARIANT value;
956 unsigned int i;
957 HRESULT hr;
958 DWORD id;
960 IMFMediaEvent_GetType(event, &event_type);
962 if (FAILED(hr = media_stream_get_id(stream, &id)))
964 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
965 return hr;
968 EnterCriticalSection(&reader->cs);
970 for (i = 0; i < reader->stream_count; ++i)
972 struct media_stream *stream = &reader->streams[i];
974 if (id == stream->id)
976 switch (event_type)
978 case MEEndOfStream:
980 struct list *ptr;
982 stream->state = STREAM_STATE_EOS;
983 stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
985 if ((ptr = list_head(&stream->transforms)))
987 struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry);
988 if (FAILED(hr = source_reader_drain_transform_samples(reader, stream, entry)))
989 WARN("Failed to drain pending samples, hr %#lx.\n", hr);
992 while (stream->requests)
993 source_reader_queue_response(reader, stream, S_OK, MF_SOURCE_READERF_ENDOFSTREAM, 0, NULL);
995 break;
997 case MEStreamSeeked:
998 case MEStreamStarted:
999 stream->state = STREAM_STATE_READY;
1000 break;
1001 case MEStreamStopped:
1002 stream->flags |= STREAM_FLAG_STOPPED;
1003 break;
1004 case MEStreamTick:
1005 value.vt = VT_EMPTY;
1006 hr = SUCCEEDED(IMFMediaEvent_GetValue(event, &value)) && value.vt == VT_I8 ? S_OK : E_UNEXPECTED;
1007 timestamp = SUCCEEDED(hr) ? value.hVal.QuadPart : 0;
1008 PropVariantClear(&value);
1010 source_reader_queue_response(reader, stream, hr, MF_SOURCE_READERF_STREAMTICK, timestamp, NULL);
1012 break;
1013 default:
1017 break;
1021 LeaveCriticalSection(&reader->cs);
1023 if (event_type == MEStreamStopped)
1024 WakeAllConditionVariable(&reader->stop_event);
1026 return S_OK;
1029 static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1031 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
1032 MediaEventType event_type;
1033 IMFMediaStream *stream;
1034 IMFMediaEvent *event;
1035 HRESULT hr;
1037 TRACE("%p, %p.\n", iface, result);
1039 stream = (IMFMediaStream *)IMFAsyncResult_GetStateNoAddRef(result);
1041 if (FAILED(hr = IMFMediaStream_EndGetEvent(stream, result, &event)))
1042 return hr;
1044 IMFMediaEvent_GetType(event, &event_type);
1046 TRACE("Got event %lu.\n", event_type);
1048 switch (event_type)
1050 case MEMediaSample:
1051 hr = source_reader_media_sample_handler(reader, stream, event);
1052 break;
1053 case MEStreamSeeked:
1054 case MEStreamStarted:
1055 case MEStreamStopped:
1056 case MEStreamTick:
1057 case MEEndOfStream:
1058 hr = source_reader_media_stream_state_handler(reader, stream, event);
1059 break;
1060 default:
1064 if (FAILED(hr))
1065 WARN("Failed while handling %ld event, hr %#lx.\n", event_type, hr);
1067 IMFMediaEvent_Release(event);
1069 if (event_type != MEStreamStopped)
1070 IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
1072 return S_OK;
1075 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl =
1077 source_reader_callback_QueryInterface,
1078 source_reader_stream_events_callback_AddRef,
1079 source_reader_stream_events_callback_Release,
1080 source_reader_callback_GetParameters,
1081 source_reader_stream_events_callback_Invoke,
1084 static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface)
1086 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1087 return source_reader_addref(reader);
1090 static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface)
1092 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1093 return source_reader_release(reader);
1096 static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response)
1098 struct media_stream *stream;
1100 list_remove(&response->entry);
1102 if (response->stream_index < reader->stream_count)
1104 stream = &reader->streams[response->stream_index];
1105 if (stream->responses)
1106 --stream->responses;
1109 return response;
1112 static struct stream_response *media_stream_pop_response(struct source_reader *reader, struct media_stream *stream)
1114 struct stream_response *response;
1115 IMFSample *sample;
1116 HRESULT hr;
1118 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
1120 if (stream && response->stream_index != stream->index)
1121 continue;
1123 if (!stream) stream = &reader->streams[response->stream_index];
1125 if (response->sample && stream->allocator)
1127 /* Return allocation error to the caller, while keeping original response sample in for later. */
1128 if (SUCCEEDED(hr = IMFVideoSampleAllocatorEx_AllocateSample(stream->allocator, &sample)))
1130 source_reader_copy_sample_buffer(response->sample, sample);
1131 IMFSample_Release(response->sample);
1132 response->sample = sample;
1134 else
1136 if (!(response = calloc(1, sizeof(*response))))
1137 return NULL;
1139 response->status = hr;
1140 response->stream_flags = MF_SOURCE_READERF_ERROR;
1141 return response;
1145 return media_stream_detach_response(reader, response);
1148 return NULL;
1151 static void source_reader_release_response(struct stream_response *response)
1153 if (response->sample)
1154 IMFSample_Release(response->sample);
1155 free(response);
1158 static HRESULT source_reader_get_stream_selection(const struct source_reader *reader, DWORD index, BOOL *selected)
1160 IMFStreamDescriptor *sd;
1162 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, selected, &sd)))
1163 return MF_E_INVALIDSTREAMNUMBER;
1164 IMFStreamDescriptor_Release(sd);
1166 return S_OK;
1169 static HRESULT source_reader_start_source(struct source_reader *reader)
1171 BOOL selected, selection_changed = FALSE;
1172 PROPVARIANT position;
1173 HRESULT hr = S_OK;
1174 unsigned int i;
1176 for (i = 0; i < reader->stream_count; ++i)
1178 source_reader_get_stream_selection(reader, i, &selected);
1179 if (selected)
1180 reader->streams[i].flags |= STREAM_FLAG_SELECTED;
1181 else
1182 reader->streams[i].flags &= ~STREAM_FLAG_SELECTED;
1185 if (reader->source_state == SOURCE_STATE_STARTED)
1187 for (i = 0; i < reader->stream_count; ++i)
1189 selection_changed = !!(reader->streams[i].flags & STREAM_FLAG_SELECTED) ^
1190 !!(reader->streams[i].flags & STREAM_FLAG_PRESENTED);
1191 if (selection_changed)
1192 break;
1196 position.hVal.QuadPart = 0;
1197 if (reader->source_state != SOURCE_STATE_STARTED || selection_changed)
1199 position.vt = reader->source_state == SOURCE_STATE_STARTED ? VT_EMPTY : VT_I8;
1201 /* Update cached stream selection if descriptor was accepted. */
1202 if (SUCCEEDED(hr = IMFMediaSource_Start(reader->source, reader->descriptor, &GUID_NULL, &position)))
1204 for (i = 0; i < reader->stream_count; ++i)
1206 if (reader->streams[i].flags & STREAM_FLAG_SELECTED)
1207 reader->streams[i].flags |= STREAM_FLAG_PRESENTED;
1212 return hr;
1215 static BOOL source_reader_got_response_for_stream(struct source_reader *reader, struct media_stream *stream)
1217 struct stream_response *response;
1219 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
1221 if (response->stream_index == stream->index)
1222 return TRUE;
1225 return FALSE;
1228 static BOOL source_reader_get_read_result(struct source_reader *reader, struct media_stream *stream, DWORD flags,
1229 HRESULT *status, DWORD *stream_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1231 struct stream_response *response = NULL;
1232 BOOL request_sample = FALSE;
1234 if ((response = media_stream_pop_response(reader, stream)))
1236 *status = response->status;
1237 *stream_index = stream->index;
1238 *stream_flags = response->stream_flags;
1239 *timestamp = response->timestamp;
1240 *sample = response->sample;
1241 if (*sample)
1242 IMFSample_AddRef(*sample);
1244 source_reader_release_response(response);
1246 else
1248 *status = S_OK;
1249 *stream_index = stream->index;
1250 *timestamp = 0;
1251 *sample = NULL;
1253 if (stream->state == STREAM_STATE_EOS)
1255 *stream_flags = MF_SOURCE_READERF_ENDOFSTREAM;
1257 else
1259 request_sample = !(flags & MF_SOURCE_READER_CONTROLF_DRAIN);
1260 *stream_flags = 0;
1264 return !request_sample;
1267 static HRESULT source_reader_get_next_selected_stream(struct source_reader *reader, DWORD *stream_index)
1269 unsigned int i, first_selected = ~0u;
1270 BOOL selected, stream_drained;
1271 LONGLONG min_ts = MAXLONGLONG;
1273 for (i = 0; i < reader->stream_count; ++i)
1275 stream_drained = reader->streams[i].state == STREAM_STATE_EOS && !reader->streams[i].responses;
1276 selected = SUCCEEDED(source_reader_get_stream_selection(reader, i, &selected)) && selected;
1278 if (selected)
1280 if (first_selected == ~0u)
1281 first_selected = i;
1283 /* Pick the stream whose last sample had the lowest timestamp. */
1284 if (!stream_drained && reader->streams[i].last_sample_ts < min_ts)
1286 min_ts = reader->streams[i].last_sample_ts;
1287 *stream_index = i;
1292 /* If all selected streams reached EOS, use first selected. */
1293 if (first_selected != ~0u)
1295 if (min_ts == MAXLONGLONG)
1296 *stream_index = first_selected;
1299 return first_selected == ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED : S_OK;
1302 static HRESULT source_reader_get_stream_read_index(struct source_reader *reader, unsigned int index, DWORD *stream_index)
1304 BOOL selected;
1305 HRESULT hr;
1307 switch (index)
1309 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1310 *stream_index = reader->first_video_stream_index;
1311 break;
1312 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1313 *stream_index = reader->first_audio_stream_index;
1314 break;
1315 case MF_SOURCE_READER_ANY_STREAM:
1316 return source_reader_get_next_selected_stream(reader, stream_index);
1317 default:
1318 *stream_index = index;
1321 /* Can't read from deselected streams. */
1322 if (SUCCEEDED(hr = source_reader_get_stream_selection(reader, *stream_index, &selected)) && !selected)
1323 hr = MF_E_INVALIDREQUEST;
1325 return hr;
1328 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream)
1330 struct stream_response *ptr, *next;
1332 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &reader->responses, struct stream_response, entry)
1334 if (stream && stream->index != ptr->stream_index &&
1335 ptr->stream_index != MF_SOURCE_READER_FIRST_VIDEO_STREAM &&
1336 ptr->stream_index != MF_SOURCE_READER_FIRST_AUDIO_STREAM &&
1337 ptr->stream_index != MF_SOURCE_READER_ANY_STREAM)
1339 continue;
1341 media_stream_detach_response(reader, ptr);
1342 source_reader_release_response(ptr);
1346 static void source_reader_flush_stream(struct source_reader *reader, DWORD stream_index)
1348 struct media_stream *stream = &reader->streams[stream_index];
1349 struct list *ptr;
1350 HRESULT hr;
1352 source_reader_release_responses(reader, stream);
1354 if ((ptr = list_head(&stream->transforms)))
1356 struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry);
1357 if (FAILED(hr = source_reader_flush_transform_samples(reader, stream, entry)))
1358 WARN("Failed to drain pending samples, hr %#lx.\n", hr);
1361 stream->requests = 0;
1364 static HRESULT source_reader_flush(struct source_reader *reader, unsigned int index)
1366 unsigned int stream_index;
1367 HRESULT hr = S_OK;
1369 if (index == MF_SOURCE_READER_ALL_STREAMS)
1371 for (stream_index = 0; stream_index < reader->stream_count; ++stream_index)
1372 source_reader_flush_stream(reader, stream_index);
1374 else
1376 switch (index)
1378 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1379 stream_index = reader->first_video_stream_index;
1380 break;
1381 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1382 stream_index = reader->first_audio_stream_index;
1383 break;
1384 default:
1385 stream_index = index;
1388 if (stream_index < reader->stream_count)
1389 source_reader_flush_stream(reader, stream_index);
1390 else
1391 hr = MF_E_INVALIDSTREAMNUMBER;
1394 return hr;
1397 static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1399 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1400 struct media_stream *stream, stub_stream = { .requests = 1 };
1401 struct source_reader_async_command *command;
1402 struct stream_response *response;
1403 DWORD stream_index, stream_flags;
1404 BOOL report_sample = FALSE;
1405 IMFSample *sample = NULL;
1406 LONGLONG timestamp = 0;
1407 HRESULT hr, status;
1408 IUnknown *state;
1410 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
1411 return hr;
1413 command = impl_from_async_command_IUnknown(state);
1415 switch (command->op)
1417 case SOURCE_READER_ASYNC_READ:
1418 EnterCriticalSection(&reader->cs);
1420 if (SUCCEEDED(hr = source_reader_start_source(reader)))
1422 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, command->u.read.stream_index, &stream_index)))
1424 stream = &reader->streams[stream_index];
1426 if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status,
1427 &stream_index, &stream_flags, &timestamp, &sample)))
1429 stream->requests++;
1430 source_reader_request_sample(reader, stream);
1431 /* FIXME: set error stream/reader state on request failure */
1434 else
1436 stub_stream.index = command->u.read.stream_index;
1437 source_reader_queue_response(reader, &stub_stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL);
1441 LeaveCriticalSection(&reader->cs);
1443 if (report_sample)
1444 IMFSourceReaderCallback_OnReadSample(reader->async_callback, status, stream_index, stream_flags,
1445 timestamp, sample);
1447 if (sample)
1448 IMFSample_Release(sample);
1450 break;
1452 case SOURCE_READER_ASYNC_SEEK:
1454 EnterCriticalSection(&reader->cs);
1455 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, &command->u.seek.format,
1456 &command->u.seek.position)))
1458 reader->flags |= SOURCE_READER_SEEKING;
1460 LeaveCriticalSection(&reader->cs);
1462 break;
1464 case SOURCE_READER_ASYNC_SAMPLE_READY:
1466 EnterCriticalSection(&reader->cs);
1467 response = media_stream_pop_response(reader, NULL);
1468 LeaveCriticalSection(&reader->cs);
1470 if (response)
1472 IMFSourceReaderCallback_OnReadSample(reader->async_callback, response->status, response->stream_index,
1473 response->stream_flags, response->timestamp, response->sample);
1474 source_reader_release_response(response);
1477 break;
1478 case SOURCE_READER_ASYNC_FLUSH:
1479 EnterCriticalSection(&reader->cs);
1480 source_reader_flush(reader, command->u.flush.stream_index);
1481 reader->flags &= ~SOURCE_READER_FLUSHING;
1482 LeaveCriticalSection(&reader->cs);
1484 IMFSourceReaderCallback_OnFlush(reader->async_callback, command->u.flush.stream_index);
1485 break;
1486 default:
1490 IUnknown_Release(state);
1492 return S_OK;
1495 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl =
1497 source_reader_callback_QueryInterface,
1498 source_reader_async_commands_callback_AddRef,
1499 source_reader_async_commands_callback_Release,
1500 source_reader_callback_GetParameters,
1501 source_reader_async_commands_callback_Invoke,
1504 static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReaderEx *iface, REFIID riid, void **out)
1506 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1508 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1510 if (IsEqualGUID(riid, &IID_IUnknown)
1511 || IsEqualGUID(riid, &IID_IMFSourceReader)
1512 || IsEqualGUID(riid, &IID_IMFSourceReaderEx))
1514 *out = &reader->IMFSourceReaderEx_iface;
1516 else
1518 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
1519 *out = NULL;
1520 return E_NOINTERFACE;
1523 IUnknown_AddRef((IUnknown*)*out);
1524 return S_OK;
1527 static ULONG WINAPI src_reader_AddRef(IMFSourceReaderEx *iface)
1529 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1530 ULONG refcount = InterlockedIncrement(&reader->public_refcount);
1532 TRACE("%p, refcount %lu.\n", iface, refcount);
1534 return refcount;
1537 static BOOL source_reader_is_source_stopped(const struct source_reader *reader)
1539 unsigned int i;
1541 if (reader->source_state != SOURCE_STATE_STOPPED)
1542 return FALSE;
1544 for (i = 0; i < reader->stream_count; ++i)
1546 if (reader->streams[i].stream && !(reader->streams[i].flags & STREAM_FLAG_STOPPED))
1547 return FALSE;
1550 return TRUE;
1553 static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface)
1555 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1556 ULONG refcount = InterlockedDecrement(&reader->public_refcount);
1557 unsigned int i;
1559 TRACE("%p, refcount %lu.\n", iface, refcount);
1561 if (!refcount)
1563 if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE)
1564 IMFMediaSource_Shutdown(reader->source);
1565 else if (SUCCEEDED(IMFMediaSource_Stop(reader->source)))
1567 EnterCriticalSection(&reader->cs);
1569 while (!source_reader_is_source_stopped(reader))
1571 SleepConditionVariableCS(&reader->stop_event, &reader->cs, INFINITE);
1574 LeaveCriticalSection(&reader->cs);
1577 for (i = 0; i < reader->stream_count; ++i)
1579 struct media_stream *stream = &reader->streams[i];
1580 IMFVideoSampleAllocatorCallback *callback;
1582 if (!stream->allocator)
1583 continue;
1585 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream->allocator, &IID_IMFVideoSampleAllocatorCallback,
1586 (void **)&callback)))
1588 IMFVideoSampleAllocatorCallback_SetCallback(callback, NULL);
1589 IMFVideoSampleAllocatorCallback_Release(callback);
1593 source_reader_release(reader);
1596 return refcount;
1599 static HRESULT WINAPI src_reader_GetStreamSelection(IMFSourceReaderEx *iface, DWORD index, BOOL *selected)
1601 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1603 TRACE("%p, %#lx, %p.\n", iface, index, selected);
1605 switch (index)
1607 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1608 index = reader->first_video_stream_index;
1609 break;
1610 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1611 index = reader->first_audio_stream_index;
1612 break;
1613 default:
1617 return source_reader_get_stream_selection(reader, index, selected);
1620 static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReaderEx *iface, DWORD index, BOOL selection)
1622 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1623 HRESULT hr = S_OK;
1624 BOOL selection_changed = FALSE, selected;
1625 unsigned int i;
1627 TRACE("%p, %#lx, %d.\n", iface, index, selection);
1629 selection = !!selection;
1631 EnterCriticalSection(&reader->cs);
1633 if (index == MF_SOURCE_READER_ALL_STREAMS)
1635 for (i = 0; i < reader->stream_count; ++i)
1637 if (!selection_changed)
1639 source_reader_get_stream_selection(reader, i, &selected);
1640 selection_changed = !!(selected ^ selection);
1643 if (selection)
1644 IMFPresentationDescriptor_SelectStream(reader->descriptor, i);
1645 else
1646 IMFPresentationDescriptor_DeselectStream(reader->descriptor, i);
1649 else
1651 switch (index)
1653 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1654 index = reader->first_video_stream_index;
1655 break;
1656 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1657 index = reader->first_audio_stream_index;
1658 break;
1659 default:
1663 source_reader_get_stream_selection(reader, index, &selected);
1664 selection_changed = !!(selected ^ selection);
1666 if (selection)
1667 hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
1668 else
1669 hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
1672 if (selection_changed)
1674 for (i = 0; i < reader->stream_count; ++i)
1676 reader->streams[i].last_sample_ts = 0;
1680 LeaveCriticalSection(&reader->cs);
1682 return SUCCEEDED(hr) ? S_OK : MF_E_INVALIDSTREAMNUMBER;
1685 static HRESULT source_reader_get_native_media_type(struct source_reader *reader, DWORD index, DWORD type_index,
1686 IMFMediaType **type)
1688 IMFMediaTypeHandler *handler;
1689 IMFStreamDescriptor *sd;
1690 IMFMediaType *src_type;
1691 BOOL selected;
1692 HRESULT hr;
1694 switch (index)
1696 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1697 index = reader->first_video_stream_index;
1698 break;
1699 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1700 index = reader->first_audio_stream_index;
1701 break;
1702 default:
1706 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1707 return MF_E_INVALIDSTREAMNUMBER;
1709 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
1710 IMFStreamDescriptor_Release(sd);
1711 if (FAILED(hr))
1712 return hr;
1714 if (type_index == MF_SOURCE_READER_CURRENT_TYPE_INDEX)
1715 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &src_type);
1716 else
1717 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, type_index, &src_type);
1718 IMFMediaTypeHandler_Release(handler);
1720 if (SUCCEEDED(hr))
1722 if (SUCCEEDED(hr = MFCreateMediaType(type)))
1723 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)*type);
1724 IMFMediaType_Release(src_type);
1727 return hr;
1730 static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReaderEx *iface, DWORD index, DWORD type_index,
1731 IMFMediaType **type)
1733 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1735 TRACE("%p, %#lx, %#lx, %p.\n", iface, index, type_index, type);
1737 return source_reader_get_native_media_type(reader, index, type_index, type);
1740 static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReaderEx *iface, DWORD index, IMFMediaType **type)
1742 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1743 HRESULT hr;
1745 TRACE("%p, %#lx, %p.\n", iface, index, type);
1747 switch (index)
1749 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1750 index = reader->first_video_stream_index;
1751 break;
1752 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1753 index = reader->first_audio_stream_index;
1754 break;
1755 default:
1759 if (index >= reader->stream_count)
1760 return MF_E_INVALIDSTREAMNUMBER;
1762 if (FAILED(hr = MFCreateMediaType(type)))
1763 return hr;
1765 EnterCriticalSection(&reader->cs);
1767 hr = IMFMediaType_CopyAllItems(reader->streams[index].current, (IMFAttributes *)*type);
1769 LeaveCriticalSection(&reader->cs);
1771 return hr;
1774 static HRESULT source_reader_get_source_type_handler(struct source_reader *reader, DWORD index,
1775 IMFMediaTypeHandler **handler)
1777 IMFStreamDescriptor *sd;
1778 BOOL selected;
1779 HRESULT hr;
1781 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1782 return hr;
1784 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, handler);
1785 IMFStreamDescriptor_Release(sd);
1787 return hr;
1790 static HRESULT source_reader_set_compatible_media_type(struct source_reader *reader, DWORD index, IMFMediaType *type)
1792 struct media_stream *stream = &reader->streams[index];
1793 struct transform_entry *entry, *next;
1794 IMFMediaTypeHandler *type_handler;
1795 IMFMediaType *native_type;
1796 BOOL type_set = FALSE;
1797 unsigned int i = 0;
1798 DWORD flags;
1799 HRESULT hr;
1801 if (FAILED(hr = IMFMediaType_IsEqual(type, stream->current, &flags)))
1802 return hr;
1804 if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES))
1805 return MF_E_INVALIDMEDIATYPE;
1807 /* No need for a decoder or type change. */
1808 if (flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)
1809 return S_OK;
1811 if (stream->transform_service)
1813 IMFTransform_Release(stream->transform_service);
1814 stream->transform_service = NULL;
1816 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry)
1818 list_remove(&entry->entry);
1819 transform_entry_destroy(entry);
1822 if (FAILED(hr = source_reader_get_source_type_handler(reader, index, &type_handler)))
1823 return hr;
1825 while (!type_set && IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, i++, &native_type) == S_OK)
1827 static const DWORD compare_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_DATA;
1829 if (SUCCEEDED(IMFMediaType_IsEqual(native_type, type, &flags)) && (flags & compare_flags) == compare_flags)
1831 if ((type_set = SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler, native_type))))
1832 IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)stream->current);
1835 IMFMediaType_Release(native_type);
1838 IMFMediaTypeHandler_Release(type_handler);
1840 return type_set ? S_OK : S_FALSE;
1843 static HRESULT source_reader_create_sample_allocator_attributes(const struct source_reader *reader,
1844 IMFAttributes **attributes)
1846 UINT32 shared = 0, shared_without_mutex = 0;
1847 HRESULT hr;
1849 if (FAILED(hr = MFCreateAttributes(attributes, 1)))
1850 return hr;
1852 IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared);
1853 IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex);
1855 if (shared_without_mutex)
1856 hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE);
1857 else if (shared)
1858 hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED, TRUE);
1860 return hr;
1863 static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index)
1865 struct media_stream *stream = &reader->streams[index];
1866 IMFAttributes *attributes = NULL;
1867 GUID major = { 0 };
1868 HRESULT hr;
1870 IMFMediaType_GetMajorType(stream->current, &major);
1871 if (!IsEqualGUID(&major, &MFMediaType_Video))
1872 return S_OK;
1874 if (!(reader->flags & SOURCE_READER_HAS_DEVICE_MANAGER))
1875 return S_OK;
1877 if (!stream->allocator)
1879 if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&stream->allocator)))
1881 WARN("Failed to create sample allocator, hr %#lx.\n", hr);
1882 return hr;
1886 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream->allocator);
1887 if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(stream->allocator, reader->device_manager)))
1889 WARN("Failed to set device manager, hr %#lx.\n", hr);
1890 return hr;
1893 if (FAILED(hr = source_reader_create_sample_allocator_attributes(reader, &attributes)))
1894 WARN("Failed to create allocator attributes, hr %#lx.\n", hr);
1896 if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8,
1897 attributes, stream->current)))
1899 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr);
1902 if (attributes)
1903 IMFAttributes_Release(attributes);
1905 return hr;
1908 static BOOL source_reader_allow_video_processor(struct source_reader *reader, BOOL *advanced)
1910 UINT32 value;
1912 *advanced = FALSE;
1913 if (!reader->attributes)
1914 return FALSE;
1916 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, &value)))
1917 *advanced = value;
1918 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, &value)))
1919 return value || *advanced;
1921 return *advanced;
1924 static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL decoder, BOOL allow_processor,
1925 IMFMediaType *input_type, IMFMediaType *output_type, struct transform_entry **out)
1927 MFT_REGISTER_TYPE_INFO in_type, out_type;
1928 struct transform_entry *entry;
1929 IMFActivate **activates;
1930 GUID category;
1931 IMFTransform *transform;
1932 UINT i, count;
1933 HRESULT hr;
1935 if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &in_type.guidMajorType))
1936 || FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype)))
1937 return hr;
1938 if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType))
1939 || FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype)))
1940 return hr;
1942 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video))
1943 category = decoder ? MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_PROCESSOR;
1944 else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio))
1945 category = decoder ? MFT_CATEGORY_AUDIO_DECODER : MFT_CATEGORY_AUDIO_EFFECT;
1946 else
1947 return MF_E_TOPO_CODEC_NOT_FOUND;
1949 if (!(entry = calloc(1, sizeof(*entry))))
1950 return E_OUTOFMEMORY;
1951 list_init(&entry->entry);
1952 entry->category = category;
1954 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)
1955 && SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size)))
1957 UINT32 bytes_per_second;
1959 if (SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second)))
1960 entry->min_buffer_size = max(entry->min_buffer_size, bytes_per_second);
1963 count = 0;
1964 if (SUCCEEDED(hr = MFTEnumEx(category, 0, &in_type, allow_processor ? NULL : &out_type, &activates, &count)))
1966 if (!count)
1968 free(entry);
1969 return MF_E_TOPO_CODEC_NOT_FOUND;
1972 for (i = 0; i < count; i++)
1974 IMFMediaType *media_type;
1976 if (FAILED(IMFActivate_ActivateObject(activates[i], &IID_IMFTransform, (void **)&transform)))
1977 continue;
1978 if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0))
1979 && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type)))
1981 if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type))
1982 && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0)) && allow_processor
1983 && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type)))
1985 struct transform_entry *converter;
1987 if (SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0))
1988 && SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type))
1989 && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, media_type, output_type, &converter)))
1990 list_add_tail(&entry->entry, &converter->entry);
1992 IMFMediaType_Release(media_type);
1995 if (SUCCEEDED(hr))
1997 entry->transform = transform;
1998 *out = entry;
1999 break;
2003 IMFTransform_Release(transform);
2006 for (i = 0; i < count; ++i)
2007 IMFActivate_Release(activates[i]);
2008 CoTaskMemFree(activates);
2011 if (FAILED(hr))
2012 free(entry);
2013 return hr;
2016 static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type)
2018 BOOL enable_advanced, allow_processor;
2019 struct media_stream *stream = &reader->streams[index];
2020 IMFMediaType *input_type;
2021 unsigned int i = 0;
2022 HRESULT hr;
2024 allow_processor = source_reader_allow_video_processor(reader, &enable_advanced);
2026 while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type)))
2028 struct transform_entry *entry;
2030 /* first, try to append a single processor, then try again with a decoder and a processor */
2031 if ((allow_processor && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, input_type, output_type, &entry)))
2032 || SUCCEEDED(hr = source_reader_create_transform(reader, TRUE, allow_processor, input_type, output_type, &entry)))
2034 struct list *ptr = list_head(&entry->entry);
2035 struct transform_entry *service = ptr ? LIST_ENTRY(ptr, struct transform_entry, entry) : entry;
2036 IMFMediaTypeHandler *type_handler;
2038 if (enable_advanced)
2040 /* when advanced video processing is enabled, converters are exposed as stream transform service */
2041 stream->transform_service = service->transform;
2042 IMFTransform_AddRef(stream->transform_service);
2044 else
2046 /* when advanced video processing is disabled, only decoders are exposed as stream transform service */
2047 if (IsEqualGUID(&entry->category, &MFT_CATEGORY_AUDIO_DECODER)
2048 || IsEqualGUID(&entry->category, &MFT_CATEGORY_VIDEO_DECODER))
2050 stream->transform_service = entry->transform;
2051 IMFTransform_AddRef(stream->transform_service);
2053 /* converters are hidden from the stream transforms */
2054 if (service != entry)
2055 service->hidden = TRUE;
2057 else
2059 /* converters are hidden from the stream transforms */
2060 entry->hidden = TRUE;
2064 /* move any additional transforms that have been created */
2065 list_move_head(&stream->transforms, &entry->entry);
2066 list_add_head(&stream->transforms, &entry->entry);
2068 if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler)))
2070 if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type)))
2071 WARN("Failed to set current input media type, hr %#lx\n", hr);
2072 IMFMediaTypeHandler_Release(type_handler);
2075 if (FAILED(hr = IMFTransform_GetOutputCurrentType(service->transform, 0, &output_type)))
2076 WARN("Failed to get decoder output media type, hr %#lx\n", hr);
2077 else
2079 IMFMediaType_CopyAllItems(output_type, (IMFAttributes *)stream->current);
2080 IMFMediaType_Release(output_type);
2083 IMFMediaType_Release(input_type);
2084 return S_OK;
2087 IMFMediaType_Release(input_type);
2090 return MF_E_TOPO_CODEC_NOT_FOUND;
2093 static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, DWORD index, DWORD *reserved,
2094 IMFMediaType *type)
2096 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2097 HRESULT hr;
2099 TRACE("%p, %#lx, %p, %p.\n", iface, index, reserved, type);
2101 switch (index)
2103 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2104 index = reader->first_video_stream_index;
2105 break;
2106 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2107 index = reader->first_audio_stream_index;
2108 break;
2109 default:
2113 if (index >= reader->stream_count)
2114 return MF_E_INVALIDSTREAMNUMBER;
2116 /* FIXME: setting the output type while streaming should trigger a flush */
2118 EnterCriticalSection(&reader->cs);
2120 hr = source_reader_set_compatible_media_type(reader, index, type);
2121 if (hr == S_FALSE)
2122 hr = source_reader_create_decoder_for_stream(reader, index, type);
2123 if (SUCCEEDED(hr))
2124 hr = source_reader_setup_sample_allocator(reader, index);
2126 LeaveCriticalSection(&reader->cs);
2128 return hr;
2131 static HRESULT WINAPI src_reader_SetCurrentPosition(IMFSourceReaderEx *iface, REFGUID format, REFPROPVARIANT position)
2133 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2134 struct source_reader_async_command *command;
2135 unsigned int i;
2136 DWORD flags;
2137 HRESULT hr;
2139 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), position);
2141 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
2142 return hr;
2144 if (!(flags & MFMEDIASOURCE_CAN_SEEK))
2145 return MF_E_INVALIDREQUEST;
2147 EnterCriticalSection(&reader->cs);
2149 /* Check if we got pending requests. */
2150 for (i = 0; i < reader->stream_count; ++i)
2152 if (reader->streams[i].requests)
2154 hr = MF_E_INVALIDREQUEST;
2155 break;
2159 if (SUCCEEDED(hr))
2161 for (i = 0; i < reader->stream_count; ++i)
2163 reader->streams[i].last_sample_ts = 0;
2166 if (reader->async_callback)
2168 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK, &command)))
2170 command->u.seek.format = *format;
2171 PropVariantCopy(&command->u.seek.position, position);
2173 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2174 IUnknown_Release(&command->IUnknown_iface);
2177 else
2179 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, format, position)))
2181 reader->flags |= SOURCE_READER_SEEKING;
2182 while (reader->flags & SOURCE_READER_SEEKING)
2184 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
2190 LeaveCriticalSection(&reader->cs);
2192 return hr;
2195 static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD index, DWORD flags, DWORD *actual_index,
2196 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2198 struct media_stream *stream;
2199 DWORD actual_index_tmp;
2200 LONGLONG timestamp_tmp;
2201 DWORD stream_index;
2202 HRESULT hr = S_OK;
2204 if (!stream_flags || !sample)
2205 return E_POINTER;
2207 *sample = NULL;
2209 if (!timestamp)
2210 timestamp = &timestamp_tmp;
2212 if (!actual_index)
2213 actual_index = &actual_index_tmp;
2215 if (SUCCEEDED(hr = source_reader_start_source(reader)))
2217 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, index, &stream_index)))
2219 *actual_index = stream_index;
2221 stream = &reader->streams[stream_index];
2223 if (!source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
2224 timestamp, sample))
2226 while (!source_reader_got_response_for_stream(reader, stream) && stream->state != STREAM_STATE_EOS)
2228 stream->requests++;
2229 if (FAILED(hr = source_reader_request_sample(reader, stream)))
2230 WARN("Failed to request a sample, hr %#lx.\n", hr);
2231 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
2233 *stream_flags = MF_SOURCE_READERF_ERROR;
2234 *timestamp = 0;
2235 break;
2237 SleepConditionVariableCS(&reader->sample_event, &reader->cs, INFINITE);
2239 if (SUCCEEDED(hr))
2240 source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
2241 timestamp, sample);
2244 else
2246 *actual_index = index;
2247 *stream_flags = MF_SOURCE_READERF_ERROR;
2248 *timestamp = 0;
2252 TRACE("Stream %lu, got sample %p, flags %#lx.\n", *actual_index, *sample, *stream_flags);
2254 return hr;
2257 static HRESULT source_reader_read_sample_async(struct source_reader *reader, unsigned int index, unsigned int flags,
2258 DWORD *actual_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2260 struct source_reader_async_command *command;
2261 HRESULT hr;
2263 if (actual_index || stream_flags || timestamp || sample)
2264 return E_INVALIDARG;
2266 if (reader->flags & SOURCE_READER_FLUSHING)
2267 hr = MF_E_NOTACCEPTING;
2268 else
2270 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_READ, &command)))
2272 command->u.read.stream_index = index;
2273 command->u.read.flags = flags;
2275 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2276 IUnknown_Release(&command->IUnknown_iface);
2280 return hr;
2283 static HRESULT WINAPI src_reader_ReadSample(IMFSourceReaderEx *iface, DWORD index, DWORD flags, DWORD *actual_index,
2284 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2286 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2287 HRESULT hr;
2289 TRACE("%p, %#lx, %#lx, %p, %p, %p, %p\n", iface, index, flags, actual_index, stream_flags, timestamp, sample);
2291 EnterCriticalSection(&reader->cs);
2293 while (reader->flags & SOURCE_READER_SEEKING)
2295 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
2298 if (reader->async_callback)
2299 hr = source_reader_read_sample_async(reader, index, flags, actual_index, stream_flags, timestamp, sample);
2300 else
2301 hr = source_reader_read_sample(reader, index, flags, actual_index, stream_flags, timestamp, sample);
2303 LeaveCriticalSection(&reader->cs);
2305 return hr;
2308 static HRESULT source_reader_flush_async(struct source_reader *reader, unsigned int index)
2310 struct source_reader_async_command *command;
2311 unsigned int stream_index;
2312 HRESULT hr;
2314 if (reader->flags & SOURCE_READER_FLUSHING)
2315 return MF_E_INVALIDREQUEST;
2317 switch (index)
2319 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2320 stream_index = reader->first_video_stream_index;
2321 break;
2322 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2323 stream_index = reader->first_audio_stream_index;
2324 break;
2325 default:
2326 stream_index = index;
2329 reader->flags |= SOURCE_READER_FLUSHING;
2331 if (stream_index != MF_SOURCE_READER_ALL_STREAMS && stream_index >= reader->stream_count)
2332 return MF_E_INVALIDSTREAMNUMBER;
2334 if (FAILED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH, &command)))
2335 return hr;
2337 command->u.flush.stream_index = stream_index;
2339 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2340 IUnknown_Release(&command->IUnknown_iface);
2342 return hr;
2345 static HRESULT WINAPI src_reader_Flush(IMFSourceReaderEx *iface, DWORD index)
2347 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2348 HRESULT hr;
2350 TRACE("%p, %#lx.\n", iface, index);
2352 EnterCriticalSection(&reader->cs);
2354 if (reader->async_callback)
2355 hr = source_reader_flush_async(reader, index);
2356 else
2357 hr = source_reader_flush(reader, index);
2359 LeaveCriticalSection(&reader->cs);
2361 return hr;
2364 static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, DWORD index, REFGUID service,
2365 REFIID riid, void **object)
2367 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2368 struct media_stream *stream = &reader->streams[index];
2369 IUnknown *obj = NULL;
2370 HRESULT hr = S_OK;
2372 TRACE("%p, %#lx, %s, %s, %p\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object);
2374 EnterCriticalSection(&reader->cs);
2376 switch (index)
2378 case MF_SOURCE_READER_MEDIASOURCE:
2379 obj = (IUnknown *)reader->source;
2380 break;
2381 default:
2382 if (index == MF_SOURCE_READER_FIRST_VIDEO_STREAM)
2383 index = reader->first_video_stream_index;
2384 else if (index == MF_SOURCE_READER_FIRST_AUDIO_STREAM)
2385 index = reader->first_audio_stream_index;
2387 if (index >= reader->stream_count)
2388 hr = MF_E_INVALIDSTREAMNUMBER;
2389 else if (!(obj = (IUnknown *)stream->transform_service))
2390 hr = E_NOINTERFACE;
2391 break;
2394 if (obj)
2395 IUnknown_AddRef(obj);
2397 LeaveCriticalSection(&reader->cs);
2399 if (obj)
2401 if (IsEqualGUID(service, &GUID_NULL))
2403 hr = IUnknown_QueryInterface(obj, riid, object);
2405 else
2407 IMFGetService *gs;
2409 hr = IUnknown_QueryInterface(obj, &IID_IMFGetService, (void **)&gs);
2410 if (SUCCEEDED(hr))
2412 hr = IMFGetService_GetService(gs, service, riid, object);
2413 IMFGetService_Release(gs);
2418 if (obj)
2419 IUnknown_Release(obj);
2421 return hr;
2424 static HRESULT WINAPI src_reader_GetPresentationAttribute(IMFSourceReaderEx *iface, DWORD index,
2425 REFGUID guid, PROPVARIANT *value)
2427 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2428 IMFStreamDescriptor *sd;
2429 BOOL selected;
2430 HRESULT hr;
2432 TRACE("%p, %#lx, %s, %p.\n", iface, index, debugstr_guid(guid), value);
2434 switch (index)
2436 case MF_SOURCE_READER_MEDIASOURCE:
2437 if (IsEqualGUID(guid, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS))
2439 DWORD flags;
2441 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
2442 return hr;
2444 value->vt = VT_UI4;
2445 value->ulVal = flags;
2446 return S_OK;
2448 else
2450 return IMFPresentationDescriptor_GetItem(reader->descriptor, guid, value);
2452 break;
2453 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2454 index = reader->first_video_stream_index;
2455 break;
2456 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2457 index = reader->first_audio_stream_index;
2458 break;
2459 default:
2463 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
2464 return hr;
2466 hr = IMFStreamDescriptor_GetItem(sd, guid, value);
2467 IMFStreamDescriptor_Release(sd);
2469 return hr;
2472 static HRESULT WINAPI src_reader_SetNativeMediaType(IMFSourceReaderEx *iface, DWORD stream_index,
2473 IMFMediaType *media_type, DWORD *stream_flags)
2475 FIXME("%p, %#lx, %p, %p.\n", iface, stream_index, media_type, stream_flags);
2477 return E_NOTIMPL;
2480 static HRESULT WINAPI src_reader_AddTransformForStream(IMFSourceReaderEx *iface, DWORD stream_index,
2481 IUnknown *transform)
2483 FIXME("%p, %#lx, %p.\n", iface, stream_index, transform);
2485 return E_NOTIMPL;
2488 static HRESULT WINAPI src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx *iface, DWORD stream_index)
2490 FIXME("%p, %#lx.\n", iface, stream_index);
2492 return E_NOTIMPL;
2495 static struct transform_entry *get_transform_at_index(struct media_stream *stream, UINT index)
2497 struct transform_entry *entry;
2499 LIST_FOR_EACH_ENTRY(entry, &stream->transforms, struct transform_entry, entry)
2500 if (!entry->hidden && !index--)
2501 return entry;
2503 return NULL;
2506 static HRESULT WINAPI src_reader_GetTransformForStream(IMFSourceReaderEx *iface, DWORD stream_index,
2507 DWORD transform_index, GUID *category, IMFTransform **transform)
2509 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2510 struct transform_entry *entry;
2511 HRESULT hr;
2513 TRACE("%p, %#lx, %#lx, %p, %p.\n", iface, stream_index, transform_index, category, transform);
2515 EnterCriticalSection(&reader->cs);
2517 if (stream_index == MF_SOURCE_READER_FIRST_VIDEO_STREAM)
2518 stream_index = reader->first_video_stream_index;
2519 else if (stream_index == MF_SOURCE_READER_FIRST_AUDIO_STREAM)
2520 stream_index = reader->first_audio_stream_index;
2522 if (stream_index >= reader->stream_count)
2523 hr = MF_E_INVALIDSTREAMNUMBER;
2524 else if (!(entry = get_transform_at_index(&reader->streams[stream_index], transform_index)))
2525 hr = MF_E_INVALIDINDEX;
2526 else
2528 *category = entry->category;
2529 *transform = entry->transform;
2530 IMFTransform_AddRef(*transform);
2531 hr = S_OK;
2534 LeaveCriticalSection(&reader->cs);
2536 return hr;
2539 static const IMFSourceReaderExVtbl srcreader_vtbl =
2541 src_reader_QueryInterface,
2542 src_reader_AddRef,
2543 src_reader_Release,
2544 src_reader_GetStreamSelection,
2545 src_reader_SetStreamSelection,
2546 src_reader_GetNativeMediaType,
2547 src_reader_GetCurrentMediaType,
2548 src_reader_SetCurrentMediaType,
2549 src_reader_SetCurrentPosition,
2550 src_reader_ReadSample,
2551 src_reader_Flush,
2552 src_reader_GetServiceForStream,
2553 src_reader_GetPresentationAttribute,
2554 src_reader_SetNativeMediaType,
2555 src_reader_AddTransformForStream,
2556 src_reader_RemoveAllTransformsForStream,
2557 src_reader_GetTransformForStream,
2560 static DWORD reader_get_first_stream_index(IMFPresentationDescriptor *descriptor, const GUID *major)
2562 DWORD count, i;
2563 BOOL selected;
2564 HRESULT hr;
2565 GUID guid;
2567 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count)))
2568 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2570 for (i = 0; i < count; ++i)
2572 IMFMediaTypeHandler *handler;
2573 IMFStreamDescriptor *sd;
2575 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i, &selected, &sd)))
2577 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2578 IMFStreamDescriptor_Release(sd);
2579 if (SUCCEEDED(hr))
2581 hr = IMFMediaTypeHandler_GetMajorType(handler, &guid);
2582 IMFMediaTypeHandler_Release(handler);
2583 if (FAILED(hr))
2585 WARN("Failed to get stream major type, hr %#lx.\n", hr);
2586 continue;
2589 if (IsEqualGUID(&guid, major))
2591 return i;
2597 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2600 static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttributes *attributes,
2601 BOOL shutdown_on_release, REFIID riid, void **out)
2603 struct source_reader *object;
2604 unsigned int i;
2605 HRESULT hr;
2607 object = calloc(1, sizeof(*object));
2608 if (!object)
2609 return E_OUTOFMEMORY;
2611 object->IMFSourceReaderEx_iface.lpVtbl = &srcreader_vtbl;
2612 object->source_events_callback.lpVtbl = &source_events_callback_vtbl;
2613 object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl;
2614 object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl;
2615 object->public_refcount = 1;
2616 object->refcount = 1;
2617 list_init(&object->responses);
2618 if (shutdown_on_release)
2619 object->flags |= SOURCE_READER_SHUTDOWN_ON_RELEASE;
2620 object->source = source;
2621 IMFMediaSource_AddRef(object->source);
2622 InitializeCriticalSection(&object->cs);
2623 InitializeConditionVariable(&object->sample_event);
2624 InitializeConditionVariable(&object->state_event);
2625 InitializeConditionVariable(&object->stop_event);
2627 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor)))
2628 goto failed;
2630 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(object->descriptor, &object->stream_count)))
2631 goto failed;
2633 if (!(object->streams = calloc(object->stream_count, sizeof(*object->streams))))
2635 hr = E_OUTOFMEMORY;
2636 goto failed;
2639 /* Set initial current media types. */
2640 for (i = 0; i < object->stream_count; ++i)
2642 IMFMediaTypeHandler *handler;
2643 IMFStreamDescriptor *sd;
2644 IMFMediaType *src_type;
2645 BOOL selected;
2647 list_init(&object->streams[i].transforms);
2649 if (FAILED(hr = MFCreateMediaType(&object->streams[i].current)))
2650 break;
2652 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(object->descriptor, i, &selected, &sd)))
2653 break;
2655 if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &object->streams[i].id)))
2656 WARN("Failed to get stream identifier, hr %#lx.\n", hr);
2658 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2659 IMFStreamDescriptor_Release(sd);
2660 if (FAILED(hr))
2661 break;
2663 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &src_type);
2664 IMFMediaTypeHandler_Release(handler);
2665 if (FAILED(hr))
2666 break;
2668 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)object->streams[i].current);
2669 IMFMediaType_Release(src_type);
2670 if (FAILED(hr))
2671 break;
2673 object->streams[i].reader = object;
2674 object->streams[i].index = i;
2677 if (FAILED(hr))
2678 goto failed;
2680 /* At least one major type has to be set. */
2681 object->first_audio_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Audio);
2682 object->first_video_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Video);
2684 if (object->first_audio_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX &&
2685 object->first_video_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX)
2687 hr = MF_E_ATTRIBUTENOTFOUND;
2690 if (FAILED(hr = IMFMediaSource_BeginGetEvent(object->source, &object->source_events_callback,
2691 (IUnknown *)object->source)))
2693 goto failed;
2696 if (attributes)
2698 object->attributes = attributes;
2699 IMFAttributes_AddRef(object->attributes);
2701 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_ASYNC_CALLBACK, &IID_IMFSourceReaderCallback,
2702 (void **)&object->async_callback);
2703 if (object->async_callback)
2704 TRACE("Using async callback %p.\n", object->async_callback);
2706 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, &IID_IUnknown, (void **)&object->device_manager);
2707 if (object->device_manager)
2709 IUnknown *unk = NULL;
2711 if (SUCCEEDED(IUnknown_QueryInterface(object->device_manager, &IID_IMFDXGIDeviceManager, (void **)&unk)))
2712 object->flags |= SOURCE_READER_DXGI_DEVICE_MANAGER;
2713 else if (SUCCEEDED(IUnknown_QueryInterface(object->device_manager, &IID_IDirect3DDeviceManager9, (void **)&unk)))
2714 object->flags |= SOURCE_READER_D3D9_DEVICE_MANAGER;
2716 if (!(object->flags & (SOURCE_READER_HAS_DEVICE_MANAGER)))
2718 WARN("Unknown device manager.\n");
2719 IUnknown_Release(object->device_manager);
2720 object->device_manager = NULL;
2723 if (unk)
2724 IUnknown_Release(unk);
2728 if (FAILED(hr = MFLockSharedWorkQueue(L"", 0, NULL, &object->queue)))
2729 WARN("Failed to acquired shared queue, hr %#lx.\n", hr);
2731 if (SUCCEEDED(hr))
2732 hr = IMFSourceReaderEx_QueryInterface(&object->IMFSourceReaderEx_iface, riid, out);
2734 failed:
2735 IMFSourceReaderEx_Release(&object->IMFSourceReaderEx_iface);
2736 return hr;
2739 static HRESULT create_source_reader_from_stream(IMFByteStream *stream, IMFAttributes *attributes,
2740 REFIID riid, void **out)
2742 IPropertyStore *props = NULL;
2743 IMFSourceResolver *resolver;
2744 MF_OBJECT_TYPE obj_type;
2745 IMFMediaSource *source;
2746 HRESULT hr;
2748 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2749 return hr;
2751 if (attributes)
2752 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2753 (void **)&props);
2755 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE
2756 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, props, &obj_type, (IUnknown **)&source);
2757 IMFSourceResolver_Release(resolver);
2758 if (props)
2759 IPropertyStore_Release(props);
2760 if (FAILED(hr))
2761 return hr;
2763 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2764 IMFMediaSource_Release(source);
2765 return hr;
2768 static HRESULT create_source_reader_from_url(const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2770 IPropertyStore *props = NULL;
2771 IMFSourceResolver *resolver;
2772 IUnknown *object = NULL;
2773 MF_OBJECT_TYPE obj_type;
2774 IMFMediaSource *source;
2775 HRESULT hr;
2777 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2778 return hr;
2780 if (attributes)
2781 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2782 (void **)&props);
2784 hr = IMFSourceResolver_CreateObjectFromURL(resolver, url, MF_RESOLUTION_MEDIASOURCE, props, &obj_type,
2785 &object);
2786 if (SUCCEEDED(hr))
2788 switch (obj_type)
2790 case MF_OBJECT_BYTESTREAM:
2791 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, (IMFByteStream *)object, NULL,
2792 MF_RESOLUTION_MEDIASOURCE, props, &obj_type, (IUnknown **)&source);
2793 break;
2794 case MF_OBJECT_MEDIASOURCE:
2795 source = (IMFMediaSource *)object;
2796 IMFMediaSource_AddRef(source);
2797 break;
2798 default:
2799 WARN("Unknown object type %d.\n", obj_type);
2800 hr = E_UNEXPECTED;
2802 IUnknown_Release(object);
2805 IMFSourceResolver_Release(resolver);
2806 if (props)
2807 IPropertyStore_Release(props);
2808 if (FAILED(hr))
2809 return hr;
2811 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2812 IMFMediaSource_Release(source);
2813 return hr;
2816 static HRESULT create_source_reader_from_object(IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2818 IMFMediaSource *source = NULL;
2819 IMFByteStream *stream = NULL;
2820 HRESULT hr;
2822 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSource, (void **)&source);
2823 if (FAILED(hr))
2824 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2826 if (source)
2828 UINT32 disconnect = 0;
2830 if (attributes)
2831 IMFAttributes_GetUINT32(attributes, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN, &disconnect);
2832 hr = create_source_reader_from_source(source, attributes, !disconnect, riid, out);
2834 else if (stream)
2835 hr = create_source_reader_from_stream(stream, attributes, riid, out);
2837 if (source)
2838 IMFMediaSource_Release(source);
2839 if (stream)
2840 IMFByteStream_Release(stream);
2842 return hr;
2845 /***********************************************************************
2846 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2848 HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes,
2849 IMFSourceReader **reader)
2851 TRACE("%p, %p, %p.\n", stream, attributes, reader);
2853 return create_source_reader_from_object((IUnknown *)stream, attributes, &IID_IMFSourceReader, (void **)reader);
2856 /***********************************************************************
2857 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2859 HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes,
2860 IMFSourceReader **reader)
2862 TRACE("%p, %p, %p.\n", source, attributes, reader);
2864 return create_source_reader_from_object((IUnknown *)source, attributes, &IID_IMFSourceReader, (void **)reader);
2867 /***********************************************************************
2868 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2870 HRESULT WINAPI MFCreateSourceReaderFromURL(const WCHAR *url, IMFAttributes *attributes, IMFSourceReader **reader)
2872 TRACE("%s, %p, %p.\n", debugstr_w(url), attributes, reader);
2874 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, (void **)reader);
2877 static HRESULT WINAPI readwrite_factory_QueryInterface(IMFReadWriteClassFactory *iface, REFIID riid, void **out)
2879 if (IsEqualIID(riid, &IID_IMFReadWriteClassFactory) ||
2880 IsEqualIID(riid, &IID_IUnknown))
2882 *out = iface;
2883 IMFReadWriteClassFactory_AddRef(iface);
2884 return S_OK;
2887 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
2888 *out = NULL;
2889 return E_NOINTERFACE;
2892 static ULONG WINAPI readwrite_factory_AddRef(IMFReadWriteClassFactory *iface)
2894 return 2;
2897 static ULONG WINAPI readwrite_factory_Release(IMFReadWriteClassFactory *iface)
2899 return 1;
2902 static HRESULT WINAPI readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2903 const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2905 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid), debugstr_w(url), attributes, debugstr_guid(riid), out);
2907 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2909 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, out);
2911 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
2913 return create_sink_writer_from_url(url, NULL, attributes, riid, out);
2916 FIXME("Unsupported %s.\n", debugstr_guid(clsid));
2918 return E_NOTIMPL;
2921 static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2922 IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2924 HRESULT hr;
2926 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid), unk, attributes, debugstr_guid(riid), out);
2928 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2930 return create_source_reader_from_object(unk, attributes, riid, out);
2932 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
2934 IMFByteStream *stream = NULL;
2935 IMFMediaSink *sink = NULL;
2937 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2938 if (FAILED(hr))
2939 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSink, (void **)&sink);
2941 if (stream)
2942 hr = create_sink_writer_from_url(NULL, stream, attributes, riid, out);
2943 else if (sink)
2944 hr = create_sink_writer_from_sink(sink, attributes, riid, out);
2946 if (sink)
2947 IMFMediaSink_Release(sink);
2948 if (stream)
2949 IMFByteStream_Release(stream);
2951 return hr;
2953 else
2955 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2956 *out = NULL;
2957 return E_FAIL;
2961 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl =
2963 readwrite_factory_QueryInterface,
2964 readwrite_factory_AddRef,
2965 readwrite_factory_Release,
2966 readwrite_factory_CreateInstanceFromURL,
2967 readwrite_factory_CreateInstanceFromObject,
2970 static IMFReadWriteClassFactory readwrite_factory = { &readwrite_factory_vtbl };
2972 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
2974 TRACE("%s, %p.\n", debugstr_guid(riid), out);
2976 if (IsEqualGUID(riid, &IID_IClassFactory) ||
2977 IsEqualGUID(riid, &IID_IUnknown))
2979 IClassFactory_AddRef(iface);
2980 *out = iface;
2981 return S_OK;
2984 WARN("interface %s not implemented\n", debugstr_guid(riid));
2985 *out = NULL;
2986 return E_NOINTERFACE;
2989 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
2991 return 2;
2994 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
2996 return 1;
2999 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out)
3001 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), out);
3003 *out = NULL;
3005 if (outer)
3006 return CLASS_E_NOAGGREGATION;
3008 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory, riid, out);
3011 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
3013 FIXME("%d.\n", dolock);
3014 return S_OK;
3017 static const IClassFactoryVtbl classfactoryvtbl =
3019 classfactory_QueryInterface,
3020 classfactory_AddRef,
3021 classfactory_Release,
3022 classfactory_CreateInstance,
3023 classfactory_LockServer,
3026 static IClassFactory classfactory = { &classfactoryvtbl };
3028 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
3030 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), out);
3032 if (IsEqualGUID(clsid, &CLSID_MFReadWriteClassFactory))
3033 return IClassFactory_QueryInterface(&classfactory, riid, out);
3035 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
3036 *out = NULL;
3037 return CLASS_E_CLASSNOTAVAILABLE;