mfreadwrite/reader: Create and append a converter transform.
[wine.git] / dlls / mfreadwrite / reader.c
blob41becb2b159cf40bc4c9c2ff2c9dbaa095023c60
1 /*
3 * Copyright 2014 Austin English
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
22 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "ole2.h"
26 #include "rpcproxy.h"
28 #undef INITGUID
29 #include <guiddef.h>
30 #include "mfapi.h"
31 #include "mfidl.h"
32 #include "mfreadwrite.h"
33 #include "d3d9.h"
34 #include "initguid.h"
35 #include "dxva2api.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 #include "mf_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
44 struct stream_response
46 struct list entry;
47 HRESULT status;
48 DWORD stream_index;
49 DWORD stream_flags;
50 LONGLONG timestamp;
51 IMFSample *sample;
54 enum media_stream_state
56 STREAM_STATE_READY = 0,
57 STREAM_STATE_EOS,
60 enum media_source_state
62 SOURCE_STATE_STOPPED = 0,
63 SOURCE_STATE_STARTED,
66 enum media_stream_flags
68 STREAM_FLAG_SAMPLE_REQUESTED = 0x1, /* Protects from making multiple sample requests. */
69 STREAM_FLAG_SELECTED = 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
70 STREAM_FLAG_PRESENTED = 0x4, /* Set if stream was selected last time Start() was called. */
71 STREAM_FLAG_STOPPED = 0x8, /* Received MEStreamStopped */
74 struct transform_entry
76 struct list entry;
77 IMFTransform *transform;
78 unsigned int min_buffer_size;
79 GUID category;
82 struct media_stream
84 IMFMediaStream *stream;
85 IMFMediaType *current;
86 struct list transforms;
87 IMFVideoSampleAllocatorEx *allocator;
88 IMFTransform *transform_service;
89 DWORD id;
90 unsigned int index;
91 enum media_stream_state state;
92 unsigned int flags;
93 unsigned int requests;
94 unsigned int responses;
95 LONGLONG last_sample_ts;
96 struct source_reader *reader;
99 enum source_reader_async_op
101 SOURCE_READER_ASYNC_READ,
102 SOURCE_READER_ASYNC_SEEK,
103 SOURCE_READER_ASYNC_FLUSH,
104 SOURCE_READER_ASYNC_SAMPLE_READY,
107 struct source_reader_async_command
109 IUnknown IUnknown_iface;
110 LONG refcount;
111 enum source_reader_async_op op;
112 union
114 struct
116 unsigned int flags;
117 unsigned int stream_index;
118 } read;
119 struct
121 GUID format;
122 PROPVARIANT position;
123 } seek;
124 struct
126 unsigned int stream_index;
127 } flush;
128 struct
130 unsigned int stream_index;
131 } sample;
132 struct
134 unsigned int stream_index;
135 } sa;
136 } u;
139 enum source_reader_flags
141 SOURCE_READER_FLUSHING = 0x1,
142 SOURCE_READER_SEEKING = 0x2,
143 SOURCE_READER_SHUTDOWN_ON_RELEASE = 0x4,
144 SOURCE_READER_D3D9_DEVICE_MANAGER = 0x8,
145 SOURCE_READER_DXGI_DEVICE_MANAGER = 0x10,
146 SOURCE_READER_HAS_DEVICE_MANAGER = SOURCE_READER_D3D9_DEVICE_MANAGER | SOURCE_READER_DXGI_DEVICE_MANAGER,
149 struct source_reader
151 IMFSourceReaderEx IMFSourceReaderEx_iface;
152 IMFAsyncCallback source_events_callback;
153 IMFAsyncCallback stream_events_callback;
154 IMFAsyncCallback async_commands_callback;
155 LONG refcount;
156 LONG public_refcount;
157 IMFMediaSource *source;
158 IMFPresentationDescriptor *descriptor;
159 IMFSourceReaderCallback *async_callback;
160 IMFAttributes *attributes;
161 IUnknown *device_manager;
162 unsigned int first_audio_stream_index;
163 unsigned int first_video_stream_index;
164 DWORD stream_count;
165 unsigned int flags;
166 DWORD queue;
167 enum media_source_state source_state;
168 struct media_stream *streams;
169 struct list responses;
170 CRITICAL_SECTION cs;
171 CONDITION_VARIABLE sample_event;
172 CONDITION_VARIABLE state_event;
173 CONDITION_VARIABLE stop_event;
176 static inline struct source_reader *impl_from_IMFSourceReaderEx(IMFSourceReaderEx *iface)
178 return CONTAINING_RECORD(iface, struct source_reader, IMFSourceReaderEx_iface);
181 static struct source_reader *impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
183 return CONTAINING_RECORD(iface, struct source_reader, source_events_callback);
186 static struct source_reader *impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
188 return CONTAINING_RECORD(iface, struct source_reader, stream_events_callback);
191 static struct source_reader *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
193 return CONTAINING_RECORD(iface, struct source_reader, async_commands_callback);
196 static struct source_reader_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
198 return CONTAINING_RECORD(iface, struct source_reader_async_command, IUnknown_iface);
201 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream);
203 static ULONG source_reader_addref(struct source_reader *reader)
205 return InterlockedIncrement(&reader->refcount);
208 static void transform_entry_destroy(struct transform_entry *entry)
210 IMFTransform_Release(entry->transform);
211 free(entry);
214 static void media_stream_destroy(struct media_stream *stream)
216 struct transform_entry *entry, *next;
218 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry)
220 list_remove(&entry->entry);
221 transform_entry_destroy(entry);
224 if (stream->stream)
225 IMFMediaStream_Release(stream->stream);
226 if (stream->current)
227 IMFMediaType_Release(stream->current);
228 if (stream->allocator)
229 IMFVideoSampleAllocatorEx_Release(stream->allocator);
232 static ULONG source_reader_release(struct source_reader *reader)
234 ULONG refcount = InterlockedDecrement(&reader->refcount);
235 unsigned int i;
237 if (!refcount)
239 if (reader->device_manager)
240 IUnknown_Release(reader->device_manager);
241 if (reader->async_callback)
242 IMFSourceReaderCallback_Release(reader->async_callback);
243 if (reader->descriptor)
244 IMFPresentationDescriptor_Release(reader->descriptor);
245 if (reader->attributes)
246 IMFAttributes_Release(reader->attributes);
247 IMFMediaSource_Release(reader->source);
249 for (i = 0; i < reader->stream_count; ++i)
251 struct media_stream *stream = &reader->streams[i];
252 media_stream_destroy(stream);
254 source_reader_release_responses(reader, NULL);
255 free(reader->streams);
256 MFUnlockWorkQueue(reader->queue);
257 DeleteCriticalSection(&reader->cs);
258 free(reader);
261 return refcount;
264 static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
266 if (IsEqualIID(riid, &IID_IUnknown))
268 *obj = iface;
269 IUnknown_AddRef(iface);
270 return S_OK;
273 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
274 *obj = NULL;
275 return E_NOINTERFACE;
278 static ULONG WINAPI source_reader_async_command_AddRef(IUnknown *iface)
280 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
281 return InterlockedIncrement(&command->refcount);
284 static ULONG WINAPI source_reader_async_command_Release(IUnknown *iface)
286 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
287 ULONG refcount = InterlockedIncrement(&command->refcount);
289 if (!refcount)
291 if (command->op == SOURCE_READER_ASYNC_SEEK)
292 PropVariantClear(&command->u.seek.position);
293 free(command);
296 return refcount;
299 static const IUnknownVtbl source_reader_async_command_vtbl =
301 source_reader_async_command_QueryInterface,
302 source_reader_async_command_AddRef,
303 source_reader_async_command_Release,
306 static HRESULT source_reader_create_async_op(enum source_reader_async_op op, struct source_reader_async_command **ret)
308 struct source_reader_async_command *command;
310 if (!(command = calloc(1, sizeof(*command))))
311 return E_OUTOFMEMORY;
313 command->IUnknown_iface.lpVtbl = &source_reader_async_command_vtbl;
314 command->op = op;
316 *ret = command;
318 return S_OK;
321 static HRESULT media_event_get_object(IMFMediaEvent *event, REFIID riid, void **obj)
323 PROPVARIANT value;
324 HRESULT hr;
326 PropVariantInit(&value);
327 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
329 WARN("Failed to get event value, hr %#lx.\n", hr);
330 return hr;
333 if (value.vt != VT_UNKNOWN || !value.punkVal)
335 WARN("Unexpected value type %d.\n", value.vt);
336 PropVariantClear(&value);
337 return E_UNEXPECTED;
340 hr = IUnknown_QueryInterface(value.punkVal, riid, obj);
341 PropVariantClear(&value);
342 if (FAILED(hr))
344 WARN("Unexpected object type.\n");
345 return hr;
348 return hr;
351 static HRESULT media_stream_get_id(IMFMediaStream *stream, DWORD *id)
353 IMFStreamDescriptor *sd;
354 HRESULT hr;
356 if (SUCCEEDED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
358 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, id);
359 IMFStreamDescriptor_Release(sd);
362 return hr;
365 static HRESULT WINAPI source_reader_callback_QueryInterface(IMFAsyncCallback *iface,
366 REFIID riid, void **obj)
368 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
370 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
371 IsEqualIID(riid, &IID_IUnknown))
373 *obj = iface;
374 IMFAsyncCallback_AddRef(iface);
375 return S_OK;
378 WARN("Unsupported %s.\n", debugstr_guid(riid));
379 *obj = NULL;
380 return E_NOINTERFACE;
383 static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface)
385 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
386 return source_reader_addref(reader);
389 static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface)
391 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
392 return source_reader_release(reader);
395 static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface,
396 DWORD *flags, DWORD *queue)
398 return E_NOTIMPL;
401 static void source_reader_response_ready(struct source_reader *reader, struct stream_response *response)
403 struct source_reader_async_command *command;
404 struct media_stream *stream = &reader->streams[response->stream_index];
405 HRESULT hr;
407 if (!stream->requests)
408 return;
410 if (reader->async_callback)
412 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY, &command)))
414 command->u.sample.stream_index = stream->index;
415 if (FAILED(hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface)))
416 WARN("Failed to submit async result, hr %#lx.\n", hr);
417 IUnknown_Release(&command->IUnknown_iface);
420 else
421 WakeAllConditionVariable(&reader->sample_event);
423 stream->requests--;
426 static void source_reader_copy_sample_buffer(IMFSample *src, IMFSample *dst)
428 IMFMediaBuffer *buffer;
429 LONGLONG time;
430 DWORD flags;
431 HRESULT hr;
433 IMFSample_CopyAllItems(src, (IMFAttributes *)dst);
435 IMFSample_SetSampleDuration(dst, 0);
436 IMFSample_SetSampleTime(dst, 0);
437 IMFSample_SetSampleFlags(dst, 0);
439 if (SUCCEEDED(IMFSample_GetSampleDuration(src, &time)))
440 IMFSample_SetSampleDuration(dst, time);
442 if (SUCCEEDED(IMFSample_GetSampleTime(src, &time)))
443 IMFSample_SetSampleTime(dst, time);
445 if (SUCCEEDED(IMFSample_GetSampleFlags(src, &flags)))
446 IMFSample_SetSampleFlags(dst, flags);
448 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src, NULL)))
450 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst, 0, &buffer)))
452 if (FAILED(hr = IMFSample_CopyToBuffer(src, buffer)))
453 WARN("Failed to copy a buffer, hr %#lx.\n", hr);
454 IMFMediaBuffer_Release(buffer);
459 static HRESULT source_reader_queue_response(struct source_reader *reader, struct media_stream *stream, HRESULT status,
460 DWORD stream_flags, LONGLONG timestamp, IMFSample *sample)
462 struct stream_response *response;
464 if (!(response = calloc(1, sizeof(*response))))
465 return E_OUTOFMEMORY;
467 response->status = status;
468 response->stream_index = stream->index;
469 response->stream_flags = stream_flags;
470 response->timestamp = timestamp;
471 response->sample = sample;
472 if (response->sample)
473 IMFSample_AddRef(response->sample);
475 list_add_tail(&reader->responses, &response->entry);
476 stream->responses++;
478 source_reader_response_ready(reader, response);
480 stream->last_sample_ts = timestamp;
482 return S_OK;
485 static HRESULT source_reader_queue_sample(struct source_reader *reader, struct media_stream *stream,
486 IMFSample *sample)
488 LONGLONG timestamp = 0;
490 if (FAILED(IMFSample_GetSampleTime(sample, &timestamp)))
491 WARN("Sample time wasn't set.\n");
493 return source_reader_queue_response(reader, stream, S_OK, 0, timestamp, sample);
496 static HRESULT source_reader_request_sample(struct source_reader *reader, struct media_stream *stream)
498 HRESULT hr = S_OK;
500 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
502 if (FAILED(hr = IMFMediaStream_RequestSample(stream->stream, NULL)))
503 WARN("Sample request failed, hr %#lx.\n", hr);
504 else
506 stream->flags |= STREAM_FLAG_SAMPLE_REQUESTED;
510 return hr;
513 static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IMFMediaEvent *event)
515 IMFMediaStream *stream;
516 unsigned int i;
517 DWORD id = 0;
518 HRESULT hr;
520 if (FAILED(hr = media_event_get_object(event, &IID_IMFMediaStream, (void **)&stream)))
522 WARN("Failed to get stream object, hr %#lx.\n", hr);
523 return hr;
526 TRACE("Got new stream %p.\n", stream);
528 if (FAILED(hr = media_stream_get_id(stream, &id)))
530 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
531 IMFMediaStream_Release(stream);
532 return hr;
535 EnterCriticalSection(&reader->cs);
537 for (i = 0; i < reader->stream_count; ++i)
539 if (id == reader->streams[i].id)
541 if (!reader->streams[i].stream)
543 reader->streams[i].stream = stream;
544 IMFMediaStream_AddRef(reader->streams[i].stream);
545 if (FAILED(hr = IMFMediaStream_BeginGetEvent(stream, &reader->stream_events_callback,
546 (IUnknown *)stream)))
548 WARN("Failed to subscribe to stream events, hr %#lx.\n", hr);
551 if (reader->streams[i].requests)
552 if (FAILED(source_reader_request_sample(reader, &reader->streams[i])))
553 WakeAllConditionVariable(&reader->sample_event);
555 break;
559 if (i == reader->stream_count)
560 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id);
562 LeaveCriticalSection(&reader->cs);
564 IMFMediaStream_Release(stream);
566 return hr;
569 static HRESULT source_reader_source_state_handler(struct source_reader *reader, MediaEventType event_type)
571 EnterCriticalSection(&reader->cs);
573 switch (event_type)
575 case MESourceStarted:
576 reader->source_state = SOURCE_STATE_STARTED;
577 reader->flags &= ~SOURCE_READER_SEEKING;
578 break;
579 case MESourceStopped:
580 reader->source_state = SOURCE_STATE_STOPPED;
581 reader->flags &= ~SOURCE_READER_SEEKING;
582 break;
583 case MESourceSeeked:
584 reader->flags &= ~SOURCE_READER_SEEKING;
585 break;
586 default:
587 WARN("Unhandled event %ld.\n", event_type);
590 LeaveCriticalSection(&reader->cs);
592 WakeAllConditionVariable(&reader->state_event);
593 if (event_type == MESourceStopped)
594 WakeAllConditionVariable(&reader->stop_event);
596 return S_OK;
599 static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
601 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
602 MediaEventType event_type;
603 IMFMediaSource *source;
604 IMFMediaEvent *event;
605 HRESULT hr;
607 TRACE("%p, %p.\n", iface, result);
609 source = (IMFMediaSource *)IMFAsyncResult_GetStateNoAddRef(result);
611 if (FAILED(hr = IMFMediaSource_EndGetEvent(source, result, &event)))
612 return hr;
614 IMFMediaEvent_GetType(event, &event_type);
616 TRACE("Got event %lu.\n", event_type);
618 switch (event_type)
620 case MENewStream:
621 hr = source_reader_new_stream_handler(reader, event);
622 break;
623 case MESourceStarted:
624 case MESourcePaused:
625 case MESourceStopped:
626 case MESourceSeeked:
627 hr = source_reader_source_state_handler(reader, event_type);
628 break;
629 case MEBufferingStarted:
630 case MEBufferingStopped:
631 case MEConnectStart:
632 case MEConnectEnd:
633 case MEExtendedType:
634 case MESourceCharacteristicsChanged:
635 case MESourceMetadataChanged:
636 case MEContentProtectionMetadata:
637 case MEDeviceThermalStateChanged:
638 if (reader->async_callback)
639 IMFSourceReaderCallback_OnEvent(reader->async_callback, MF_SOURCE_READER_MEDIASOURCE, event);
640 break;
641 default:
645 if (FAILED(hr))
646 WARN("Failed while handling %ld event, hr %#lx.\n", event_type, hr);
648 IMFMediaEvent_Release(event);
650 if (event_type != MESourceStopped)
651 IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
653 return S_OK;
656 static const IMFAsyncCallbackVtbl source_events_callback_vtbl =
658 source_reader_callback_QueryInterface,
659 source_reader_source_events_callback_AddRef,
660 source_reader_source_events_callback_Release,
661 source_reader_callback_GetParameters,
662 source_reader_source_events_callback_Invoke,
665 static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface)
667 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
668 return source_reader_addref(reader);
671 static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface)
673 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
674 return source_reader_release(reader);
677 static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info, IMFSample **out)
679 IMFMediaBuffer *buffer;
680 IMFSample *sample;
681 HRESULT hr;
683 *out = NULL;
684 if (FAILED(hr = MFCreateSample(&sample)))
685 return hr;
686 if (SUCCEEDED(hr = MFCreateAlignedMemoryBuffer(info->cbSize, info->cbAlignment, &buffer)))
688 if (SUCCEEDED(hr = IMFSample_AddBuffer(sample, buffer)))
690 *out = sample;
691 IMFSample_AddRef(sample);
693 IMFMediaBuffer_Release(buffer);
696 IMFSample_Release(sample);
697 return hr;
700 static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const GUID *attr, HRESULT *hr)
702 PROPVARIANT value;
704 PropVariantInit(&value);
705 if (SUCCEEDED(*hr) && FAILED(IMFMediaType_GetItem(dst, attr, NULL))
706 && SUCCEEDED(IMFMediaType_GetItem(src, attr, &value)))
707 *hr = IMFMediaType_SetItem(dst, attr, &value);
708 PropVariantClear(&value);
711 /* update a media type with additional attributes reported by upstream element */
712 /* also present in mf/topology_loader.c pipeline */
713 static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type)
715 HRESULT hr = S_OK;
717 /* propagate common video attributes */
718 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_SIZE, &hr);
719 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_RATE, &hr);
720 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_DEFAULT_STRIDE, &hr);
721 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_ROTATION, &hr);
722 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FIXED_SIZE_SAMPLES, &hr);
723 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_PIXEL_ASPECT_RATIO, &hr);
724 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &hr);
725 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &hr);
727 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_CHROMA_SITING, &hr);
728 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_INTERLACE_MODE, &hr);
729 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_TRANSFER_FUNCTION, &hr);
730 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_PRIMARIES, &hr);
731 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_YUV_MATRIX, &hr);
732 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_LIGHTING, &hr);
733 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_NOMINAL_RANGE, &hr);
735 /* propagate common audio attributes */
736 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_NUM_CHANNELS, &hr);
737 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &hr);
738 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &hr);
739 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &hr);
740 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &hr);
741 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_CHANNEL_MASK, &hr);
742 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &hr);
743 media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &hr);
745 return hr;
748 static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream,
749 struct transform_entry *entry);
750 static HRESULT source_reader_push_transform_samples(struct source_reader *reader, struct media_stream *stream,
751 struct transform_entry *entry, IMFSample *sample)
753 HRESULT hr;
757 if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry))
758 && hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
759 return hr;
760 if (SUCCEEDED(hr = IMFTransform_ProcessInput(entry->transform, 0, sample, 0)))
761 return source_reader_pull_transform_samples(reader, stream, entry);
763 while (hr == MF_E_NOTACCEPTING);
765 return hr;
768 static HRESULT source_reader_pull_transform_samples(struct source_reader *reader, struct media_stream *stream,
769 struct transform_entry *entry)
771 MFT_OUTPUT_STREAM_INFO stream_info = {0};
772 struct transform_entry *next = NULL;
773 struct list *ptr;
774 DWORD status;
775 HRESULT hr;
777 if ((ptr = list_next(&stream->transforms, &entry->entry)))
778 next = LIST_ENTRY(ptr, struct transform_entry, entry);
780 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(entry->transform, 0, &stream_info)))
781 return hr;
782 stream_info.cbSize = max(stream_info.cbSize, entry->min_buffer_size);
784 while (SUCCEEDED(hr))
786 MFT_OUTPUT_DATA_BUFFER out_buffer = {0};
788 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES))
789 && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample)))
790 break;
792 if (SUCCEEDED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status)))
794 if (next)
795 hr = source_reader_push_transform_samples(reader, stream, next, out_buffer.pSample);
796 else
797 hr = source_reader_queue_sample(reader, stream, out_buffer.pSample);
800 if (out_buffer.pSample)
801 IMFSample_Release(out_buffer.pSample);
802 if (out_buffer.pEvents)
803 IMFCollection_Release(out_buffer.pEvents);
806 return hr;
809 static HRESULT source_reader_drain_transform_samples(struct source_reader *reader, struct media_stream *stream,
810 struct transform_entry *entry)
812 struct transform_entry *next = NULL;
813 struct list *ptr;
814 HRESULT hr;
816 if ((ptr = list_next(&stream->transforms, &entry->entry)))
817 next = LIST_ENTRY(ptr, struct transform_entry, entry);
819 if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_DRAIN, 0)))
820 WARN("Failed to drain transform %p, hr %#lx\n", entry->transform, hr);
821 if (FAILED(hr = source_reader_pull_transform_samples(reader, stream, entry))
822 && hr != MF_E_TRANSFORM_NEED_MORE_INPUT)
823 WARN("Failed to pull pending samples, hr %#lx.\n", hr);
825 return next ? source_reader_drain_transform_samples(reader, stream, next) : S_OK;
828 static HRESULT source_reader_flush_transform_samples(struct source_reader *reader, struct media_stream *stream,
829 struct transform_entry *entry)
831 struct transform_entry *next = NULL;
832 struct list *ptr;
833 HRESULT hr;
835 if ((ptr = list_next(&stream->transforms, &entry->entry)))
836 next = LIST_ENTRY(ptr, struct transform_entry, entry);
838 if (FAILED(hr = IMFTransform_ProcessMessage(entry->transform, MFT_MESSAGE_COMMAND_FLUSH, 0)))
839 WARN("Failed to flush transform %p, hr %#lx\n", entry->transform, hr);
841 return next ? source_reader_flush_transform_samples(reader, stream, next) : S_OK;
844 static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream,
845 IMFSample *sample)
847 struct transform_entry *entry;
848 struct list *ptr;
849 HRESULT hr;
851 if (!(ptr = list_head(&stream->transforms)))
852 return source_reader_queue_sample(reader, stream, sample);
853 entry = LIST_ENTRY(ptr, struct transform_entry, entry);
855 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
856 if (SUCCEEDED(hr = source_reader_push_transform_samples(reader, stream, entry, sample))
857 || hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
858 hr = stream->requests ? source_reader_request_sample(reader, stream) : S_OK;
859 else
860 WARN("Transform failed to process output, hr %#lx.\n", hr);
862 return hr;
865 static HRESULT source_reader_media_sample_handler(struct source_reader *reader, IMFMediaStream *stream,
866 IMFMediaEvent *event)
868 IMFSample *sample;
869 unsigned int i;
870 DWORD id = 0;
871 HRESULT hr;
873 TRACE("Got new sample for stream %p.\n", stream);
875 if (FAILED(hr = media_event_get_object(event, &IID_IMFSample, (void **)&sample)))
877 WARN("Failed to get sample object, hr %#lx.\n", hr);
878 return hr;
881 if (FAILED(hr = media_stream_get_id(stream, &id)))
883 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
884 IMFSample_Release(sample);
885 return hr;
888 EnterCriticalSection(&reader->cs);
890 for (i = 0; i < reader->stream_count; ++i)
892 if (id == reader->streams[i].id)
894 /* FIXME: propagate processing errors? */
895 reader->streams[i].flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
896 hr = source_reader_process_sample(reader, &reader->streams[i], sample);
897 break;
901 if (i == reader->stream_count)
902 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id);
904 LeaveCriticalSection(&reader->cs);
906 IMFSample_Release(sample);
908 return hr;
911 static HRESULT source_reader_media_stream_state_handler(struct source_reader *reader, IMFMediaStream *stream,
912 IMFMediaEvent *event)
914 MediaEventType event_type;
915 LONGLONG timestamp;
916 PROPVARIANT value;
917 unsigned int i;
918 HRESULT hr;
919 DWORD id;
921 IMFMediaEvent_GetType(event, &event_type);
923 if (FAILED(hr = media_stream_get_id(stream, &id)))
925 WARN("Unidentified stream %p, hr %#lx.\n", stream, hr);
926 return hr;
929 EnterCriticalSection(&reader->cs);
931 for (i = 0; i < reader->stream_count; ++i)
933 struct media_stream *stream = &reader->streams[i];
935 if (id == stream->id)
937 switch (event_type)
939 case MEEndOfStream:
941 struct list *ptr;
943 stream->state = STREAM_STATE_EOS;
944 stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
946 if ((ptr = list_head(&stream->transforms)))
948 struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry);
949 if (FAILED(hr = source_reader_drain_transform_samples(reader, stream, entry)))
950 WARN("Failed to drain pending samples, hr %#lx.\n", hr);
953 while (stream->requests)
954 source_reader_queue_response(reader, stream, S_OK, MF_SOURCE_READERF_ENDOFSTREAM, 0, NULL);
956 break;
958 case MEStreamSeeked:
959 case MEStreamStarted:
960 stream->state = STREAM_STATE_READY;
961 break;
962 case MEStreamStopped:
963 stream->flags |= STREAM_FLAG_STOPPED;
964 break;
965 case MEStreamTick:
966 value.vt = VT_EMPTY;
967 hr = SUCCEEDED(IMFMediaEvent_GetValue(event, &value)) && value.vt == VT_I8 ? S_OK : E_UNEXPECTED;
968 timestamp = SUCCEEDED(hr) ? value.hVal.QuadPart : 0;
969 PropVariantClear(&value);
971 source_reader_queue_response(reader, stream, hr, MF_SOURCE_READERF_STREAMTICK, timestamp, NULL);
973 break;
974 default:
978 break;
982 LeaveCriticalSection(&reader->cs);
984 if (event_type == MEStreamStopped)
985 WakeAllConditionVariable(&reader->stop_event);
987 return S_OK;
990 static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
992 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
993 MediaEventType event_type;
994 IMFMediaStream *stream;
995 IMFMediaEvent *event;
996 HRESULT hr;
998 TRACE("%p, %p.\n", iface, result);
1000 stream = (IMFMediaStream *)IMFAsyncResult_GetStateNoAddRef(result);
1002 if (FAILED(hr = IMFMediaStream_EndGetEvent(stream, result, &event)))
1003 return hr;
1005 IMFMediaEvent_GetType(event, &event_type);
1007 TRACE("Got event %lu.\n", event_type);
1009 switch (event_type)
1011 case MEMediaSample:
1012 hr = source_reader_media_sample_handler(reader, stream, event);
1013 break;
1014 case MEStreamSeeked:
1015 case MEStreamStarted:
1016 case MEStreamStopped:
1017 case MEStreamTick:
1018 case MEEndOfStream:
1019 hr = source_reader_media_stream_state_handler(reader, stream, event);
1020 break;
1021 default:
1025 if (FAILED(hr))
1026 WARN("Failed while handling %ld event, hr %#lx.\n", event_type, hr);
1028 IMFMediaEvent_Release(event);
1030 if (event_type != MEStreamStopped)
1031 IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
1033 return S_OK;
1036 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl =
1038 source_reader_callback_QueryInterface,
1039 source_reader_stream_events_callback_AddRef,
1040 source_reader_stream_events_callback_Release,
1041 source_reader_callback_GetParameters,
1042 source_reader_stream_events_callback_Invoke,
1045 static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface)
1047 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1048 return source_reader_addref(reader);
1051 static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface)
1053 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1054 return source_reader_release(reader);
1057 static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response)
1059 struct media_stream *stream;
1061 list_remove(&response->entry);
1063 if (response->stream_index < reader->stream_count)
1065 stream = &reader->streams[response->stream_index];
1066 if (stream->responses)
1067 --stream->responses;
1070 return response;
1073 static struct stream_response *media_stream_pop_response(struct source_reader *reader, struct media_stream *stream)
1075 struct stream_response *response;
1076 IMFSample *sample;
1077 HRESULT hr;
1079 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
1081 if (stream && response->stream_index != stream->index)
1082 continue;
1084 if (!stream) stream = &reader->streams[response->stream_index];
1086 if (response->sample && stream->allocator)
1088 /* Return allocation error to the caller, while keeping original response sample in for later. */
1089 if (SUCCEEDED(hr = IMFVideoSampleAllocatorEx_AllocateSample(stream->allocator, &sample)))
1091 source_reader_copy_sample_buffer(response->sample, sample);
1092 IMFSample_Release(response->sample);
1093 response->sample = sample;
1095 else
1097 if (!(response = calloc(1, sizeof(*response))))
1098 return NULL;
1100 response->status = hr;
1101 response->stream_flags = MF_SOURCE_READERF_ERROR;
1102 return response;
1106 return media_stream_detach_response(reader, response);
1109 return NULL;
1112 static void source_reader_release_response(struct stream_response *response)
1114 if (response->sample)
1115 IMFSample_Release(response->sample);
1116 free(response);
1119 static HRESULT source_reader_get_stream_selection(const struct source_reader *reader, DWORD index, BOOL *selected)
1121 IMFStreamDescriptor *sd;
1123 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, selected, &sd)))
1124 return MF_E_INVALIDSTREAMNUMBER;
1125 IMFStreamDescriptor_Release(sd);
1127 return S_OK;
1130 static HRESULT source_reader_start_source(struct source_reader *reader)
1132 BOOL selected, selection_changed = FALSE;
1133 PROPVARIANT position;
1134 HRESULT hr = S_OK;
1135 unsigned int i;
1137 for (i = 0; i < reader->stream_count; ++i)
1139 source_reader_get_stream_selection(reader, i, &selected);
1140 if (selected)
1141 reader->streams[i].flags |= STREAM_FLAG_SELECTED;
1142 else
1143 reader->streams[i].flags &= ~STREAM_FLAG_SELECTED;
1146 if (reader->source_state == SOURCE_STATE_STARTED)
1148 for (i = 0; i < reader->stream_count; ++i)
1150 selection_changed = !!(reader->streams[i].flags & STREAM_FLAG_SELECTED) ^
1151 !!(reader->streams[i].flags & STREAM_FLAG_PRESENTED);
1152 if (selection_changed)
1153 break;
1157 position.hVal.QuadPart = 0;
1158 if (reader->source_state != SOURCE_STATE_STARTED || selection_changed)
1160 position.vt = reader->source_state == SOURCE_STATE_STARTED ? VT_EMPTY : VT_I8;
1162 /* Update cached stream selection if descriptor was accepted. */
1163 if (SUCCEEDED(hr = IMFMediaSource_Start(reader->source, reader->descriptor, &GUID_NULL, &position)))
1165 for (i = 0; i < reader->stream_count; ++i)
1167 if (reader->streams[i].flags & STREAM_FLAG_SELECTED)
1168 reader->streams[i].flags |= STREAM_FLAG_PRESENTED;
1173 return hr;
1176 static BOOL source_reader_got_response_for_stream(struct source_reader *reader, struct media_stream *stream)
1178 struct stream_response *response;
1180 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
1182 if (response->stream_index == stream->index)
1183 return TRUE;
1186 return FALSE;
1189 static BOOL source_reader_get_read_result(struct source_reader *reader, struct media_stream *stream, DWORD flags,
1190 HRESULT *status, DWORD *stream_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1192 struct stream_response *response = NULL;
1193 BOOL request_sample = FALSE;
1195 if ((response = media_stream_pop_response(reader, stream)))
1197 *status = response->status;
1198 *stream_index = stream->index;
1199 *stream_flags = response->stream_flags;
1200 *timestamp = response->timestamp;
1201 *sample = response->sample;
1202 if (*sample)
1203 IMFSample_AddRef(*sample);
1205 source_reader_release_response(response);
1207 else
1209 *status = S_OK;
1210 *stream_index = stream->index;
1211 *timestamp = 0;
1212 *sample = NULL;
1214 if (stream->state == STREAM_STATE_EOS)
1216 *stream_flags = MF_SOURCE_READERF_ENDOFSTREAM;
1218 else
1220 request_sample = !(flags & MF_SOURCE_READER_CONTROLF_DRAIN);
1221 *stream_flags = 0;
1225 return !request_sample;
1228 static HRESULT source_reader_get_next_selected_stream(struct source_reader *reader, DWORD *stream_index)
1230 unsigned int i, first_selected = ~0u;
1231 BOOL selected, stream_drained;
1232 LONGLONG min_ts = MAXLONGLONG;
1234 for (i = 0; i < reader->stream_count; ++i)
1236 stream_drained = reader->streams[i].state == STREAM_STATE_EOS && !reader->streams[i].responses;
1237 selected = SUCCEEDED(source_reader_get_stream_selection(reader, i, &selected)) && selected;
1239 if (selected)
1241 if (first_selected == ~0u)
1242 first_selected = i;
1244 /* Pick the stream whose last sample had the lowest timestamp. */
1245 if (!stream_drained && reader->streams[i].last_sample_ts < min_ts)
1247 min_ts = reader->streams[i].last_sample_ts;
1248 *stream_index = i;
1253 /* If all selected streams reached EOS, use first selected. */
1254 if (first_selected != ~0u)
1256 if (min_ts == MAXLONGLONG)
1257 *stream_index = first_selected;
1260 return first_selected == ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED : S_OK;
1263 static HRESULT source_reader_get_stream_read_index(struct source_reader *reader, unsigned int index, DWORD *stream_index)
1265 BOOL selected;
1266 HRESULT hr;
1268 switch (index)
1270 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1271 *stream_index = reader->first_video_stream_index;
1272 break;
1273 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1274 *stream_index = reader->first_audio_stream_index;
1275 break;
1276 case MF_SOURCE_READER_ANY_STREAM:
1277 return source_reader_get_next_selected_stream(reader, stream_index);
1278 default:
1279 *stream_index = index;
1282 /* Can't read from deselected streams. */
1283 if (SUCCEEDED(hr = source_reader_get_stream_selection(reader, *stream_index, &selected)) && !selected)
1284 hr = MF_E_INVALIDREQUEST;
1286 return hr;
1289 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream)
1291 struct stream_response *ptr, *next;
1293 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &reader->responses, struct stream_response, entry)
1295 if (stream && stream->index != ptr->stream_index &&
1296 ptr->stream_index != MF_SOURCE_READER_FIRST_VIDEO_STREAM &&
1297 ptr->stream_index != MF_SOURCE_READER_FIRST_AUDIO_STREAM &&
1298 ptr->stream_index != MF_SOURCE_READER_ANY_STREAM)
1300 continue;
1302 media_stream_detach_response(reader, ptr);
1303 source_reader_release_response(ptr);
1307 static void source_reader_flush_stream(struct source_reader *reader, DWORD stream_index)
1309 struct media_stream *stream = &reader->streams[stream_index];
1310 struct list *ptr;
1311 HRESULT hr;
1313 source_reader_release_responses(reader, stream);
1315 if ((ptr = list_head(&stream->transforms)))
1317 struct transform_entry *entry = LIST_ENTRY(ptr, struct transform_entry, entry);
1318 if (FAILED(hr = source_reader_flush_transform_samples(reader, stream, entry)))
1319 WARN("Failed to drain pending samples, hr %#lx.\n", hr);
1322 stream->requests = 0;
1325 static HRESULT source_reader_flush(struct source_reader *reader, unsigned int index)
1327 unsigned int stream_index;
1328 HRESULT hr = S_OK;
1330 if (index == MF_SOURCE_READER_ALL_STREAMS)
1332 for (stream_index = 0; stream_index < reader->stream_count; ++stream_index)
1333 source_reader_flush_stream(reader, stream_index);
1335 else
1337 switch (index)
1339 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1340 stream_index = reader->first_video_stream_index;
1341 break;
1342 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1343 stream_index = reader->first_audio_stream_index;
1344 break;
1345 default:
1346 stream_index = index;
1349 if (stream_index < reader->stream_count)
1350 source_reader_flush_stream(reader, stream_index);
1351 else
1352 hr = MF_E_INVALIDSTREAMNUMBER;
1355 return hr;
1358 static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1360 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1361 struct media_stream *stream, stub_stream = { .requests = 1 };
1362 struct source_reader_async_command *command;
1363 struct stream_response *response;
1364 DWORD stream_index, stream_flags;
1365 BOOL report_sample = FALSE;
1366 IMFSample *sample = NULL;
1367 LONGLONG timestamp = 0;
1368 HRESULT hr, status;
1369 IUnknown *state;
1371 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
1372 return hr;
1374 command = impl_from_async_command_IUnknown(state);
1376 switch (command->op)
1378 case SOURCE_READER_ASYNC_READ:
1379 EnterCriticalSection(&reader->cs);
1381 if (SUCCEEDED(hr = source_reader_start_source(reader)))
1383 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, command->u.read.stream_index, &stream_index)))
1385 stream = &reader->streams[stream_index];
1387 if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status,
1388 &stream_index, &stream_flags, &timestamp, &sample)))
1390 stream->requests++;
1391 source_reader_request_sample(reader, stream);
1392 /* FIXME: set error stream/reader state on request failure */
1395 else
1397 stub_stream.index = command->u.read.stream_index;
1398 source_reader_queue_response(reader, &stub_stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL);
1402 LeaveCriticalSection(&reader->cs);
1404 if (report_sample)
1405 IMFSourceReaderCallback_OnReadSample(reader->async_callback, status, stream_index, stream_flags,
1406 timestamp, sample);
1408 if (sample)
1409 IMFSample_Release(sample);
1411 break;
1413 case SOURCE_READER_ASYNC_SEEK:
1415 EnterCriticalSection(&reader->cs);
1416 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, &command->u.seek.format,
1417 &command->u.seek.position)))
1419 reader->flags |= SOURCE_READER_SEEKING;
1421 LeaveCriticalSection(&reader->cs);
1423 break;
1425 case SOURCE_READER_ASYNC_SAMPLE_READY:
1427 EnterCriticalSection(&reader->cs);
1428 response = media_stream_pop_response(reader, NULL);
1429 LeaveCriticalSection(&reader->cs);
1431 if (response)
1433 IMFSourceReaderCallback_OnReadSample(reader->async_callback, response->status, response->stream_index,
1434 response->stream_flags, response->timestamp, response->sample);
1435 source_reader_release_response(response);
1438 break;
1439 case SOURCE_READER_ASYNC_FLUSH:
1440 EnterCriticalSection(&reader->cs);
1441 source_reader_flush(reader, command->u.flush.stream_index);
1442 reader->flags &= ~SOURCE_READER_FLUSHING;
1443 LeaveCriticalSection(&reader->cs);
1445 IMFSourceReaderCallback_OnFlush(reader->async_callback, command->u.flush.stream_index);
1446 break;
1447 default:
1451 IUnknown_Release(state);
1453 return S_OK;
1456 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl =
1458 source_reader_callback_QueryInterface,
1459 source_reader_async_commands_callback_AddRef,
1460 source_reader_async_commands_callback_Release,
1461 source_reader_callback_GetParameters,
1462 source_reader_async_commands_callback_Invoke,
1465 static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReaderEx *iface, REFIID riid, void **out)
1467 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1469 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1471 if (IsEqualGUID(riid, &IID_IUnknown)
1472 || IsEqualGUID(riid, &IID_IMFSourceReader)
1473 || IsEqualGUID(riid, &IID_IMFSourceReaderEx))
1475 *out = &reader->IMFSourceReaderEx_iface;
1477 else
1479 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
1480 *out = NULL;
1481 return E_NOINTERFACE;
1484 IUnknown_AddRef((IUnknown*)*out);
1485 return S_OK;
1488 static ULONG WINAPI src_reader_AddRef(IMFSourceReaderEx *iface)
1490 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1491 ULONG refcount = InterlockedIncrement(&reader->public_refcount);
1493 TRACE("%p, refcount %lu.\n", iface, refcount);
1495 return refcount;
1498 static BOOL source_reader_is_source_stopped(const struct source_reader *reader)
1500 unsigned int i;
1502 if (reader->source_state != SOURCE_STATE_STOPPED)
1503 return FALSE;
1505 for (i = 0; i < reader->stream_count; ++i)
1507 if (reader->streams[i].stream && !(reader->streams[i].flags & STREAM_FLAG_STOPPED))
1508 return FALSE;
1511 return TRUE;
1514 static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface)
1516 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1517 ULONG refcount = InterlockedDecrement(&reader->public_refcount);
1518 unsigned int i;
1520 TRACE("%p, refcount %lu.\n", iface, refcount);
1522 if (!refcount)
1524 if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE)
1525 IMFMediaSource_Shutdown(reader->source);
1526 else if (SUCCEEDED(IMFMediaSource_Stop(reader->source)))
1528 EnterCriticalSection(&reader->cs);
1530 while (!source_reader_is_source_stopped(reader))
1532 SleepConditionVariableCS(&reader->stop_event, &reader->cs, INFINITE);
1535 LeaveCriticalSection(&reader->cs);
1538 for (i = 0; i < reader->stream_count; ++i)
1540 struct media_stream *stream = &reader->streams[i];
1541 IMFVideoSampleAllocatorCallback *callback;
1543 if (!stream->allocator)
1544 continue;
1546 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream->allocator, &IID_IMFVideoSampleAllocatorCallback,
1547 (void **)&callback)))
1549 IMFVideoSampleAllocatorCallback_SetCallback(callback, NULL);
1550 IMFVideoSampleAllocatorCallback_Release(callback);
1554 source_reader_release(reader);
1557 return refcount;
1560 static HRESULT WINAPI src_reader_GetStreamSelection(IMFSourceReaderEx *iface, DWORD index, BOOL *selected)
1562 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1564 TRACE("%p, %#lx, %p.\n", iface, index, selected);
1566 switch (index)
1568 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1569 index = reader->first_video_stream_index;
1570 break;
1571 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1572 index = reader->first_audio_stream_index;
1573 break;
1574 default:
1578 return source_reader_get_stream_selection(reader, index, selected);
1581 static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReaderEx *iface, DWORD index, BOOL selection)
1583 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1584 HRESULT hr = S_OK;
1585 BOOL selection_changed = FALSE, selected;
1586 unsigned int i;
1588 TRACE("%p, %#lx, %d.\n", iface, index, selection);
1590 selection = !!selection;
1592 EnterCriticalSection(&reader->cs);
1594 if (index == MF_SOURCE_READER_ALL_STREAMS)
1596 for (i = 0; i < reader->stream_count; ++i)
1598 if (!selection_changed)
1600 source_reader_get_stream_selection(reader, i, &selected);
1601 selection_changed = !!(selected ^ selection);
1604 if (selection)
1605 IMFPresentationDescriptor_SelectStream(reader->descriptor, i);
1606 else
1607 IMFPresentationDescriptor_DeselectStream(reader->descriptor, i);
1610 else
1612 switch (index)
1614 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1615 index = reader->first_video_stream_index;
1616 break;
1617 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1618 index = reader->first_audio_stream_index;
1619 break;
1620 default:
1624 source_reader_get_stream_selection(reader, index, &selected);
1625 selection_changed = !!(selected ^ selection);
1627 if (selection)
1628 hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
1629 else
1630 hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
1633 if (selection_changed)
1635 for (i = 0; i < reader->stream_count; ++i)
1637 reader->streams[i].last_sample_ts = 0;
1641 LeaveCriticalSection(&reader->cs);
1643 return SUCCEEDED(hr) ? S_OK : MF_E_INVALIDSTREAMNUMBER;
1646 static HRESULT source_reader_get_native_media_type(struct source_reader *reader, DWORD index, DWORD type_index,
1647 IMFMediaType **type)
1649 IMFMediaTypeHandler *handler;
1650 IMFStreamDescriptor *sd;
1651 IMFMediaType *src_type;
1652 BOOL selected;
1653 HRESULT hr;
1655 switch (index)
1657 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1658 index = reader->first_video_stream_index;
1659 break;
1660 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1661 index = reader->first_audio_stream_index;
1662 break;
1663 default:
1667 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1668 return MF_E_INVALIDSTREAMNUMBER;
1670 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
1671 IMFStreamDescriptor_Release(sd);
1672 if (FAILED(hr))
1673 return hr;
1675 if (type_index == MF_SOURCE_READER_CURRENT_TYPE_INDEX)
1676 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &src_type);
1677 else
1678 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, type_index, &src_type);
1679 IMFMediaTypeHandler_Release(handler);
1681 if (SUCCEEDED(hr))
1683 if (SUCCEEDED(hr = MFCreateMediaType(type)))
1684 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)*type);
1685 IMFMediaType_Release(src_type);
1688 return hr;
1691 static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReaderEx *iface, DWORD index, DWORD type_index,
1692 IMFMediaType **type)
1694 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1696 TRACE("%p, %#lx, %#lx, %p.\n", iface, index, type_index, type);
1698 return source_reader_get_native_media_type(reader, index, type_index, type);
1701 static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReaderEx *iface, DWORD index, IMFMediaType **type)
1703 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
1704 HRESULT hr;
1706 TRACE("%p, %#lx, %p.\n", iface, index, type);
1708 switch (index)
1710 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1711 index = reader->first_video_stream_index;
1712 break;
1713 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1714 index = reader->first_audio_stream_index;
1715 break;
1716 default:
1720 if (index >= reader->stream_count)
1721 return MF_E_INVALIDSTREAMNUMBER;
1723 if (FAILED(hr = MFCreateMediaType(type)))
1724 return hr;
1726 EnterCriticalSection(&reader->cs);
1728 hr = IMFMediaType_CopyAllItems(reader->streams[index].current, (IMFAttributes *)*type);
1730 LeaveCriticalSection(&reader->cs);
1732 return hr;
1735 static HRESULT source_reader_get_source_type_handler(struct source_reader *reader, DWORD index,
1736 IMFMediaTypeHandler **handler)
1738 IMFStreamDescriptor *sd;
1739 BOOL selected;
1740 HRESULT hr;
1742 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1743 return hr;
1745 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, handler);
1746 IMFStreamDescriptor_Release(sd);
1748 return hr;
1751 static HRESULT source_reader_set_compatible_media_type(struct source_reader *reader, DWORD index, IMFMediaType *type)
1753 struct media_stream *stream = &reader->streams[index];
1754 struct transform_entry *entry, *next;
1755 IMFMediaTypeHandler *type_handler;
1756 IMFMediaType *native_type;
1757 BOOL type_set = FALSE;
1758 unsigned int i = 0;
1759 DWORD flags;
1760 HRESULT hr;
1762 if (FAILED(hr = IMFMediaType_IsEqual(type, stream->current, &flags)))
1763 return hr;
1765 if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES))
1766 return MF_E_INVALIDMEDIATYPE;
1768 /* No need for a decoder or type change. */
1769 if (flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)
1770 return S_OK;
1772 if (stream->transform_service)
1774 IMFTransform_Release(stream->transform_service);
1775 stream->transform_service = NULL;
1777 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &stream->transforms, struct transform_entry, entry)
1779 list_remove(&entry->entry);
1780 transform_entry_destroy(entry);
1783 if (FAILED(hr = source_reader_get_source_type_handler(reader, index, &type_handler)))
1784 return hr;
1786 while (!type_set && IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, i++, &native_type) == S_OK)
1788 static const DWORD compare_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_DATA;
1790 if (SUCCEEDED(IMFMediaType_IsEqual(native_type, type, &flags)) && (flags & compare_flags) == compare_flags)
1792 if ((type_set = SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler, native_type))))
1793 IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)stream->current);
1796 IMFMediaType_Release(native_type);
1799 IMFMediaTypeHandler_Release(type_handler);
1801 return type_set ? S_OK : S_FALSE;
1804 static HRESULT source_reader_create_sample_allocator_attributes(const struct source_reader *reader,
1805 IMFAttributes **attributes)
1807 UINT32 shared = 0, shared_without_mutex = 0;
1808 HRESULT hr;
1810 if (FAILED(hr = MFCreateAttributes(attributes, 1)))
1811 return hr;
1813 IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared);
1814 IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex);
1816 if (shared_without_mutex)
1817 hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE);
1818 else if (shared)
1819 hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED, TRUE);
1821 return hr;
1824 static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index)
1826 struct media_stream *stream = &reader->streams[index];
1827 IMFAttributes *attributes = NULL;
1828 GUID major = { 0 };
1829 HRESULT hr;
1831 IMFMediaType_GetMajorType(stream->current, &major);
1832 if (!IsEqualGUID(&major, &MFMediaType_Video))
1833 return S_OK;
1835 if (!(reader->flags & SOURCE_READER_HAS_DEVICE_MANAGER))
1836 return S_OK;
1838 if (!stream->allocator)
1840 if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&stream->allocator)))
1842 WARN("Failed to create sample allocator, hr %#lx.\n", hr);
1843 return hr;
1847 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream->allocator);
1848 if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(stream->allocator, reader->device_manager)))
1850 WARN("Failed to set device manager, hr %#lx.\n", hr);
1851 return hr;
1854 if (FAILED(hr = source_reader_create_sample_allocator_attributes(reader, &attributes)))
1855 WARN("Failed to create allocator attributes, hr %#lx.\n", hr);
1857 if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8,
1858 attributes, stream->current)))
1860 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr);
1863 if (attributes)
1864 IMFAttributes_Release(attributes);
1866 return hr;
1869 static BOOL source_reader_allow_video_processor(struct source_reader *reader, BOOL *advanced)
1871 UINT32 value;
1873 *advanced = FALSE;
1874 if (!reader->attributes)
1875 return FALSE;
1877 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, &value)))
1878 *advanced = value;
1879 if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, &value)))
1880 return value || *advanced;
1882 return *advanced;
1885 static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL decoder, BOOL allow_processor,
1886 IMFMediaType *input_type, IMFMediaType *output_type, struct transform_entry **out)
1888 MFT_REGISTER_TYPE_INFO in_type, out_type;
1889 struct transform_entry *entry;
1890 GUID *classes, category;
1891 IMFTransform *transform;
1892 UINT i, count;
1893 HRESULT hr;
1895 if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &in_type.guidMajorType))
1896 || FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype)))
1897 return hr;
1898 if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType))
1899 || FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype)))
1900 return hr;
1902 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video))
1903 category = decoder ? MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_PROCESSOR;
1904 else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio))
1905 category = decoder ? MFT_CATEGORY_AUDIO_DECODER : MFT_CATEGORY_AUDIO_EFFECT;
1906 else
1907 return MF_E_TOPO_CODEC_NOT_FOUND;
1909 if (!(entry = calloc(1, sizeof(*entry))))
1910 return E_OUTOFMEMORY;
1911 list_init(&entry->entry);
1912 entry->category = category;
1914 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio))
1915 IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT,
1916 &entry->min_buffer_size);
1918 count = 0;
1919 if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, allow_processor ? NULL : &out_type, NULL, &classes, &count)))
1921 if (!count)
1922 return MF_E_TOPO_CODEC_NOT_FOUND;
1924 for (i = 0; i < count; i++)
1926 IMFMediaType *media_type;
1928 if (FAILED(hr = CoCreateInstance(&classes[i], NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform)))
1929 break;
1930 if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0))
1931 && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type)))
1933 if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type))
1934 && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0)) && allow_processor
1935 && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type)))
1937 struct transform_entry *converter;
1939 if (SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0))
1940 && SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type))
1941 && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, media_type, output_type, &converter)))
1942 list_add_tail(&entry->entry, &converter->entry);
1944 IMFMediaType_Release(media_type);
1947 if (SUCCEEDED(hr))
1949 entry->transform = transform;
1950 *out = entry;
1951 return S_OK;
1955 IMFTransform_Release(transform);
1958 CoTaskMemFree(classes);
1961 free(entry);
1962 return hr;
1965 static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type)
1967 BOOL enable_advanced, allow_processor;
1968 struct media_stream *stream = &reader->streams[index];
1969 IMFMediaType *input_type;
1970 unsigned int i = 0;
1971 HRESULT hr;
1973 allow_processor = source_reader_allow_video_processor(reader, &enable_advanced);
1975 while (SUCCEEDED(hr = source_reader_get_native_media_type(reader, index, i++, &input_type)))
1977 struct transform_entry *entry;
1979 /* first, try to append a single processor, then try again with a decoder and a processor */
1980 if ((allow_processor && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, input_type, output_type, &entry)))
1981 || SUCCEEDED(hr = source_reader_create_transform(reader, TRUE, allow_processor, input_type, output_type, &entry)))
1983 struct list *ptr = list_head(&entry->entry);
1984 struct transform_entry *service = ptr ? LIST_ENTRY(ptr, struct transform_entry, entry) : entry;
1985 IMFMediaTypeHandler *type_handler;
1987 if (enable_advanced)
1989 /* when advanced video processing is enabled, converters are exposed as stream transform service */
1990 stream->transform_service = service->transform;
1991 IMFTransform_AddRef(stream->transform_service);
1993 else
1995 /* when advanced video processing is disabled, only decoders are exposed as stream transform service */
1996 if (IsEqualGUID(&entry->category, &MFT_CATEGORY_AUDIO_DECODER)
1997 || IsEqualGUID(&entry->category, &MFT_CATEGORY_VIDEO_DECODER))
1999 stream->transform_service = entry->transform;
2000 IMFTransform_AddRef(stream->transform_service);
2004 /* move any additional transforms that have been created */
2005 list_move_head(&stream->transforms, &entry->entry);
2006 list_add_head(&stream->transforms, &entry->entry);
2008 if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler)))
2010 if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type)))
2011 WARN("Failed to set current input media type, hr %#lx\n", hr);
2012 IMFMediaTypeHandler_Release(type_handler);
2015 if (FAILED(hr = IMFTransform_GetOutputCurrentType(service->transform, 0, &output_type)))
2016 WARN("Failed to get decoder output media type, hr %#lx\n", hr);
2017 else
2019 IMFMediaType_CopyAllItems(output_type, (IMFAttributes *)stream->current);
2020 IMFMediaType_Release(output_type);
2023 IMFMediaType_Release(input_type);
2024 return S_OK;
2027 IMFMediaType_Release(input_type);
2030 return MF_E_TOPO_CODEC_NOT_FOUND;
2033 static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, DWORD index, DWORD *reserved,
2034 IMFMediaType *type)
2036 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2037 HRESULT hr;
2039 TRACE("%p, %#lx, %p, %p.\n", iface, index, reserved, type);
2041 switch (index)
2043 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2044 index = reader->first_video_stream_index;
2045 break;
2046 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2047 index = reader->first_audio_stream_index;
2048 break;
2049 default:
2053 if (index >= reader->stream_count)
2054 return MF_E_INVALIDSTREAMNUMBER;
2056 /* FIXME: setting the output type while streaming should trigger a flush */
2058 EnterCriticalSection(&reader->cs);
2060 hr = source_reader_set_compatible_media_type(reader, index, type);
2061 if (hr == S_FALSE)
2062 hr = source_reader_create_decoder_for_stream(reader, index, type);
2063 if (SUCCEEDED(hr))
2064 hr = source_reader_setup_sample_allocator(reader, index);
2066 LeaveCriticalSection(&reader->cs);
2068 return hr;
2071 static HRESULT WINAPI src_reader_SetCurrentPosition(IMFSourceReaderEx *iface, REFGUID format, REFPROPVARIANT position)
2073 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2074 struct source_reader_async_command *command;
2075 unsigned int i;
2076 DWORD flags;
2077 HRESULT hr;
2079 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), position);
2081 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
2082 return hr;
2084 if (!(flags & MFMEDIASOURCE_CAN_SEEK))
2085 return MF_E_INVALIDREQUEST;
2087 EnterCriticalSection(&reader->cs);
2089 /* Check if we got pending requests. */
2090 for (i = 0; i < reader->stream_count; ++i)
2092 if (reader->streams[i].requests)
2094 hr = MF_E_INVALIDREQUEST;
2095 break;
2099 if (SUCCEEDED(hr))
2101 for (i = 0; i < reader->stream_count; ++i)
2103 reader->streams[i].last_sample_ts = 0;
2106 if (reader->async_callback)
2108 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK, &command)))
2110 command->u.seek.format = *format;
2111 PropVariantCopy(&command->u.seek.position, position);
2113 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2114 IUnknown_Release(&command->IUnknown_iface);
2117 else
2119 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, format, position)))
2121 reader->flags |= SOURCE_READER_SEEKING;
2122 while (reader->flags & SOURCE_READER_SEEKING)
2124 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
2130 LeaveCriticalSection(&reader->cs);
2132 return hr;
2135 static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD index, DWORD flags, DWORD *actual_index,
2136 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2138 struct media_stream *stream;
2139 DWORD actual_index_tmp;
2140 LONGLONG timestamp_tmp;
2141 DWORD stream_index;
2142 HRESULT hr = S_OK;
2144 if (!stream_flags || !sample)
2145 return E_POINTER;
2147 *sample = NULL;
2149 if (!timestamp)
2150 timestamp = &timestamp_tmp;
2152 if (!actual_index)
2153 actual_index = &actual_index_tmp;
2155 if (SUCCEEDED(hr = source_reader_start_source(reader)))
2157 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, index, &stream_index)))
2159 *actual_index = stream_index;
2161 stream = &reader->streams[stream_index];
2163 if (!source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
2164 timestamp, sample))
2166 while (!source_reader_got_response_for_stream(reader, stream) && stream->state != STREAM_STATE_EOS)
2168 stream->requests++;
2169 if (FAILED(hr = source_reader_request_sample(reader, stream)))
2170 WARN("Failed to request a sample, hr %#lx.\n", hr);
2171 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
2173 *stream_flags = MF_SOURCE_READERF_ERROR;
2174 *timestamp = 0;
2175 break;
2177 SleepConditionVariableCS(&reader->sample_event, &reader->cs, INFINITE);
2179 if (SUCCEEDED(hr))
2180 source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
2181 timestamp, sample);
2184 else
2186 *actual_index = index;
2187 *stream_flags = MF_SOURCE_READERF_ERROR;
2188 *timestamp = 0;
2192 TRACE("Stream %lu, got sample %p, flags %#lx.\n", *actual_index, *sample, *stream_flags);
2194 return hr;
2197 static HRESULT source_reader_read_sample_async(struct source_reader *reader, unsigned int index, unsigned int flags,
2198 DWORD *actual_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2200 struct source_reader_async_command *command;
2201 HRESULT hr;
2203 if (actual_index || stream_flags || timestamp || sample)
2204 return E_INVALIDARG;
2206 if (reader->flags & SOURCE_READER_FLUSHING)
2207 hr = MF_E_NOTACCEPTING;
2208 else
2210 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_READ, &command)))
2212 command->u.read.stream_index = index;
2213 command->u.read.flags = flags;
2215 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2216 IUnknown_Release(&command->IUnknown_iface);
2220 return hr;
2223 static HRESULT WINAPI src_reader_ReadSample(IMFSourceReaderEx *iface, DWORD index, DWORD flags, DWORD *actual_index,
2224 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
2226 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2227 HRESULT hr;
2229 TRACE("%p, %#lx, %#lx, %p, %p, %p, %p\n", iface, index, flags, actual_index, stream_flags, timestamp, sample);
2231 EnterCriticalSection(&reader->cs);
2233 while (reader->flags & SOURCE_READER_SEEKING)
2235 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
2238 if (reader->async_callback)
2239 hr = source_reader_read_sample_async(reader, index, flags, actual_index, stream_flags, timestamp, sample);
2240 else
2241 hr = source_reader_read_sample(reader, index, flags, actual_index, stream_flags, timestamp, sample);
2243 LeaveCriticalSection(&reader->cs);
2245 return hr;
2248 static HRESULT source_reader_flush_async(struct source_reader *reader, unsigned int index)
2250 struct source_reader_async_command *command;
2251 unsigned int stream_index;
2252 HRESULT hr;
2254 if (reader->flags & SOURCE_READER_FLUSHING)
2255 return MF_E_INVALIDREQUEST;
2257 switch (index)
2259 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2260 stream_index = reader->first_video_stream_index;
2261 break;
2262 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2263 stream_index = reader->first_audio_stream_index;
2264 break;
2265 default:
2266 stream_index = index;
2269 reader->flags |= SOURCE_READER_FLUSHING;
2271 if (stream_index != MF_SOURCE_READER_ALL_STREAMS && stream_index >= reader->stream_count)
2272 return MF_E_INVALIDSTREAMNUMBER;
2274 if (FAILED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH, &command)))
2275 return hr;
2277 command->u.flush.stream_index = stream_index;
2279 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2280 IUnknown_Release(&command->IUnknown_iface);
2282 return hr;
2285 static HRESULT WINAPI src_reader_Flush(IMFSourceReaderEx *iface, DWORD index)
2287 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2288 HRESULT hr;
2290 TRACE("%p, %#lx.\n", iface, index);
2292 EnterCriticalSection(&reader->cs);
2294 if (reader->async_callback)
2295 hr = source_reader_flush_async(reader, index);
2296 else
2297 hr = source_reader_flush(reader, index);
2299 LeaveCriticalSection(&reader->cs);
2301 return hr;
2304 static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReaderEx *iface, DWORD index, REFGUID service,
2305 REFIID riid, void **object)
2307 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2308 struct media_stream *stream = &reader->streams[index];
2309 IUnknown *obj = NULL;
2310 HRESULT hr = S_OK;
2312 TRACE("%p, %#lx, %s, %s, %p\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object);
2314 EnterCriticalSection(&reader->cs);
2316 switch (index)
2318 case MF_SOURCE_READER_MEDIASOURCE:
2319 obj = (IUnknown *)reader->source;
2320 break;
2321 default:
2322 if (index == MF_SOURCE_READER_FIRST_VIDEO_STREAM)
2323 index = reader->first_video_stream_index;
2324 else if (index == MF_SOURCE_READER_FIRST_AUDIO_STREAM)
2325 index = reader->first_audio_stream_index;
2327 if (index >= reader->stream_count)
2328 hr = MF_E_INVALIDSTREAMNUMBER;
2329 else if (!(obj = (IUnknown *)stream->transform_service))
2330 hr = E_NOINTERFACE;
2331 break;
2334 if (obj)
2335 IUnknown_AddRef(obj);
2337 LeaveCriticalSection(&reader->cs);
2339 if (obj)
2341 if (IsEqualGUID(service, &GUID_NULL))
2343 hr = IUnknown_QueryInterface(obj, riid, object);
2345 else
2347 IMFGetService *gs;
2349 hr = IUnknown_QueryInterface(obj, &IID_IMFGetService, (void **)&gs);
2350 if (SUCCEEDED(hr))
2352 hr = IMFGetService_GetService(gs, service, riid, object);
2353 IMFGetService_Release(gs);
2358 if (obj)
2359 IUnknown_Release(obj);
2361 return hr;
2364 static HRESULT WINAPI src_reader_GetPresentationAttribute(IMFSourceReaderEx *iface, DWORD index,
2365 REFGUID guid, PROPVARIANT *value)
2367 struct source_reader *reader = impl_from_IMFSourceReaderEx(iface);
2368 IMFStreamDescriptor *sd;
2369 BOOL selected;
2370 HRESULT hr;
2372 TRACE("%p, %#lx, %s, %p.\n", iface, index, debugstr_guid(guid), value);
2374 switch (index)
2376 case MF_SOURCE_READER_MEDIASOURCE:
2377 if (IsEqualGUID(guid, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS))
2379 DWORD flags;
2381 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
2382 return hr;
2384 value->vt = VT_UI4;
2385 value->ulVal = flags;
2386 return S_OK;
2388 else
2390 return IMFPresentationDescriptor_GetItem(reader->descriptor, guid, value);
2392 break;
2393 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2394 index = reader->first_video_stream_index;
2395 break;
2396 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2397 index = reader->first_audio_stream_index;
2398 break;
2399 default:
2403 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
2404 return hr;
2406 hr = IMFStreamDescriptor_GetItem(sd, guid, value);
2407 IMFStreamDescriptor_Release(sd);
2409 return hr;
2412 static HRESULT WINAPI src_reader_SetNativeMediaType(IMFSourceReaderEx *iface, DWORD stream_index,
2413 IMFMediaType *media_type, DWORD *stream_flags)
2415 FIXME("%p, %#lx, %p, %p.\n", iface, stream_index, media_type, stream_flags);
2417 return E_NOTIMPL;
2420 static HRESULT WINAPI src_reader_AddTransformForStream(IMFSourceReaderEx *iface, DWORD stream_index,
2421 IUnknown *transform)
2423 FIXME("%p, %#lx, %p.\n", iface, stream_index, transform);
2425 return E_NOTIMPL;
2428 static HRESULT WINAPI src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx *iface, DWORD stream_index)
2430 FIXME("%p, %#lx.\n", iface, stream_index);
2432 return E_NOTIMPL;
2435 static HRESULT WINAPI src_reader_GetTransformForStream(IMFSourceReaderEx *iface, DWORD stream_index,
2436 DWORD transform_index, GUID *category, IMFTransform **transform)
2438 FIXME("%p, %#lx, %#lx, %p, %p.\n", iface, stream_index, transform_index, category, transform);
2440 return E_NOTIMPL;
2443 static const IMFSourceReaderExVtbl srcreader_vtbl =
2445 src_reader_QueryInterface,
2446 src_reader_AddRef,
2447 src_reader_Release,
2448 src_reader_GetStreamSelection,
2449 src_reader_SetStreamSelection,
2450 src_reader_GetNativeMediaType,
2451 src_reader_GetCurrentMediaType,
2452 src_reader_SetCurrentMediaType,
2453 src_reader_SetCurrentPosition,
2454 src_reader_ReadSample,
2455 src_reader_Flush,
2456 src_reader_GetServiceForStream,
2457 src_reader_GetPresentationAttribute,
2458 src_reader_SetNativeMediaType,
2459 src_reader_AddTransformForStream,
2460 src_reader_RemoveAllTransformsForStream,
2461 src_reader_GetTransformForStream,
2464 static DWORD reader_get_first_stream_index(IMFPresentationDescriptor *descriptor, const GUID *major)
2466 DWORD count, i;
2467 BOOL selected;
2468 HRESULT hr;
2469 GUID guid;
2471 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count)))
2472 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2474 for (i = 0; i < count; ++i)
2476 IMFMediaTypeHandler *handler;
2477 IMFStreamDescriptor *sd;
2479 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i, &selected, &sd)))
2481 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2482 IMFStreamDescriptor_Release(sd);
2483 if (SUCCEEDED(hr))
2485 hr = IMFMediaTypeHandler_GetMajorType(handler, &guid);
2486 IMFMediaTypeHandler_Release(handler);
2487 if (FAILED(hr))
2489 WARN("Failed to get stream major type, hr %#lx.\n", hr);
2490 continue;
2493 if (IsEqualGUID(&guid, major))
2495 return i;
2501 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2504 static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttributes *attributes,
2505 BOOL shutdown_on_release, REFIID riid, void **out)
2507 struct source_reader *object;
2508 unsigned int i;
2509 HRESULT hr;
2511 object = calloc(1, sizeof(*object));
2512 if (!object)
2513 return E_OUTOFMEMORY;
2515 object->IMFSourceReaderEx_iface.lpVtbl = &srcreader_vtbl;
2516 object->source_events_callback.lpVtbl = &source_events_callback_vtbl;
2517 object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl;
2518 object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl;
2519 object->public_refcount = 1;
2520 object->refcount = 1;
2521 list_init(&object->responses);
2522 if (shutdown_on_release)
2523 object->flags |= SOURCE_READER_SHUTDOWN_ON_RELEASE;
2524 object->source = source;
2525 IMFMediaSource_AddRef(object->source);
2526 InitializeCriticalSection(&object->cs);
2527 InitializeConditionVariable(&object->sample_event);
2528 InitializeConditionVariable(&object->state_event);
2529 InitializeConditionVariable(&object->stop_event);
2531 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor)))
2532 goto failed;
2534 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(object->descriptor, &object->stream_count)))
2535 goto failed;
2537 if (!(object->streams = calloc(object->stream_count, sizeof(*object->streams))))
2539 hr = E_OUTOFMEMORY;
2540 goto failed;
2543 /* Set initial current media types. */
2544 for (i = 0; i < object->stream_count; ++i)
2546 IMFMediaTypeHandler *handler;
2547 IMFStreamDescriptor *sd;
2548 IMFMediaType *src_type;
2549 BOOL selected;
2551 list_init(&object->streams[i].transforms);
2553 if (FAILED(hr = MFCreateMediaType(&object->streams[i].current)))
2554 break;
2556 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(object->descriptor, i, &selected, &sd)))
2557 break;
2559 if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &object->streams[i].id)))
2560 WARN("Failed to get stream identifier, hr %#lx.\n", hr);
2562 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2563 IMFStreamDescriptor_Release(sd);
2564 if (FAILED(hr))
2565 break;
2567 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &src_type);
2568 IMFMediaTypeHandler_Release(handler);
2569 if (FAILED(hr))
2570 break;
2572 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)object->streams[i].current);
2573 IMFMediaType_Release(src_type);
2574 if (FAILED(hr))
2575 break;
2577 object->streams[i].reader = object;
2578 object->streams[i].index = i;
2581 if (FAILED(hr))
2582 goto failed;
2584 /* At least one major type has to be set. */
2585 object->first_audio_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Audio);
2586 object->first_video_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Video);
2588 if (object->first_audio_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX &&
2589 object->first_video_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX)
2591 hr = MF_E_ATTRIBUTENOTFOUND;
2594 if (FAILED(hr = IMFMediaSource_BeginGetEvent(object->source, &object->source_events_callback,
2595 (IUnknown *)object->source)))
2597 goto failed;
2600 if (attributes)
2602 object->attributes = attributes;
2603 IMFAttributes_AddRef(object->attributes);
2605 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_ASYNC_CALLBACK, &IID_IMFSourceReaderCallback,
2606 (void **)&object->async_callback);
2607 if (object->async_callback)
2608 TRACE("Using async callback %p.\n", object->async_callback);
2610 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, &IID_IUnknown, (void **)&object->device_manager);
2611 if (object->device_manager)
2613 IUnknown *unk = NULL;
2615 if (SUCCEEDED(IUnknown_QueryInterface(object->device_manager, &IID_IMFDXGIDeviceManager, (void **)&unk)))
2616 object->flags |= SOURCE_READER_DXGI_DEVICE_MANAGER;
2617 else if (SUCCEEDED(IUnknown_QueryInterface(object->device_manager, &IID_IDirect3DDeviceManager9, (void **)&unk)))
2618 object->flags |= SOURCE_READER_D3D9_DEVICE_MANAGER;
2620 if (!(object->flags & (SOURCE_READER_HAS_DEVICE_MANAGER)))
2622 WARN("Unknown device manager.\n");
2623 IUnknown_Release(object->device_manager);
2624 object->device_manager = NULL;
2627 if (unk)
2628 IUnknown_Release(unk);
2632 if (FAILED(hr = MFLockSharedWorkQueue(L"", 0, NULL, &object->queue)))
2633 WARN("Failed to acquired shared queue, hr %#lx.\n", hr);
2635 if (SUCCEEDED(hr))
2636 hr = IMFSourceReaderEx_QueryInterface(&object->IMFSourceReaderEx_iface, riid, out);
2638 failed:
2639 IMFSourceReaderEx_Release(&object->IMFSourceReaderEx_iface);
2640 return hr;
2643 static HRESULT create_source_reader_from_stream(IMFByteStream *stream, IMFAttributes *attributes,
2644 REFIID riid, void **out)
2646 IPropertyStore *props = NULL;
2647 IMFSourceResolver *resolver;
2648 MF_OBJECT_TYPE obj_type;
2649 IMFMediaSource *source;
2650 HRESULT hr;
2652 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2653 return hr;
2655 if (attributes)
2656 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2657 (void **)&props);
2659 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE
2660 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, props, &obj_type, (IUnknown **)&source);
2661 IMFSourceResolver_Release(resolver);
2662 if (props)
2663 IPropertyStore_Release(props);
2664 if (FAILED(hr))
2665 return hr;
2667 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2668 IMFMediaSource_Release(source);
2669 return hr;
2672 static HRESULT create_source_reader_from_url(const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2674 IPropertyStore *props = NULL;
2675 IMFSourceResolver *resolver;
2676 IUnknown *object = NULL;
2677 MF_OBJECT_TYPE obj_type;
2678 IMFMediaSource *source;
2679 HRESULT hr;
2681 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2682 return hr;
2684 if (attributes)
2685 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2686 (void **)&props);
2688 hr = IMFSourceResolver_CreateObjectFromURL(resolver, url, MF_RESOLUTION_MEDIASOURCE, props, &obj_type,
2689 &object);
2690 if (SUCCEEDED(hr))
2692 switch (obj_type)
2694 case MF_OBJECT_BYTESTREAM:
2695 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, (IMFByteStream *)object, NULL,
2696 MF_RESOLUTION_MEDIASOURCE, props, &obj_type, (IUnknown **)&source);
2697 break;
2698 case MF_OBJECT_MEDIASOURCE:
2699 source = (IMFMediaSource *)object;
2700 IMFMediaSource_AddRef(source);
2701 break;
2702 default:
2703 WARN("Unknown object type %d.\n", obj_type);
2704 hr = E_UNEXPECTED;
2706 IUnknown_Release(object);
2709 IMFSourceResolver_Release(resolver);
2710 if (props)
2711 IPropertyStore_Release(props);
2712 if (FAILED(hr))
2713 return hr;
2715 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2716 IMFMediaSource_Release(source);
2717 return hr;
2720 static HRESULT create_source_reader_from_object(IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2722 IMFMediaSource *source = NULL;
2723 IMFByteStream *stream = NULL;
2724 HRESULT hr;
2726 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSource, (void **)&source);
2727 if (FAILED(hr))
2728 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2730 if (source)
2732 UINT32 disconnect = 0;
2734 if (attributes)
2735 IMFAttributes_GetUINT32(attributes, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN, &disconnect);
2736 hr = create_source_reader_from_source(source, attributes, !disconnect, riid, out);
2738 else if (stream)
2739 hr = create_source_reader_from_stream(stream, attributes, riid, out);
2741 if (source)
2742 IMFMediaSource_Release(source);
2743 if (stream)
2744 IMFByteStream_Release(stream);
2746 return hr;
2749 /***********************************************************************
2750 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2752 HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes,
2753 IMFSourceReader **reader)
2755 TRACE("%p, %p, %p.\n", stream, attributes, reader);
2757 return create_source_reader_from_object((IUnknown *)stream, attributes, &IID_IMFSourceReader, (void **)reader);
2760 /***********************************************************************
2761 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2763 HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes,
2764 IMFSourceReader **reader)
2766 TRACE("%p, %p, %p.\n", source, attributes, reader);
2768 return create_source_reader_from_object((IUnknown *)source, attributes, &IID_IMFSourceReader, (void **)reader);
2771 /***********************************************************************
2772 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2774 HRESULT WINAPI MFCreateSourceReaderFromURL(const WCHAR *url, IMFAttributes *attributes, IMFSourceReader **reader)
2776 TRACE("%s, %p, %p.\n", debugstr_w(url), attributes, reader);
2778 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, (void **)reader);
2781 static HRESULT WINAPI readwrite_factory_QueryInterface(IMFReadWriteClassFactory *iface, REFIID riid, void **out)
2783 if (IsEqualIID(riid, &IID_IMFReadWriteClassFactory) ||
2784 IsEqualIID(riid, &IID_IUnknown))
2786 *out = iface;
2787 IMFReadWriteClassFactory_AddRef(iface);
2788 return S_OK;
2791 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
2792 *out = NULL;
2793 return E_NOINTERFACE;
2796 static ULONG WINAPI readwrite_factory_AddRef(IMFReadWriteClassFactory *iface)
2798 return 2;
2801 static ULONG WINAPI readwrite_factory_Release(IMFReadWriteClassFactory *iface)
2803 return 1;
2806 static HRESULT WINAPI readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2807 const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2809 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid), debugstr_w(url), attributes, debugstr_guid(riid), out);
2811 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2813 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, out);
2815 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
2817 return create_sink_writer_from_url(url, NULL, attributes, riid, out);
2820 FIXME("Unsupported %s.\n", debugstr_guid(clsid));
2822 return E_NOTIMPL;
2825 static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2826 IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2828 HRESULT hr;
2830 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid), unk, attributes, debugstr_guid(riid), out);
2832 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2834 return create_source_reader_from_object(unk, attributes, riid, out);
2836 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
2838 IMFByteStream *stream = NULL;
2839 IMFMediaSink *sink = NULL;
2841 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2842 if (FAILED(hr))
2843 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSink, (void **)&sink);
2845 if (stream)
2846 hr = create_sink_writer_from_url(NULL, stream, attributes, riid, out);
2847 else if (sink)
2848 hr = create_sink_writer_from_sink(sink, attributes, riid, out);
2850 if (sink)
2851 IMFMediaSink_Release(sink);
2852 if (stream)
2853 IMFByteStream_Release(stream);
2855 return hr;
2857 else
2859 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2860 *out = NULL;
2861 return E_FAIL;
2865 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl =
2867 readwrite_factory_QueryInterface,
2868 readwrite_factory_AddRef,
2869 readwrite_factory_Release,
2870 readwrite_factory_CreateInstanceFromURL,
2871 readwrite_factory_CreateInstanceFromObject,
2874 static IMFReadWriteClassFactory readwrite_factory = { &readwrite_factory_vtbl };
2876 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
2878 TRACE("%s, %p.\n", debugstr_guid(riid), out);
2880 if (IsEqualGUID(riid, &IID_IClassFactory) ||
2881 IsEqualGUID(riid, &IID_IUnknown))
2883 IClassFactory_AddRef(iface);
2884 *out = iface;
2885 return S_OK;
2888 WARN("interface %s not implemented\n", debugstr_guid(riid));
2889 *out = NULL;
2890 return E_NOINTERFACE;
2893 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
2895 return 2;
2898 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
2900 return 1;
2903 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out)
2905 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), out);
2907 *out = NULL;
2909 if (outer)
2910 return CLASS_E_NOAGGREGATION;
2912 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory, riid, out);
2915 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
2917 FIXME("%d.\n", dolock);
2918 return S_OK;
2921 static const IClassFactoryVtbl classfactoryvtbl =
2923 classfactory_QueryInterface,
2924 classfactory_AddRef,
2925 classfactory_Release,
2926 classfactory_CreateInstance,
2927 classfactory_LockServer,
2930 static IClassFactory classfactory = { &classfactoryvtbl };
2932 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
2934 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), out);
2936 if (IsEqualGUID(clsid, &CLSID_MFReadWriteClassFactory))
2937 return IClassFactory_QueryInterface(&classfactory, riid, out);
2939 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2940 *out = NULL;
2941 return CLASS_E_CLASSNOTAVAILABLE;