wined3d: Correctly destroy the adapter on format initialization failure in no3d mode.
[wine/zf.git] / dlls / mfreadwrite / reader.c
blob96a82b798ab3b50bfefb3aba839b66aa551893ee
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 #define NONAMELESSUNION
25 #include "windef.h"
26 #include "winbase.h"
27 #include "ole2.h"
28 #include "rpcproxy.h"
30 #undef INITGUID
31 #include <guiddef.h>
32 #include "mfapi.h"
33 #include "mferror.h"
34 #include "mfidl.h"
35 #include "mfreadwrite.h"
37 #include "wine/debug.h"
38 #include "wine/heap.h"
39 #include "wine/list.h"
41 #include "mf_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
45 static HINSTANCE mfinstance;
47 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
49 switch (reason)
51 case DLL_WINE_PREATTACH:
52 return FALSE; /* prefer native version */
53 case DLL_PROCESS_ATTACH:
54 mfinstance = instance;
55 DisableThreadLibraryCalls(instance);
56 break;
59 return TRUE;
62 HRESULT WINAPI DllCanUnloadNow(void)
64 return S_FALSE;
67 HRESULT WINAPI DllRegisterServer(void)
69 return __wine_register_resources( mfinstance );
72 HRESULT WINAPI DllUnregisterServer(void)
74 return __wine_unregister_resources( mfinstance );
77 struct stream_response
79 struct list entry;
80 HRESULT status;
81 DWORD stream_index;
82 DWORD stream_flags;
83 LONGLONG timestamp;
84 IMFSample *sample;
87 enum media_stream_state
89 STREAM_STATE_READY = 0,
90 STREAM_STATE_EOS,
93 enum media_source_state
95 SOURCE_STATE_STOPPED = 0,
96 SOURCE_STATE_STARTED,
99 enum media_stream_flags
101 STREAM_FLAG_SAMPLE_REQUESTED = 0x1, /* Protects from making multiple sample requests. */
102 STREAM_FLAG_SELECTED = 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
103 STREAM_FLAG_PRESENTED = 0x4, /* Set if stream was selected last time Start() was called. */
104 STREAM_FLAG_REQUESTED_ONCE = 0x8, /* Used for MF_SOURCE_READER_ANY_STREAM in synchronous mode. */
107 struct media_stream
109 IMFMediaStream *stream;
110 IMFMediaType *current;
111 IMFTransform *decoder;
112 DWORD id;
113 unsigned int index;
114 enum media_stream_state state;
115 unsigned int flags;
116 unsigned int requests;
117 unsigned int responses;
120 enum source_reader_async_op
122 SOURCE_READER_ASYNC_READ,
123 SOURCE_READER_ASYNC_SEEK,
124 SOURCE_READER_ASYNC_FLUSH,
125 SOURCE_READER_ASYNC_SAMPLE_READY,
128 struct source_reader_async_command
130 IUnknown IUnknown_iface;
131 LONG refcount;
132 enum source_reader_async_op op;
133 union
135 struct
137 unsigned int flags;
138 unsigned int stream_index;
139 } read;
140 struct
142 GUID format;
143 PROPVARIANT position;
144 } seek;
145 struct
147 unsigned int stream_index;
148 } flush;
149 struct
151 unsigned int stream_index;
152 } sample;
153 } u;
156 enum source_reader_flags
158 SOURCE_READER_FLUSHING = 0x1,
159 SOURCE_READER_SEEKING = 0x2,
160 SOURCE_READER_SHUTDOWN_ON_RELEASE = 0x4,
163 struct source_reader
165 IMFSourceReader IMFSourceReader_iface;
166 IMFAsyncCallback source_events_callback;
167 IMFAsyncCallback stream_events_callback;
168 IMFAsyncCallback async_commands_callback;
169 LONG refcount;
170 IMFMediaSource *source;
171 IMFPresentationDescriptor *descriptor;
172 DWORD first_audio_stream_index;
173 DWORD first_video_stream_index;
174 IMFSourceReaderCallback *async_callback;
175 unsigned int flags;
176 enum media_source_state source_state;
177 struct media_stream *streams;
178 DWORD stream_count;
179 struct list responses;
180 CRITICAL_SECTION cs;
181 CONDITION_VARIABLE sample_event;
182 CONDITION_VARIABLE state_event;
185 static inline struct source_reader *impl_from_IMFSourceReader(IMFSourceReader *iface)
187 return CONTAINING_RECORD(iface, struct source_reader, IMFSourceReader_iface);
190 static struct source_reader *impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
192 return CONTAINING_RECORD(iface, struct source_reader, source_events_callback);
195 static struct source_reader *impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
197 return CONTAINING_RECORD(iface, struct source_reader, stream_events_callback);
200 static struct source_reader *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
202 return CONTAINING_RECORD(iface, struct source_reader, async_commands_callback);
205 static struct source_reader_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
207 return CONTAINING_RECORD(iface, struct source_reader_async_command, IUnknown_iface);
210 static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
212 if (IsEqualIID(riid, &IID_IUnknown))
214 *obj = iface;
215 IUnknown_AddRef(iface);
216 return S_OK;
219 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
220 *obj = NULL;
221 return E_NOINTERFACE;
224 static ULONG WINAPI source_reader_async_command_AddRef(IUnknown *iface)
226 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
227 return InterlockedIncrement(&command->refcount);
230 static ULONG WINAPI source_reader_async_command_Release(IUnknown *iface)
232 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
233 ULONG refcount = InterlockedIncrement(&command->refcount);
235 if (!refcount)
237 if (command->op == SOURCE_READER_ASYNC_SEEK)
238 PropVariantClear(&command->u.seek.position);
239 heap_free(command);
242 return refcount;
245 static const IUnknownVtbl source_reader_async_command_vtbl =
247 source_reader_async_command_QueryInterface,
248 source_reader_async_command_AddRef,
249 source_reader_async_command_Release,
252 static HRESULT source_reader_create_async_op(enum source_reader_async_op op, struct source_reader_async_command **ret)
254 struct source_reader_async_command *command;
256 if (!(command = heap_alloc_zero(sizeof(*command))))
257 return E_OUTOFMEMORY;
259 command->IUnknown_iface.lpVtbl = &source_reader_async_command_vtbl;
260 command->op = op;
262 *ret = command;
264 return S_OK;
267 static HRESULT media_event_get_object(IMFMediaEvent *event, REFIID riid, void **obj)
269 PROPVARIANT value;
270 HRESULT hr;
272 PropVariantInit(&value);
273 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
275 WARN("Failed to get event value, hr %#x.\n", hr);
276 return hr;
279 if (value.vt != VT_UNKNOWN || !value.u.punkVal)
281 WARN("Unexpected value type %d.\n", value.vt);
282 PropVariantClear(&value);
283 return E_UNEXPECTED;
286 hr = IUnknown_QueryInterface(value.u.punkVal, riid, obj);
287 PropVariantClear(&value);
288 if (FAILED(hr))
290 WARN("Unexpected object type.\n");
291 return hr;
294 return hr;
297 static HRESULT media_stream_get_id(IMFMediaStream *stream, DWORD *id)
299 IMFStreamDescriptor *sd;
300 HRESULT hr;
302 if (SUCCEEDED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
304 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, id);
305 IMFStreamDescriptor_Release(sd);
308 return hr;
311 static HRESULT WINAPI source_reader_callback_QueryInterface(IMFAsyncCallback *iface,
312 REFIID riid, void **obj)
314 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
316 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
317 IsEqualIID(riid, &IID_IUnknown))
319 *obj = iface;
320 IMFAsyncCallback_AddRef(iface);
321 return S_OK;
324 WARN("Unsupported %s.\n", debugstr_guid(riid));
325 *obj = NULL;
326 return E_NOINTERFACE;
329 static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface)
331 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
332 return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
335 static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface)
337 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
338 return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
341 static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface,
342 DWORD *flags, DWORD *queue)
344 return E_NOTIMPL;
347 static void source_reader_queue_response(struct source_reader *reader, struct media_stream *stream, HRESULT status,
348 DWORD stream_flags, LONGLONG timestamp, IMFSample *sample)
350 struct source_reader_async_command *command;
351 struct stream_response *response;
352 HRESULT hr;
354 response = heap_alloc_zero(sizeof(*response));
355 response->status = status;
356 response->stream_index = stream->index;
357 response->stream_flags = stream_flags;
358 response->timestamp = timestamp;
359 response->sample = sample;
360 if (response->sample)
361 IMFSample_AddRef(response->sample);
363 list_add_tail(&reader->responses, &response->entry);
364 stream->responses++;
366 if (stream->requests)
368 if (reader->async_callback)
370 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY, &command)))
372 command->u.sample.stream_index = stream->index;
373 if (FAILED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &reader->async_commands_callback,
374 &command->IUnknown_iface)))
375 WARN("Failed to submit async result, hr %#x.\n", hr);
376 IUnknown_Release(&command->IUnknown_iface);
379 else
380 WakeAllConditionVariable(&reader->sample_event);
382 stream->requests--;
386 static HRESULT source_reader_request_sample(struct source_reader *reader, struct media_stream *stream)
388 HRESULT hr = S_OK;
390 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
392 if (FAILED(hr = IMFMediaStream_RequestSample(stream->stream, NULL)))
393 WARN("Sample request failed, hr %#x.\n", hr);
394 else
396 stream->flags |= (STREAM_FLAG_SAMPLE_REQUESTED | STREAM_FLAG_REQUESTED_ONCE);
400 return hr;
403 static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IMFMediaEvent *event)
405 IMFMediaStream *stream;
406 unsigned int i;
407 DWORD id = 0;
408 HRESULT hr;
410 if (FAILED(hr = media_event_get_object(event, &IID_IMFMediaStream, (void **)&stream)))
412 WARN("Failed to get stream object, hr %#x.\n", hr);
413 return hr;
416 TRACE("Got new stream %p.\n", stream);
418 if (FAILED(hr = media_stream_get_id(stream, &id)))
420 WARN("Unidentified stream %p, hr %#x.\n", stream, hr);
421 IMFMediaStream_Release(stream);
422 return hr;
425 EnterCriticalSection(&reader->cs);
427 for (i = 0; i < reader->stream_count; ++i)
429 if (id == reader->streams[i].id)
431 if (!reader->streams[i].stream)
433 reader->streams[i].stream = stream;
434 IMFMediaStream_AddRef(reader->streams[i].stream);
435 if (FAILED(hr = IMFMediaStream_BeginGetEvent(stream, &reader->stream_events_callback,
436 (IUnknown *)stream)))
438 WARN("Failed to subscribe to stream events, hr %#x.\n", hr);
441 if (reader->streams[i].requests)
442 source_reader_request_sample(reader, &reader->streams[i]);
444 break;
448 if (i == reader->stream_count)
449 WARN("Stream with id %#x was not present in presentation descriptor.\n", id);
451 LeaveCriticalSection(&reader->cs);
453 IMFMediaStream_Release(stream);
455 return hr;
458 static HRESULT source_reader_source_state_handler(struct source_reader *reader, MediaEventType event_type)
460 EnterCriticalSection(&reader->cs);
462 switch (event_type)
464 case MESourceStarted:
465 reader->source_state = SOURCE_STATE_STARTED;
466 break;
467 case MESourceStopped:
468 reader->source_state = SOURCE_STATE_STOPPED;
469 break;
470 case MESourceSeeked:
471 reader->flags &= ~SOURCE_READER_SEEKING;
472 break;
473 default:
474 WARN("Unhandled event %d.\n", event_type);
477 LeaveCriticalSection(&reader->cs);
479 WakeAllConditionVariable(&reader->state_event);
481 return S_OK;
484 static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
486 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
487 MediaEventType event_type;
488 IMFMediaSource *source;
489 IMFMediaEvent *event;
490 HRESULT hr;
492 TRACE("%p, %p.\n", iface, result);
494 source = (IMFMediaSource *)IMFAsyncResult_GetStateNoAddRef(result);
496 if (FAILED(hr = IMFMediaSource_EndGetEvent(source, result, &event)))
497 return hr;
499 IMFMediaEvent_GetType(event, &event_type);
501 TRACE("Got event %u.\n", event_type);
503 switch (event_type)
505 case MENewStream:
506 hr = source_reader_new_stream_handler(reader, event);
507 break;
508 case MESourceStarted:
509 case MESourcePaused:
510 case MESourceStopped:
511 case MESourceSeeked:
512 hr = source_reader_source_state_handler(reader, event_type);
513 break;
514 case MEBufferingStarted:
515 case MEBufferingStopped:
516 case MEConnectStart:
517 case MEConnectEnd:
518 case MEExtendedType:
519 case MESourceCharacteristicsChanged:
520 case MESourceMetadataChanged:
521 case MEContentProtectionMetadata:
522 case MEDeviceThermalStateChanged:
523 if (reader->async_callback)
524 IMFSourceReaderCallback_OnEvent(reader->async_callback, MF_SOURCE_READER_MEDIASOURCE, event);
525 break;
526 default:
530 if (FAILED(hr))
531 WARN("Failed while handling %d event, hr %#x.\n", event_type, hr);
533 IMFMediaEvent_Release(event);
535 IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
537 return S_OK;
540 static const IMFAsyncCallbackVtbl source_events_callback_vtbl =
542 source_reader_callback_QueryInterface,
543 source_reader_source_events_callback_AddRef,
544 source_reader_source_events_callback_Release,
545 source_reader_callback_GetParameters,
546 source_reader_source_events_callback_Invoke,
549 static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface)
551 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
552 return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
555 static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface)
557 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
558 return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
561 static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, struct media_stream *stream)
563 MFT_OUTPUT_STREAM_INFO stream_info = { 0 };
564 MFT_OUTPUT_DATA_BUFFER out_buffer;
565 IMFMediaBuffer *buffer;
566 LONGLONG timestamp;
567 DWORD status;
568 HRESULT hr;
570 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(stream->decoder, 0, &stream_info)))
572 WARN("Failed to get output stream info, hr %#x.\n", hr);
573 return hr;
576 for (;;)
578 memset(&out_buffer, 0, sizeof(out_buffer));
580 if (!(stream_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
582 if (FAILED(hr = MFCreateSample(&out_buffer.pSample)))
583 break;
585 if (FAILED(hr = MFCreateAlignedMemoryBuffer(stream_info.cbSize, stream_info.cbAlignment, &buffer)))
587 IMFSample_Release(out_buffer.pSample);
588 break;
591 IMFSample_AddBuffer(out_buffer.pSample, buffer);
592 IMFMediaBuffer_Release(buffer);
595 if (FAILED(hr = IMFTransform_ProcessOutput(stream->decoder, 0, 1, &out_buffer, &status)))
597 if (out_buffer.pSample)
598 IMFSample_Release(out_buffer.pSample);
599 break;
602 timestamp = 0;
603 if (FAILED(IMFSample_GetSampleTime(out_buffer.pSample, &timestamp)))
604 WARN("Sample time wasn't set.\n");
606 source_reader_queue_response(reader, stream, S_OK /* FIXME */, 0, timestamp, out_buffer.pSample);
607 if (out_buffer.pSample)
608 IMFSample_Release(out_buffer.pSample);
609 if (out_buffer.pEvents)
610 IMFCollection_Release(out_buffer.pEvents);
613 return hr;
616 static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream,
617 IMFSample *sample)
619 LONGLONG timestamp;
620 HRESULT hr;
622 if (!stream->decoder)
624 timestamp = 0;
625 if (FAILED(IMFSample_GetSampleTime(sample, &timestamp)))
626 WARN("Sample time wasn't set.\n");
628 source_reader_queue_response(reader, stream, S_OK, 0, timestamp, sample);
629 return S_OK;
632 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
634 hr = source_reader_pull_stream_samples(reader, stream);
635 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
637 if (FAILED(hr = IMFTransform_ProcessInput(stream->decoder, 0, sample, 0)))
639 WARN("Transform failed to process input, hr %#x.\n", hr);
640 return hr;
643 if ((hr = source_reader_pull_stream_samples(reader, stream)) == MF_E_TRANSFORM_NEED_MORE_INPUT)
644 return S_OK;
646 else
647 WARN("Transform failed to process output, hr %#x.\n", hr);
649 return hr;
652 static HRESULT source_reader_media_sample_handler(struct source_reader *reader, IMFMediaStream *stream,
653 IMFMediaEvent *event)
655 IMFSample *sample;
656 unsigned int i;
657 DWORD id = 0;
658 HRESULT hr;
660 TRACE("Got new sample for stream %p.\n", stream);
662 if (FAILED(hr = media_event_get_object(event, &IID_IMFSample, (void **)&sample)))
664 WARN("Failed to get sample object, hr %#x.\n", hr);
665 return hr;
668 if (FAILED(hr = media_stream_get_id(stream, &id)))
670 WARN("Unidentified stream %p, hr %#x.\n", stream, hr);
671 IMFSample_Release(sample);
672 return hr;
675 EnterCriticalSection(&reader->cs);
677 for (i = 0; i < reader->stream_count; ++i)
679 if (id == reader->streams[i].id)
681 /* FIXME: propagate processing errors? */
683 reader->streams[i].flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
684 hr = source_reader_process_sample(reader, &reader->streams[i], sample);
685 if (reader->streams[i].requests)
686 source_reader_request_sample(reader, &reader->streams[i]);
688 break;
692 if (i == reader->stream_count)
693 WARN("Stream with id %#x was not present in presentation descriptor.\n", id);
695 LeaveCriticalSection(&reader->cs);
697 IMFSample_Release(sample);
699 return hr;
702 static HRESULT source_reader_media_stream_state_handler(struct source_reader *reader, IMFMediaStream *stream,
703 IMFMediaEvent *event)
705 MediaEventType event_type;
706 LONGLONG timestamp;
707 PROPVARIANT value;
708 unsigned int i;
709 HRESULT hr;
710 DWORD id;
712 IMFMediaEvent_GetType(event, &event_type);
714 if (FAILED(hr = media_stream_get_id(stream, &id)))
716 WARN("Unidentified stream %p, hr %#x.\n", stream, hr);
717 return hr;
720 EnterCriticalSection(&reader->cs);
722 for (i = 0; i < reader->stream_count; ++i)
724 struct media_stream *stream = &reader->streams[i];
726 if (id == stream->id)
728 switch (event_type)
730 case MEEndOfStream:
731 stream->state = STREAM_STATE_EOS;
732 stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
734 if (stream->decoder && SUCCEEDED(IMFTransform_ProcessMessage(stream->decoder,
735 MFT_MESSAGE_COMMAND_DRAIN, 0)))
737 if ((hr = source_reader_pull_stream_samples(reader, stream)) != MF_E_TRANSFORM_NEED_MORE_INPUT)
738 WARN("Failed to pull pending samples, hr %#x.\n", hr);
741 while (stream->requests)
742 source_reader_queue_response(reader, stream, S_OK, MF_SOURCE_READERF_ENDOFSTREAM, 0, NULL);
744 break;
745 case MEStreamSeeked:
746 case MEStreamStarted:
747 stream->state = STREAM_STATE_READY;
748 break;
749 case MEStreamTick:
750 value.vt = VT_EMPTY;
751 hr = SUCCEEDED(IMFMediaEvent_GetValue(event, &value)) && value.vt == VT_I8 ? S_OK : E_UNEXPECTED;
752 timestamp = SUCCEEDED(hr) ? value.u.hVal.QuadPart : 0;
753 PropVariantClear(&value);
755 source_reader_queue_response(reader, stream, hr, MF_SOURCE_READERF_STREAMTICK, timestamp, NULL);
757 break;
758 default:
762 break;
766 LeaveCriticalSection(&reader->cs);
768 return S_OK;
771 static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
773 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
774 MediaEventType event_type;
775 IMFMediaStream *stream;
776 IMFMediaEvent *event;
777 HRESULT hr;
779 TRACE("%p, %p.\n", iface, result);
781 stream = (IMFMediaStream *)IMFAsyncResult_GetStateNoAddRef(result);
783 if (FAILED(hr = IMFMediaStream_EndGetEvent(stream, result, &event)))
784 return hr;
786 IMFMediaEvent_GetType(event, &event_type);
788 TRACE("Got event %u.\n", event_type);
790 switch (event_type)
792 case MEMediaSample:
793 hr = source_reader_media_sample_handler(reader, stream, event);
794 break;
795 case MEStreamSeeked:
796 case MEStreamStarted:
797 case MEStreamTick:
798 case MEEndOfStream:
799 hr = source_reader_media_stream_state_handler(reader, stream, event);
800 break;
801 default:
805 if (FAILED(hr))
806 WARN("Failed while handling %d event, hr %#x.\n", event_type, hr);
808 IMFMediaEvent_Release(event);
810 IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
812 return S_OK;
815 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl =
817 source_reader_callback_QueryInterface,
818 source_reader_stream_events_callback_AddRef,
819 source_reader_stream_events_callback_Release,
820 source_reader_callback_GetParameters,
821 source_reader_stream_events_callback_Invoke,
824 static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface)
826 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
827 return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
830 static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface)
832 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
833 return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
836 static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response)
838 struct media_stream *stream;
840 list_remove(&response->entry);
842 if (response->stream_index < reader->stream_count)
844 stream = &reader->streams[response->stream_index];
845 if (stream->responses)
846 --stream->responses;
849 return response;
852 static struct stream_response *media_stream_pop_response(struct source_reader *reader, struct media_stream *stream)
854 struct stream_response *response;
855 struct list *head;
857 if (stream)
859 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
861 if (response->stream_index == stream->index)
862 return media_stream_detach_response(reader, response);
865 else
867 if ((head = list_head(&reader->responses)))
868 return media_stream_detach_response(reader, LIST_ENTRY(head, struct stream_response, entry));
871 return NULL;
874 static void source_reader_release_response(struct stream_response *response)
876 if (response->sample)
877 IMFSample_Release(response->sample);
878 heap_free(response);
881 static HRESULT source_reader_get_stream_selection(const struct source_reader *reader, DWORD index, BOOL *selected)
883 IMFStreamDescriptor *sd;
885 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, selected, &sd)))
886 return MF_E_INVALIDSTREAMNUMBER;
887 IMFStreamDescriptor_Release(sd);
889 return S_OK;
892 static HRESULT source_reader_start_source(struct source_reader *reader)
894 BOOL selected, selection_changed = FALSE;
895 PROPVARIANT position;
896 HRESULT hr = S_OK;
897 unsigned int i;
899 for (i = 0; i < reader->stream_count; ++i)
901 source_reader_get_stream_selection(reader, i, &selected);
902 if (selected)
903 reader->streams[i].flags |= STREAM_FLAG_SELECTED;
904 else
905 reader->streams[i].flags &= ~STREAM_FLAG_SELECTED;
908 if (reader->source_state == SOURCE_STATE_STARTED)
910 for (i = 0; i < reader->stream_count; ++i)
912 selection_changed = !!(reader->streams[i].flags & STREAM_FLAG_SELECTED) ^
913 !!(reader->streams[i].flags & STREAM_FLAG_PRESENTED);
914 if (selection_changed)
915 break;
919 position.u.hVal.QuadPart = 0;
920 if (reader->source_state != SOURCE_STATE_STARTED || selection_changed)
922 position.vt = reader->source_state == SOURCE_STATE_STARTED ? VT_EMPTY : VT_I8;
924 /* Update cached stream selection if descriptor was accepted. */
925 if (SUCCEEDED(hr = IMFMediaSource_Start(reader->source, reader->descriptor, &GUID_NULL, &position)))
927 for (i = 0; i < reader->stream_count; ++i)
929 if (reader->streams[i].flags & STREAM_FLAG_SELECTED)
930 reader->streams[i].flags |= STREAM_FLAG_PRESENTED;
935 return hr;
938 static BOOL source_reader_got_response_for_stream(struct source_reader *reader, struct media_stream *stream)
940 struct stream_response *response;
942 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
944 if (response->stream_index == stream->index)
945 return TRUE;
948 return FALSE;
951 static BOOL source_reader_get_read_result(struct source_reader *reader, struct media_stream *stream, DWORD flags,
952 HRESULT *status, DWORD *stream_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
954 struct stream_response *response = NULL;
955 BOOL request_sample = FALSE;
957 if ((response = media_stream_pop_response(reader, stream)))
959 *status = response->status;
960 *stream_index = stream->index;
961 *stream_flags = response->stream_flags;
962 *timestamp = response->timestamp;
963 *sample = response->sample;
964 if (*sample)
965 IMFSample_AddRef(*sample);
967 source_reader_release_response(response);
969 else
971 *status = S_OK;
972 *stream_index = stream->index;
973 *timestamp = 0;
974 *sample = NULL;
976 if (stream->state == STREAM_STATE_EOS)
978 *stream_flags = MF_SOURCE_READERF_ENDOFSTREAM;
980 else
982 request_sample = !(flags & MF_SOURCE_READER_CONTROLF_DRAIN);
983 *stream_flags = 0;
987 return !request_sample;
990 static HRESULT source_reader_get_first_selected_stream(struct source_reader *reader, unsigned int flags,
991 unsigned int *stream_index)
993 unsigned int i, first_selected = ~0u;
994 BOOL selected, stream_drained;
996 for (i = 0; i < reader->stream_count; ++i)
998 stream_drained = reader->streams[i].state == STREAM_STATE_EOS && !reader->streams[i].responses;
999 selected = SUCCEEDED(source_reader_get_stream_selection(reader, i, &selected)) && selected;
1001 if (selected && !(reader->streams[i].flags & flags))
1003 if (first_selected == ~0u)
1004 first_selected = i;
1006 if (!stream_drained)
1008 *stream_index = i;
1009 break;
1014 /* If all selected streams reached EOS, use first selected. This fallback only applies after reader went through all
1015 selected streams once. */
1016 if (i == reader->stream_count && first_selected != ~0u && !flags)
1018 *stream_index = first_selected;
1019 i = first_selected;
1022 return i == reader->stream_count ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED : S_OK;
1025 static HRESULT source_reader_get_stream_read_index(struct source_reader *reader, unsigned int index, unsigned int *stream_index)
1027 BOOL selected;
1028 HRESULT hr;
1030 switch (index)
1032 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1033 *stream_index = reader->first_video_stream_index;
1034 break;
1035 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1036 *stream_index = reader->first_audio_stream_index;
1037 break;
1038 case MF_SOURCE_READER_ANY_STREAM:
1039 if (reader->async_callback)
1041 /* Pick first selected stream. */
1042 hr = source_reader_get_first_selected_stream(reader, 0, stream_index);
1044 else
1046 /* Cycle through all selected streams once, next pick first selected. */
1047 if (FAILED(hr = source_reader_get_first_selected_stream(reader, STREAM_FLAG_REQUESTED_ONCE, stream_index)))
1048 hr = source_reader_get_first_selected_stream(reader, 0, stream_index);
1050 return hr;
1051 default:
1052 *stream_index = index;
1055 /* Can't read from deselected streams. */
1056 if (SUCCEEDED(hr = source_reader_get_stream_selection(reader, *stream_index, &selected)) && !selected)
1057 hr = MF_E_INVALIDREQUEST;
1059 return hr;
1062 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream)
1064 struct stream_response *ptr, *next;
1066 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &reader->responses, struct stream_response, entry)
1068 if (stream && stream->index != ptr->stream_index &&
1069 ptr->stream_index != MF_SOURCE_READER_FIRST_VIDEO_STREAM &&
1070 ptr->stream_index != MF_SOURCE_READER_FIRST_AUDIO_STREAM &&
1071 ptr->stream_index != MF_SOURCE_READER_ANY_STREAM)
1073 continue;
1075 media_stream_detach_response(reader, ptr);
1076 source_reader_release_response(ptr);
1080 static void source_reader_flush_stream(struct source_reader *reader, DWORD stream_index)
1082 struct media_stream *stream = &reader->streams[stream_index];
1084 source_reader_release_responses(reader, stream);
1085 if (stream->decoder)
1086 IMFTransform_ProcessMessage(stream->decoder, MFT_MESSAGE_COMMAND_FLUSH, 0);
1087 stream->requests = 0;
1090 static HRESULT source_reader_flush(struct source_reader *reader, unsigned int index)
1092 unsigned int stream_index;
1093 HRESULT hr = S_OK;
1095 if (index == MF_SOURCE_READER_ALL_STREAMS)
1097 for (stream_index = 0; stream_index < reader->stream_count; ++stream_index)
1098 source_reader_flush_stream(reader, stream_index);
1100 else
1102 switch (index)
1104 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1105 stream_index = reader->first_video_stream_index;
1106 break;
1107 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1108 stream_index = reader->first_audio_stream_index;
1109 break;
1110 default:
1111 stream_index = index;
1114 if (stream_index < reader->stream_count)
1115 source_reader_flush_stream(reader, stream_index);
1116 else
1117 hr = MF_E_INVALIDSTREAMNUMBER;
1120 return hr;
1123 static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1125 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1126 struct media_stream *stream, stub_stream = { .requests = 1 };
1127 struct source_reader_async_command *command;
1128 struct stream_response *response;
1129 DWORD stream_index, stream_flags;
1130 BOOL report_sample = FALSE;
1131 IMFSample *sample = NULL;
1132 LONGLONG timestamp = 0;
1133 HRESULT hr, status;
1134 IUnknown *state;
1136 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
1137 return hr;
1139 command = impl_from_async_command_IUnknown(state);
1141 switch (command->op)
1143 case SOURCE_READER_ASYNC_READ:
1144 EnterCriticalSection(&reader->cs);
1146 if (SUCCEEDED(hr = source_reader_start_source(reader)))
1148 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, command->u.read.stream_index, &stream_index)))
1150 stream = &reader->streams[stream_index];
1152 if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status,
1153 &stream_index, &stream_flags, &timestamp, &sample)))
1155 stream->requests++;
1156 source_reader_request_sample(reader, stream);
1157 /* FIXME: set error stream/reader state on request failure */
1160 else
1162 stub_stream.index = command->u.read.stream_index;
1163 source_reader_queue_response(reader, &stub_stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL);
1167 LeaveCriticalSection(&reader->cs);
1169 if (report_sample)
1170 IMFSourceReaderCallback_OnReadSample(reader->async_callback, status, stream_index, stream_flags,
1171 timestamp, sample);
1173 if (sample)
1174 IMFSample_Release(sample);
1176 break;
1178 case SOURCE_READER_ASYNC_SEEK:
1180 EnterCriticalSection(&reader->cs);
1181 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, &command->u.seek.format,
1182 &command->u.seek.position)))
1184 reader->flags |= SOURCE_READER_SEEKING;
1186 LeaveCriticalSection(&reader->cs);
1188 break;
1190 case SOURCE_READER_ASYNC_SAMPLE_READY:
1192 EnterCriticalSection(&reader->cs);
1193 response = media_stream_pop_response(reader, NULL);
1194 LeaveCriticalSection(&reader->cs);
1196 if (response)
1198 IMFSourceReaderCallback_OnReadSample(reader->async_callback, response->status, response->stream_index,
1199 response->stream_flags, response->timestamp, response->sample);
1200 source_reader_release_response(response);
1203 break;
1204 case SOURCE_READER_ASYNC_FLUSH:
1205 EnterCriticalSection(&reader->cs);
1206 source_reader_flush(reader, command->u.flush.stream_index);
1207 reader->flags &= ~SOURCE_READER_FLUSHING;
1208 LeaveCriticalSection(&reader->cs);
1210 IMFSourceReaderCallback_OnFlush(reader->async_callback, command->u.flush.stream_index);
1211 break;
1212 default:
1216 IUnknown_Release(state);
1218 return S_OK;
1221 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl =
1223 source_reader_callback_QueryInterface,
1224 source_reader_async_commands_callback_AddRef,
1225 source_reader_async_commands_callback_Release,
1226 source_reader_callback_GetParameters,
1227 source_reader_async_commands_callback_Invoke,
1230 static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReader *iface, REFIID riid, void **out)
1232 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1234 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1236 if(IsEqualGUID(riid, &IID_IUnknown) ||
1237 IsEqualGUID(riid, &IID_IMFSourceReader))
1239 *out = &reader->IMFSourceReader_iface;
1241 else
1243 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
1244 *out = NULL;
1245 return E_NOINTERFACE;
1248 IUnknown_AddRef((IUnknown*)*out);
1249 return S_OK;
1252 static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface)
1254 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1255 ULONG refcount = InterlockedIncrement(&reader->refcount);
1257 TRACE("%p, refcount %u.\n", iface, refcount);
1259 return refcount;
1262 static ULONG WINAPI src_reader_Release(IMFSourceReader *iface)
1264 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1265 ULONG refcount = InterlockedDecrement(&reader->refcount);
1266 unsigned int i;
1268 TRACE("%p, refcount %u.\n", iface, refcount);
1270 if (!refcount)
1272 if (reader->async_callback)
1273 IMFSourceReaderCallback_Release(reader->async_callback);
1274 if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE)
1275 IMFMediaSource_Shutdown(reader->source);
1276 if (reader->descriptor)
1277 IMFPresentationDescriptor_Release(reader->descriptor);
1278 IMFMediaSource_Release(reader->source);
1280 for (i = 0; i < reader->stream_count; ++i)
1282 struct media_stream *stream = &reader->streams[i];
1284 if (stream->stream)
1285 IMFMediaStream_Release(stream->stream);
1286 if (stream->current)
1287 IMFMediaType_Release(stream->current);
1288 if (stream->decoder)
1289 IMFTransform_Release(stream->decoder);
1291 source_reader_release_responses(reader, NULL);
1292 heap_free(reader->streams);
1293 DeleteCriticalSection(&reader->cs);
1294 heap_free(reader);
1297 return refcount;
1300 static HRESULT WINAPI src_reader_GetStreamSelection(IMFSourceReader *iface, DWORD index, BOOL *selected)
1302 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1304 TRACE("%p, %#x, %p.\n", iface, index, selected);
1306 switch (index)
1308 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1309 index = reader->first_video_stream_index;
1310 break;
1311 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1312 index = reader->first_audio_stream_index;
1313 break;
1314 default:
1318 return source_reader_get_stream_selection(reader, index, selected);
1321 static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReader *iface, DWORD index, BOOL selection)
1323 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1324 HRESULT hr = S_OK;
1325 BOOL selection_changed = FALSE, selected;
1326 unsigned int i;
1328 TRACE("%p, %#x, %d.\n", iface, index, selection);
1330 selection = !!selection;
1332 EnterCriticalSection(&reader->cs);
1334 if (index == MF_SOURCE_READER_ALL_STREAMS)
1336 for (i = 0; i < reader->stream_count; ++i)
1338 if (!selection_changed)
1340 source_reader_get_stream_selection(reader, i, &selected);
1341 if (selected ^ selection)
1342 selection_changed = TRUE;
1345 if (selection)
1346 IMFPresentationDescriptor_SelectStream(reader->descriptor, i);
1347 else
1348 IMFPresentationDescriptor_DeselectStream(reader->descriptor, i);
1351 else
1353 switch (index)
1355 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1356 index = reader->first_video_stream_index;
1357 break;
1358 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1359 index = reader->first_audio_stream_index;
1360 break;
1361 default:
1365 source_reader_get_stream_selection(reader, index, &selected);
1366 if (selected ^ selection)
1367 selection_changed = TRUE;
1369 if (selection)
1370 hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
1371 else
1372 hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
1375 if (SUCCEEDED(hr) && selection_changed)
1377 for (i = 0; i < reader->stream_count; ++i)
1378 reader->streams[i].flags &= ~STREAM_FLAG_REQUESTED_ONCE;
1381 LeaveCriticalSection(&reader->cs);
1383 return SUCCEEDED(hr) ? S_OK : MF_E_INVALIDSTREAMNUMBER;
1386 static HRESULT source_reader_get_native_media_type(struct source_reader *reader, DWORD index, DWORD type_index,
1387 IMFMediaType **type)
1389 IMFMediaTypeHandler *handler;
1390 IMFStreamDescriptor *sd;
1391 IMFMediaType *src_type;
1392 BOOL selected;
1393 HRESULT hr;
1395 switch (index)
1397 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1398 index = reader->first_video_stream_index;
1399 break;
1400 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1401 index = reader->first_audio_stream_index;
1402 break;
1403 default:
1407 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1408 return MF_E_INVALIDSTREAMNUMBER;
1410 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
1411 IMFStreamDescriptor_Release(sd);
1412 if (FAILED(hr))
1413 return hr;
1415 if (type_index == MF_SOURCE_READER_CURRENT_TYPE_INDEX)
1416 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &src_type);
1417 else
1418 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, type_index, &src_type);
1419 IMFMediaTypeHandler_Release(handler);
1421 if (SUCCEEDED(hr))
1423 if (SUCCEEDED(hr = MFCreateMediaType(type)))
1424 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)*type);
1425 IMFMediaType_Release(src_type);
1428 return hr;
1431 static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReader *iface, DWORD index, DWORD type_index,
1432 IMFMediaType **type)
1434 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1436 TRACE("%p, %#x, %#x, %p.\n", iface, index, type_index, type);
1438 return source_reader_get_native_media_type(reader, index, type_index, type);
1441 static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReader *iface, DWORD index, IMFMediaType **type)
1443 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1444 HRESULT hr;
1446 TRACE("%p, %#x, %p.\n", iface, index, type);
1448 switch (index)
1450 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1451 index = reader->first_video_stream_index;
1452 break;
1453 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1454 index = reader->first_audio_stream_index;
1455 break;
1456 default:
1460 if (index >= reader->stream_count)
1461 return MF_E_INVALIDSTREAMNUMBER;
1463 if (FAILED(hr = MFCreateMediaType(type)))
1464 return hr;
1466 EnterCriticalSection(&reader->cs);
1468 hr = IMFMediaType_CopyAllItems(reader->streams[index].current, (IMFAttributes *)*type);
1470 LeaveCriticalSection(&reader->cs);
1472 return hr;
1475 static HRESULT source_reader_get_source_type_handler(struct source_reader *reader, DWORD index,
1476 IMFMediaTypeHandler **handler)
1478 IMFStreamDescriptor *sd;
1479 BOOL selected;
1480 HRESULT hr;
1482 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1483 return hr;
1485 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, handler);
1486 IMFStreamDescriptor_Release(sd);
1488 return hr;
1491 static HRESULT source_reader_set_compatible_media_type(struct source_reader *reader, DWORD index, IMFMediaType *type)
1493 IMFMediaTypeHandler *type_handler;
1494 IMFMediaType *native_type;
1495 BOOL type_set = FALSE;
1496 unsigned int i = 0;
1497 DWORD flags;
1498 HRESULT hr;
1500 if (FAILED(hr = IMFMediaType_IsEqual(type, reader->streams[index].current, &flags)))
1501 return hr;
1503 if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES))
1504 return MF_E_INVALIDMEDIATYPE;
1506 /* No need for a decoder or type change. */
1507 if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
1508 return S_OK;
1510 if (FAILED(hr = source_reader_get_source_type_handler(reader, index, &type_handler)))
1511 return hr;
1513 while (!type_set && IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, i++, &native_type) == S_OK)
1515 static const DWORD compare_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES;
1517 if (SUCCEEDED(IMFMediaType_IsEqual(native_type, type, &flags)) && (flags & compare_flags) == compare_flags)
1519 if ((type_set = SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler, native_type))))
1520 IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)reader->streams[index].current);
1523 IMFMediaType_Release(native_type);
1526 IMFMediaTypeHandler_Release(type_handler);
1528 return type_set ? S_OK : S_FALSE;
1531 static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWORD index, const CLSID *clsid,
1532 IMFMediaType *input_type, IMFMediaType *output_type)
1534 IMFMediaTypeHandler *type_handler;
1535 IMFTransform *transform = NULL;
1536 IMFMediaType *type = NULL;
1537 DWORD flags;
1538 HRESULT hr;
1539 int i = 0;
1541 if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform)))
1543 WARN("Failed to create transform object, hr %#x.\n", hr);
1544 return hr;
1547 if (FAILED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)))
1549 WARN("Failed to set decoder input type, hr %#x.\n", hr);
1550 IMFTransform_Release(transform);
1551 return hr;
1554 /* Find the relevant output type. */
1555 while (IMFTransform_GetOutputAvailableType(transform, 0, i++, &type) == S_OK)
1557 flags = 0;
1559 if (SUCCEEDED(IMFMediaType_IsEqual(type, output_type, &flags)))
1561 if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
1563 if (SUCCEEDED(IMFTransform_SetOutputType(transform, 0, type, 0)))
1565 if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler)))
1567 IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type);
1568 IMFMediaTypeHandler_Release(type_handler);
1571 if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)reader->streams[index].current)))
1572 WARN("Failed to copy attributes, hr %#x.\n", hr);
1573 IMFMediaType_Release(type);
1575 if (reader->streams[index].decoder)
1576 IMFTransform_Release(reader->streams[index].decoder);
1578 reader->streams[index].decoder = transform;
1580 return S_OK;
1585 IMFMediaType_Release(type);
1588 WARN("Failed to find suitable decoder output type.\n");
1590 IMFTransform_Release(transform);
1592 return MF_E_TOPO_CODEC_NOT_FOUND;
1595 static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type)
1597 MFT_REGISTER_TYPE_INFO in_type, out_type;
1598 CLSID *clsids, mft_clsid, category;
1599 unsigned int i = 0, count;
1600 IMFMediaType *input_type;
1601 HRESULT hr;
1603 /* TODO: should we check if the source type is compressed? */
1605 if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType)))
1606 return hr;
1608 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video))
1610 category = MFT_CATEGORY_VIDEO_DECODER;
1612 else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio))
1614 category = MFT_CATEGORY_AUDIO_DECODER;
1616 else
1618 WARN("Unhandled major type %s.\n", debugstr_guid(&out_type.guidMajorType));
1619 return MF_E_TOPO_CODEC_NOT_FOUND;
1622 if (FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype)))
1623 return hr;
1625 in_type.guidMajorType = out_type.guidMajorType;
1627 while (source_reader_get_native_media_type(reader, index, i++, &input_type) == S_OK)
1629 if (SUCCEEDED(IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype)))
1631 count = 0;
1632 if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &clsids, &count)) && count)
1634 mft_clsid = clsids[0];
1635 CoTaskMemFree(clsids);
1637 /* TODO: Should we iterate over all of them? */
1638 if (SUCCEEDED(source_reader_configure_decoder(reader, index, &mft_clsid, input_type, output_type)))
1640 IMFMediaType_Release(input_type);
1641 return S_OK;
1647 IMFMediaType_Release(input_type);
1650 return MF_E_TOPO_CODEC_NOT_FOUND;
1653 static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWORD index, DWORD *reserved,
1654 IMFMediaType *type)
1656 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1657 HRESULT hr;
1659 TRACE("%p, %#x, %p, %p.\n", iface, index, reserved, type);
1661 switch (index)
1663 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1664 index = reader->first_video_stream_index;
1665 break;
1666 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1667 index = reader->first_audio_stream_index;
1668 break;
1669 default:
1673 if (index >= reader->stream_count)
1674 return MF_E_INVALIDSTREAMNUMBER;
1676 /* FIXME: setting the output type while streaming should trigger a flush */
1678 EnterCriticalSection(&reader->cs);
1680 if ((hr = source_reader_set_compatible_media_type(reader, index, type)) == S_FALSE)
1681 hr = source_reader_create_decoder_for_stream(reader, index, type);
1683 LeaveCriticalSection(&reader->cs);
1685 return hr;
1688 static HRESULT WINAPI src_reader_SetCurrentPosition(IMFSourceReader *iface, REFGUID format, REFPROPVARIANT position)
1690 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1691 struct source_reader_async_command *command;
1692 unsigned int i, flags;
1693 HRESULT hr;
1695 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), position);
1697 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
1698 return hr;
1700 if (!(flags & MFMEDIASOURCE_CAN_SEEK))
1701 return MF_E_INVALIDREQUEST;
1703 EnterCriticalSection(&reader->cs);
1705 /* Check if we got pending requests. */
1706 for (i = 0; i < reader->stream_count; ++i)
1708 if (reader->streams[i].requests)
1710 hr = MF_E_INVALIDREQUEST;
1711 break;
1715 if (SUCCEEDED(hr))
1717 if (reader->async_callback)
1719 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK, &command)))
1721 command->u.seek.format = *format;
1722 PropVariantCopy(&command->u.seek.position, position);
1724 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &reader->async_commands_callback,
1725 &command->IUnknown_iface);
1726 IUnknown_Release(&command->IUnknown_iface);
1729 else
1731 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, format, position)))
1733 reader->flags |= SOURCE_READER_SEEKING;
1734 while (reader->flags & SOURCE_READER_SEEKING)
1736 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
1742 LeaveCriticalSection(&reader->cs);
1744 return hr;
1747 static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD index, DWORD flags, DWORD *actual_index,
1748 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1750 unsigned int actual_index_tmp;
1751 struct media_stream *stream;
1752 LONGLONG timestamp_tmp;
1753 DWORD stream_index;
1754 HRESULT hr = S_OK;
1756 if (!stream_flags || !sample)
1757 return E_POINTER;
1759 *sample = NULL;
1761 if (!timestamp)
1762 timestamp = &timestamp_tmp;
1764 if (!actual_index)
1765 actual_index = &actual_index_tmp;
1767 if (SUCCEEDED(hr = source_reader_start_source(reader)))
1769 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, index, &stream_index)))
1771 *actual_index = stream_index;
1773 stream = &reader->streams[stream_index];
1775 if (!source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
1776 timestamp, sample))
1778 while (!source_reader_got_response_for_stream(reader, stream) && stream->state != STREAM_STATE_EOS)
1780 stream->requests++;
1781 if (FAILED(hr = source_reader_request_sample(reader, stream)))
1782 WARN("Failed to request a sample, hr %#x.\n", hr);
1783 SleepConditionVariableCS(&reader->sample_event, &reader->cs, INFINITE);
1786 source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
1787 timestamp, sample);
1790 else
1792 *actual_index = index;
1793 *stream_flags = MF_SOURCE_READERF_ERROR;
1794 *timestamp = 0;
1798 TRACE("Stream %u, got sample %p, flags %#x.\n", *actual_index, *sample, *stream_flags);
1800 return hr;
1803 static HRESULT source_reader_read_sample_async(struct source_reader *reader, unsigned int index, unsigned int flags,
1804 unsigned int *actual_index, unsigned int *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1806 struct source_reader_async_command *command;
1807 HRESULT hr;
1809 if (actual_index || stream_flags || timestamp || sample)
1810 return E_INVALIDARG;
1812 if (reader->flags & SOURCE_READER_FLUSHING)
1813 hr = MF_E_NOTACCEPTING;
1814 else
1816 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_READ, &command)))
1818 command->u.read.stream_index = index;
1819 command->u.read.flags = flags;
1821 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &reader->async_commands_callback, &command->IUnknown_iface);
1822 IUnknown_Release(&command->IUnknown_iface);
1826 return hr;
1829 static HRESULT WINAPI src_reader_ReadSample(IMFSourceReader *iface, DWORD index, DWORD flags, DWORD *actual_index,
1830 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1832 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1833 HRESULT hr;
1835 TRACE("%p, %#x, %#x, %p, %p, %p, %p\n", iface, index, flags, actual_index, stream_flags, timestamp, sample);
1837 EnterCriticalSection(&reader->cs);
1839 while (reader->flags & SOURCE_READER_SEEKING)
1841 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
1844 if (reader->async_callback)
1845 hr = source_reader_read_sample_async(reader, index, flags, actual_index, stream_flags, timestamp, sample);
1846 else
1847 hr = source_reader_read_sample(reader, index, flags, actual_index, stream_flags, timestamp, sample);
1849 LeaveCriticalSection(&reader->cs);
1851 return hr;
1854 static HRESULT source_reader_flush_async(struct source_reader *reader, unsigned int index)
1856 struct source_reader_async_command *command;
1857 unsigned int stream_index;
1858 HRESULT hr;
1860 if (reader->flags & SOURCE_READER_FLUSHING)
1861 return MF_E_INVALIDREQUEST;
1863 switch (index)
1865 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1866 stream_index = reader->first_video_stream_index;
1867 break;
1868 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1869 stream_index = reader->first_audio_stream_index;
1870 break;
1871 default:
1872 stream_index = index;
1875 reader->flags |= SOURCE_READER_FLUSHING;
1877 if (stream_index != MF_SOURCE_READER_ALL_STREAMS && stream_index >= reader->stream_count)
1878 return MF_E_INVALIDSTREAMNUMBER;
1880 if (FAILED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH, &command)))
1881 return hr;
1883 command->u.flush.stream_index = stream_index;
1885 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &reader->async_commands_callback, &command->IUnknown_iface);
1886 IUnknown_Release(&command->IUnknown_iface);
1888 return hr;
1891 static HRESULT WINAPI src_reader_Flush(IMFSourceReader *iface, DWORD index)
1893 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1894 HRESULT hr;
1896 TRACE("%p, %#x.\n", iface, index);
1898 EnterCriticalSection(&reader->cs);
1900 if (reader->async_callback)
1901 hr = source_reader_flush_async(reader, index);
1902 else
1903 hr = source_reader_flush(reader, index);
1905 LeaveCriticalSection(&reader->cs);
1907 return hr;
1910 static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReader *iface, DWORD index, REFGUID service,
1911 REFIID riid, void **object)
1913 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1914 IUnknown *obj = NULL;
1915 HRESULT hr;
1917 TRACE("%p, %#x, %s, %s, %p\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object);
1919 switch (index)
1921 case MF_SOURCE_READER_MEDIASOURCE:
1922 obj = (IUnknown *)reader->source;
1923 break;
1924 default:
1925 FIXME("Unsupported index %#x.\n", index);
1926 return E_NOTIMPL;
1929 if (IsEqualGUID(service, &GUID_NULL))
1931 hr = IUnknown_QueryInterface(obj, riid, object);
1933 else
1935 IMFGetService *gs;
1937 hr = IUnknown_QueryInterface(obj, &IID_IMFGetService, (void **)&gs);
1938 if (SUCCEEDED(hr))
1940 hr = IMFGetService_GetService(gs, service, riid, object);
1941 IMFGetService_Release(gs);
1945 return hr;
1948 static HRESULT WINAPI src_reader_GetPresentationAttribute(IMFSourceReader *iface, DWORD index,
1949 REFGUID guid, PROPVARIANT *value)
1951 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1952 IMFStreamDescriptor *sd;
1953 BOOL selected;
1954 HRESULT hr;
1956 TRACE("%p, %#x, %s, %p.\n", iface, index, debugstr_guid(guid), value);
1958 switch (index)
1960 case MF_SOURCE_READER_MEDIASOURCE:
1961 if (IsEqualGUID(guid, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS))
1963 DWORD flags;
1965 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
1966 return hr;
1968 value->vt = VT_UI4;
1969 value->u.ulVal = flags;
1970 return S_OK;
1972 else
1974 return IMFPresentationDescriptor_GetItem(reader->descriptor, guid, value);
1976 break;
1977 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1978 index = reader->first_video_stream_index;
1979 break;
1980 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1981 index = reader->first_audio_stream_index;
1982 break;
1983 default:
1987 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1988 return hr;
1990 hr = IMFStreamDescriptor_GetItem(sd, guid, value);
1991 IMFStreamDescriptor_Release(sd);
1993 return hr;
1996 struct IMFSourceReaderVtbl srcreader_vtbl =
1998 src_reader_QueryInterface,
1999 src_reader_AddRef,
2000 src_reader_Release,
2001 src_reader_GetStreamSelection,
2002 src_reader_SetStreamSelection,
2003 src_reader_GetNativeMediaType,
2004 src_reader_GetCurrentMediaType,
2005 src_reader_SetCurrentMediaType,
2006 src_reader_SetCurrentPosition,
2007 src_reader_ReadSample,
2008 src_reader_Flush,
2009 src_reader_GetServiceForStream,
2010 src_reader_GetPresentationAttribute
2013 static DWORD reader_get_first_stream_index(IMFPresentationDescriptor *descriptor, const GUID *major)
2015 unsigned int count, i;
2016 BOOL selected;
2017 HRESULT hr;
2018 GUID guid;
2020 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count)))
2021 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2023 for (i = 0; i < count; ++i)
2025 IMFMediaTypeHandler *handler;
2026 IMFStreamDescriptor *sd;
2028 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i, &selected, &sd)))
2030 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2031 IMFStreamDescriptor_Release(sd);
2032 if (SUCCEEDED(hr))
2034 hr = IMFMediaTypeHandler_GetMajorType(handler, &guid);
2035 IMFMediaTypeHandler_Release(handler);
2036 if (FAILED(hr))
2038 WARN("Failed to get stream major type, hr %#x.\n", hr);
2039 continue;
2042 if (IsEqualGUID(&guid, major))
2044 return i;
2050 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2053 static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttributes *attributes,
2054 BOOL shutdown_on_release, REFIID riid, void **out)
2056 struct source_reader *object;
2057 unsigned int i;
2058 HRESULT hr;
2060 object = heap_alloc_zero(sizeof(*object));
2061 if (!object)
2062 return E_OUTOFMEMORY;
2064 object->IMFSourceReader_iface.lpVtbl = &srcreader_vtbl;
2065 object->source_events_callback.lpVtbl = &source_events_callback_vtbl;
2066 object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl;
2067 object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl;
2068 object->refcount = 1;
2069 list_init(&object->responses);
2070 if (shutdown_on_release)
2071 object->flags |= SOURCE_READER_SHUTDOWN_ON_RELEASE;
2072 object->source = source;
2073 IMFMediaSource_AddRef(object->source);
2074 InitializeCriticalSection(&object->cs);
2075 InitializeConditionVariable(&object->sample_event);
2076 InitializeConditionVariable(&object->state_event);
2078 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor)))
2079 goto failed;
2081 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(object->descriptor, &object->stream_count)))
2082 goto failed;
2084 if (!(object->streams = heap_alloc_zero(object->stream_count * sizeof(*object->streams))))
2086 hr = E_OUTOFMEMORY;
2087 goto failed;
2090 /* Set initial current media types. */
2091 for (i = 0; i < object->stream_count; ++i)
2093 IMFMediaTypeHandler *handler;
2094 IMFStreamDescriptor *sd;
2095 IMFMediaType *src_type;
2096 BOOL selected;
2098 if (FAILED(hr = MFCreateMediaType(&object->streams[i].current)))
2099 break;
2101 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(object->descriptor, i, &selected, &sd)))
2102 break;
2104 if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &object->streams[i].id)))
2105 WARN("Failed to get stream identifier, hr %#x.\n", hr);
2107 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2108 IMFStreamDescriptor_Release(sd);
2109 if (FAILED(hr))
2110 break;
2112 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &src_type);
2113 IMFMediaTypeHandler_Release(handler);
2114 if (FAILED(hr))
2115 break;
2117 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)object->streams[i].current);
2118 IMFMediaType_Release(src_type);
2119 if (FAILED(hr))
2120 break;
2122 object->streams[i].index = i;
2125 if (FAILED(hr))
2126 goto failed;
2128 /* At least one major type has to be set. */
2129 object->first_audio_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Audio);
2130 object->first_video_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Video);
2132 if (object->first_audio_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX &&
2133 object->first_video_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX)
2135 hr = MF_E_ATTRIBUTENOTFOUND;
2138 if (FAILED(hr = IMFMediaSource_BeginGetEvent(object->source, &object->source_events_callback,
2139 (IUnknown *)object->source)))
2141 goto failed;
2144 if (attributes)
2146 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_ASYNC_CALLBACK, &IID_IMFSourceReaderCallback,
2147 (void **)&object->async_callback);
2148 if (object->async_callback)
2149 TRACE("Using async callback %p.\n", object->async_callback);
2152 hr = IMFSourceReader_QueryInterface(&object->IMFSourceReader_iface, riid, out);
2154 failed:
2155 IMFSourceReader_Release(&object->IMFSourceReader_iface);
2156 return hr;
2159 static HRESULT bytestream_get_url_hint(IMFByteStream *stream, WCHAR const **url)
2161 static const unsigned char asfmagic[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c};
2162 static const unsigned char wavmagic[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '};
2163 static const unsigned char wavmask[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
2164 static const unsigned char isommagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00};
2165 static const unsigned char mp42magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00};
2166 static const unsigned char mp4mask[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00};
2167 static const struct stream_content_url_hint
2169 const unsigned char *magic;
2170 const WCHAR *url;
2171 const unsigned char *mask;
2173 url_hints[] =
2175 { asfmagic, L".asf" },
2176 { wavmagic, L".wav", wavmask },
2177 { isommagic, L".mp4", mp4mask },
2178 { mp42magic, L".mp4", mp4mask },
2180 unsigned char buffer[4 * sizeof(unsigned int)], pattern[4 * sizeof(unsigned int)];
2181 unsigned int i, j, length = 0, caps = 0;
2182 IMFAttributes *attributes;
2183 QWORD position;
2184 HRESULT hr;
2186 *url = NULL;
2188 if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
2190 IMFAttributes_GetStringLength(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &length);
2191 IMFAttributes_Release(attributes);
2194 if (length)
2195 return S_OK;
2197 if (FAILED(hr = IMFByteStream_GetCapabilities(stream, &caps)))
2198 return hr;
2200 if (!(caps & MFBYTESTREAM_IS_SEEKABLE))
2201 return S_OK;
2203 if (FAILED(hr = IMFByteStream_GetCurrentPosition(stream, &position)))
2204 return hr;
2206 hr = IMFByteStream_Read(stream, buffer, sizeof(buffer), &length);
2207 IMFByteStream_SetCurrentPosition(stream, position);
2208 if (FAILED(hr))
2209 return hr;
2211 if (length < sizeof(buffer))
2212 return S_OK;
2214 for (i = 0; i < ARRAY_SIZE(url_hints); ++i)
2216 memcpy(pattern, buffer, sizeof(buffer));
2217 if (url_hints[i].mask)
2219 unsigned int *mask = (unsigned int *)url_hints[i].mask;
2220 unsigned int *data = (unsigned int *)pattern;
2222 for (j = 0; j < sizeof(buffer) / sizeof(unsigned int); ++j)
2223 data[j] &= mask[j];
2226 if (!memcmp(pattern, url_hints[i].magic, sizeof(pattern)))
2228 *url = url_hints[i].url;
2229 break;
2233 if (*url)
2234 TRACE("Stream type guessed as %s from %s.\n", debugstr_w(*url), debugstr_an((char *)buffer, length));
2235 else
2236 WARN("Unrecognized content type %s.\n", debugstr_an((char *)buffer, length));
2238 return S_OK;
2241 static HRESULT create_source_reader_from_stream(IMFByteStream *stream, IMFAttributes *attributes,
2242 REFIID riid, void **out)
2244 IPropertyStore *props = NULL;
2245 IMFSourceResolver *resolver;
2246 MF_OBJECT_TYPE obj_type;
2247 IMFMediaSource *source;
2248 const WCHAR *url;
2249 HRESULT hr;
2251 /* If stream does not have content type set, try to guess from starting byte sequence. */
2252 if (FAILED(hr = bytestream_get_url_hint(stream, &url)))
2253 return hr;
2255 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2256 return hr;
2258 if (attributes)
2259 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2260 (void **)&props);
2262 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, url, MF_RESOLUTION_MEDIASOURCE, props,
2263 &obj_type, (IUnknown **)&source);
2264 IMFSourceResolver_Release(resolver);
2265 if (props)
2266 IPropertyStore_Release(props);
2267 if (FAILED(hr))
2268 return hr;
2270 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2271 IMFMediaSource_Release(source);
2272 return hr;
2275 static HRESULT create_source_reader_from_url(const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2277 IPropertyStore *props = NULL;
2278 IMFSourceResolver *resolver;
2279 IUnknown *object = NULL;
2280 MF_OBJECT_TYPE obj_type;
2281 IMFMediaSource *source;
2282 HRESULT hr;
2284 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2285 return hr;
2287 if (attributes)
2288 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2289 (void **)&props);
2291 hr = IMFSourceResolver_CreateObjectFromURL(resolver, url, MF_RESOLUTION_MEDIASOURCE, props, &obj_type,
2292 &object);
2293 if (SUCCEEDED(hr))
2295 switch (obj_type)
2297 case MF_OBJECT_BYTESTREAM:
2298 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, (IMFByteStream *)object, NULL,
2299 MF_RESOLUTION_MEDIASOURCE, props, &obj_type, (IUnknown **)&source);
2300 break;
2301 case MF_OBJECT_MEDIASOURCE:
2302 source = (IMFMediaSource *)object;
2303 IMFMediaSource_AddRef(source);
2304 break;
2305 default:
2306 WARN("Unknown object type %d.\n", obj_type);
2307 hr = E_UNEXPECTED;
2309 IUnknown_Release(object);
2312 IMFSourceResolver_Release(resolver);
2313 if (props)
2314 IPropertyStore_Release(props);
2315 if (FAILED(hr))
2316 return hr;
2318 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2319 IMFMediaSource_Release(source);
2320 return hr;
2323 static HRESULT create_source_reader_from_object(IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2325 IMFMediaSource *source = NULL;
2326 IMFByteStream *stream = NULL;
2327 HRESULT hr;
2329 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSource, (void **)&source);
2330 if (FAILED(hr))
2331 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2333 if (source)
2335 UINT32 disconnect = 0;
2337 if (attributes)
2338 IMFAttributes_GetUINT32(attributes, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN, &disconnect);
2339 hr = create_source_reader_from_source(source, attributes, !disconnect, riid, out);
2341 else if (stream)
2342 hr = create_source_reader_from_stream(stream, attributes, riid, out);
2344 if (source)
2345 IMFMediaSource_Release(source);
2346 if (stream)
2347 IMFByteStream_Release(stream);
2349 return hr;
2352 /***********************************************************************
2353 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2355 HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes,
2356 IMFSourceReader **reader)
2358 TRACE("%p, %p, %p.\n", stream, attributes, reader);
2360 return create_source_reader_from_object((IUnknown *)stream, attributes, &IID_IMFSourceReader, (void **)reader);
2363 /***********************************************************************
2364 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2366 HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes,
2367 IMFSourceReader **reader)
2369 TRACE("%p, %p, %p.\n", source, attributes, reader);
2371 return create_source_reader_from_object((IUnknown *)source, attributes, &IID_IMFSourceReader, (void **)reader);
2374 /***********************************************************************
2375 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2377 HRESULT WINAPI MFCreateSourceReaderFromURL(const WCHAR *url, IMFAttributes *attributes, IMFSourceReader **reader)
2379 TRACE("%s, %p, %p.\n", debugstr_w(url), attributes, reader);
2381 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, (void **)reader);
2384 static HRESULT WINAPI readwrite_factory_QueryInterface(IMFReadWriteClassFactory *iface, REFIID riid, void **out)
2386 if (IsEqualIID(riid, &IID_IMFReadWriteClassFactory) ||
2387 IsEqualIID(riid, &IID_IUnknown))
2389 *out = iface;
2390 IMFReadWriteClassFactory_AddRef(iface);
2391 return S_OK;
2394 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
2395 *out = NULL;
2396 return E_NOINTERFACE;
2399 static ULONG WINAPI readwrite_factory_AddRef(IMFReadWriteClassFactory *iface)
2401 return 2;
2404 static ULONG WINAPI readwrite_factory_Release(IMFReadWriteClassFactory *iface)
2406 return 1;
2409 static HRESULT WINAPI readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2410 const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2412 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid), debugstr_w(url), attributes, debugstr_guid(riid), out);
2414 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2416 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, out);
2419 FIXME("Unsupported %s.\n", debugstr_guid(clsid));
2421 return E_NOTIMPL;
2424 static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2425 IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2427 HRESULT hr;
2429 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid), unk, attributes, debugstr_guid(riid), out);
2431 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2433 return create_source_reader_from_object(unk, attributes, riid, out);
2435 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
2437 IMFByteStream *stream = NULL;
2438 IMFMediaSink *sink = NULL;
2440 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2441 if (FAILED(hr))
2442 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSink, (void **)&sink);
2444 if (stream)
2445 hr = create_sink_writer_from_stream(stream, attributes, riid, out);
2446 else if (sink)
2447 hr = create_sink_writer_from_sink(sink, attributes, riid, out);
2449 if (sink)
2450 IMFMediaSink_Release(sink);
2451 if (stream)
2452 IMFByteStream_Release(stream);
2454 return hr;
2456 else
2458 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2459 *out = NULL;
2460 return E_FAIL;
2464 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl =
2466 readwrite_factory_QueryInterface,
2467 readwrite_factory_AddRef,
2468 readwrite_factory_Release,
2469 readwrite_factory_CreateInstanceFromURL,
2470 readwrite_factory_CreateInstanceFromObject,
2473 static IMFReadWriteClassFactory readwrite_factory = { &readwrite_factory_vtbl };
2475 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
2477 TRACE("%s, %p.\n", debugstr_guid(riid), out);
2479 if (IsEqualGUID(riid, &IID_IClassFactory) ||
2480 IsEqualGUID(riid, &IID_IUnknown))
2482 IClassFactory_AddRef(iface);
2483 *out = iface;
2484 return S_OK;
2487 WARN("interface %s not implemented\n", debugstr_guid(riid));
2488 *out = NULL;
2489 return E_NOINTERFACE;
2492 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
2494 return 2;
2497 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
2499 return 1;
2502 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out)
2504 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), out);
2506 *out = NULL;
2508 if (outer)
2509 return CLASS_E_NOAGGREGATION;
2511 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory, riid, out);
2514 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
2516 FIXME("%d.\n", dolock);
2517 return S_OK;
2520 static const struct IClassFactoryVtbl classfactoryvtbl =
2522 classfactory_QueryInterface,
2523 classfactory_AddRef,
2524 classfactory_Release,
2525 classfactory_CreateInstance,
2526 classfactory_LockServer,
2529 static IClassFactory classfactory = { &classfactoryvtbl };
2531 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
2533 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), out);
2535 if (IsEqualGUID(clsid, &CLSID_MFReadWriteClassFactory))
2536 return IClassFactory_QueryInterface(&classfactory, riid, out);
2538 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2539 *out = NULL;
2540 return CLASS_E_CLASSNOTAVAILABLE;