d2d1/tests: Add return value test (Coverity).
[wine/zf.git] / dlls / mfreadwrite / reader.c
blob0e0fe1ad9cdb7671823b763c90142f20f855e339
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. */
106 struct media_stream
108 IMFMediaStream *stream;
109 IMFMediaType *current;
110 IMFTransform *decoder;
111 unsigned int id;
112 unsigned int index;
113 enum media_stream_state state;
114 unsigned int flags;
115 unsigned int requests;
116 unsigned int responses;
119 enum source_reader_async_op
121 SOURCE_READER_ASYNC_READ,
122 SOURCE_READER_ASYNC_SEEK,
123 SOURCE_READER_ASYNC_FLUSH,
124 SOURCE_READER_ASYNC_SAMPLE_READY,
127 struct source_reader_async_command
129 IUnknown IUnknown_iface;
130 LONG refcount;
131 enum source_reader_async_op op;
132 union
134 struct
136 unsigned int flags;
137 unsigned int stream_index;
138 } read;
139 struct
141 GUID format;
142 PROPVARIANT position;
143 } seek;
144 struct
146 unsigned int stream_index;
147 } flush;
148 struct
150 unsigned int stream_index;
151 } sample;
152 } u;
155 enum source_reader_flags
157 SOURCE_READER_FLUSHING = 0x1,
158 SOURCE_READER_SEEKING = 0x2,
159 SOURCE_READER_SHUTDOWN_ON_RELEASE = 0x4,
162 struct source_reader
164 IMFSourceReader IMFSourceReader_iface;
165 IMFAsyncCallback source_events_callback;
166 IMFAsyncCallback stream_events_callback;
167 IMFAsyncCallback async_commands_callback;
168 LONG refcount;
169 IMFMediaSource *source;
170 IMFPresentationDescriptor *descriptor;
171 IMFSourceReaderCallback *async_callback;
172 unsigned int first_audio_stream_index;
173 unsigned int first_video_stream_index;
174 unsigned int last_read_index;
175 unsigned int stream_count;
176 unsigned int flags;
177 enum media_source_state source_state;
178 struct media_stream *streams;
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;
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 if (FAILED(source_reader_request_sample(reader, &reader->streams[i])))
443 WakeAllConditionVariable(&reader->sample_event);
445 break;
449 if (i == reader->stream_count)
450 WARN("Stream with id %#x was not present in presentation descriptor.\n", id);
452 LeaveCriticalSection(&reader->cs);
454 IMFMediaStream_Release(stream);
456 return hr;
459 static HRESULT source_reader_source_state_handler(struct source_reader *reader, MediaEventType event_type)
461 EnterCriticalSection(&reader->cs);
463 switch (event_type)
465 case MESourceStarted:
466 reader->source_state = SOURCE_STATE_STARTED;
467 break;
468 case MESourceStopped:
469 reader->source_state = SOURCE_STATE_STOPPED;
470 break;
471 case MESourceSeeked:
472 reader->flags &= ~SOURCE_READER_SEEKING;
473 break;
474 default:
475 WARN("Unhandled event %d.\n", event_type);
478 LeaveCriticalSection(&reader->cs);
480 WakeAllConditionVariable(&reader->state_event);
482 return S_OK;
485 static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
487 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
488 MediaEventType event_type;
489 IMFMediaSource *source;
490 IMFMediaEvent *event;
491 HRESULT hr;
493 TRACE("%p, %p.\n", iface, result);
495 source = (IMFMediaSource *)IMFAsyncResult_GetStateNoAddRef(result);
497 if (FAILED(hr = IMFMediaSource_EndGetEvent(source, result, &event)))
498 return hr;
500 IMFMediaEvent_GetType(event, &event_type);
502 TRACE("Got event %u.\n", event_type);
504 switch (event_type)
506 case MENewStream:
507 hr = source_reader_new_stream_handler(reader, event);
508 break;
509 case MESourceStarted:
510 case MESourcePaused:
511 case MESourceStopped:
512 case MESourceSeeked:
513 hr = source_reader_source_state_handler(reader, event_type);
514 break;
515 case MEBufferingStarted:
516 case MEBufferingStopped:
517 case MEConnectStart:
518 case MEConnectEnd:
519 case MEExtendedType:
520 case MESourceCharacteristicsChanged:
521 case MESourceMetadataChanged:
522 case MEContentProtectionMetadata:
523 case MEDeviceThermalStateChanged:
524 if (reader->async_callback)
525 IMFSourceReaderCallback_OnEvent(reader->async_callback, MF_SOURCE_READER_MEDIASOURCE, event);
526 break;
527 default:
531 if (FAILED(hr))
532 WARN("Failed while handling %d event, hr %#x.\n", event_type, hr);
534 IMFMediaEvent_Release(event);
536 IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
538 return S_OK;
541 static const IMFAsyncCallbackVtbl source_events_callback_vtbl =
543 source_reader_callback_QueryInterface,
544 source_reader_source_events_callback_AddRef,
545 source_reader_source_events_callback_Release,
546 source_reader_callback_GetParameters,
547 source_reader_source_events_callback_Invoke,
550 static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface)
552 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
553 return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
556 static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface)
558 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
559 return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
562 static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, struct media_stream *stream)
564 MFT_OUTPUT_STREAM_INFO stream_info = { 0 };
565 MFT_OUTPUT_DATA_BUFFER out_buffer;
566 IMFMediaBuffer *buffer;
567 LONGLONG timestamp;
568 DWORD status;
569 HRESULT hr;
571 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(stream->decoder, 0, &stream_info)))
573 WARN("Failed to get output stream info, hr %#x.\n", hr);
574 return hr;
577 for (;;)
579 memset(&out_buffer, 0, sizeof(out_buffer));
581 if (!(stream_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
583 if (FAILED(hr = MFCreateSample(&out_buffer.pSample)))
584 break;
586 if (FAILED(hr = MFCreateAlignedMemoryBuffer(stream_info.cbSize, stream_info.cbAlignment, &buffer)))
588 IMFSample_Release(out_buffer.pSample);
589 break;
592 IMFSample_AddBuffer(out_buffer.pSample, buffer);
593 IMFMediaBuffer_Release(buffer);
596 if (FAILED(hr = IMFTransform_ProcessOutput(stream->decoder, 0, 1, &out_buffer, &status)))
598 if (out_buffer.pSample)
599 IMFSample_Release(out_buffer.pSample);
600 break;
603 timestamp = 0;
604 if (FAILED(IMFSample_GetSampleTime(out_buffer.pSample, &timestamp)))
605 WARN("Sample time wasn't set.\n");
607 source_reader_queue_response(reader, stream, S_OK /* FIXME */, 0, timestamp, out_buffer.pSample);
608 if (out_buffer.pSample)
609 IMFSample_Release(out_buffer.pSample);
610 if (out_buffer.pEvents)
611 IMFCollection_Release(out_buffer.pEvents);
614 return hr;
617 static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream,
618 IMFSample *sample)
620 LONGLONG timestamp;
621 HRESULT hr;
623 if (!stream->decoder)
625 timestamp = 0;
626 if (FAILED(IMFSample_GetSampleTime(sample, &timestamp)))
627 WARN("Sample time wasn't set.\n");
629 source_reader_queue_response(reader, stream, S_OK, 0, timestamp, sample);
630 return S_OK;
633 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
635 hr = source_reader_pull_stream_samples(reader, stream);
636 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
638 if (FAILED(hr = IMFTransform_ProcessInput(stream->decoder, 0, sample, 0)))
640 WARN("Transform failed to process input, hr %#x.\n", hr);
641 return hr;
644 if ((hr = source_reader_pull_stream_samples(reader, stream)) == MF_E_TRANSFORM_NEED_MORE_INPUT)
645 return S_OK;
647 else
648 WARN("Transform failed to process output, hr %#x.\n", hr);
650 return hr;
653 static HRESULT source_reader_media_sample_handler(struct source_reader *reader, IMFMediaStream *stream,
654 IMFMediaEvent *event)
656 IMFSample *sample;
657 unsigned int i;
658 DWORD id = 0;
659 HRESULT hr;
661 TRACE("Got new sample for stream %p.\n", stream);
663 if (FAILED(hr = media_event_get_object(event, &IID_IMFSample, (void **)&sample)))
665 WARN("Failed to get sample object, hr %#x.\n", hr);
666 return hr;
669 if (FAILED(hr = media_stream_get_id(stream, &id)))
671 WARN("Unidentified stream %p, hr %#x.\n", stream, hr);
672 IMFSample_Release(sample);
673 return hr;
676 EnterCriticalSection(&reader->cs);
678 for (i = 0; i < reader->stream_count; ++i)
680 if (id == reader->streams[i].id)
682 /* FIXME: propagate processing errors? */
684 reader->streams[i].flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
685 hr = source_reader_process_sample(reader, &reader->streams[i], sample);
686 if (reader->streams[i].requests)
687 source_reader_request_sample(reader, &reader->streams[i]);
689 break;
693 if (i == reader->stream_count)
694 WARN("Stream with id %#x was not present in presentation descriptor.\n", id);
696 LeaveCriticalSection(&reader->cs);
698 IMFSample_Release(sample);
700 return hr;
703 static HRESULT source_reader_media_stream_state_handler(struct source_reader *reader, IMFMediaStream *stream,
704 IMFMediaEvent *event)
706 MediaEventType event_type;
707 LONGLONG timestamp;
708 PROPVARIANT value;
709 unsigned int i;
710 HRESULT hr;
711 DWORD id;
713 IMFMediaEvent_GetType(event, &event_type);
715 if (FAILED(hr = media_stream_get_id(stream, &id)))
717 WARN("Unidentified stream %p, hr %#x.\n", stream, hr);
718 return hr;
721 EnterCriticalSection(&reader->cs);
723 for (i = 0; i < reader->stream_count; ++i)
725 struct media_stream *stream = &reader->streams[i];
727 if (id == stream->id)
729 switch (event_type)
731 case MEEndOfStream:
732 stream->state = STREAM_STATE_EOS;
733 stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
735 if (stream->decoder && SUCCEEDED(IMFTransform_ProcessMessage(stream->decoder,
736 MFT_MESSAGE_COMMAND_DRAIN, 0)))
738 if ((hr = source_reader_pull_stream_samples(reader, stream)) != MF_E_TRANSFORM_NEED_MORE_INPUT)
739 WARN("Failed to pull pending samples, hr %#x.\n", hr);
742 while (stream->requests)
743 source_reader_queue_response(reader, stream, S_OK, MF_SOURCE_READERF_ENDOFSTREAM, 0, NULL);
745 break;
746 case MEStreamSeeked:
747 case MEStreamStarted:
748 stream->state = STREAM_STATE_READY;
749 break;
750 case MEStreamTick:
751 value.vt = VT_EMPTY;
752 hr = SUCCEEDED(IMFMediaEvent_GetValue(event, &value)) && value.vt == VT_I8 ? S_OK : E_UNEXPECTED;
753 timestamp = SUCCEEDED(hr) ? value.u.hVal.QuadPart : 0;
754 PropVariantClear(&value);
756 source_reader_queue_response(reader, stream, hr, MF_SOURCE_READERF_STREAMTICK, timestamp, NULL);
758 break;
759 default:
763 break;
767 LeaveCriticalSection(&reader->cs);
769 return S_OK;
772 static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
774 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
775 MediaEventType event_type;
776 IMFMediaStream *stream;
777 IMFMediaEvent *event;
778 HRESULT hr;
780 TRACE("%p, %p.\n", iface, result);
782 stream = (IMFMediaStream *)IMFAsyncResult_GetStateNoAddRef(result);
784 if (FAILED(hr = IMFMediaStream_EndGetEvent(stream, result, &event)))
785 return hr;
787 IMFMediaEvent_GetType(event, &event_type);
789 TRACE("Got event %u.\n", event_type);
791 switch (event_type)
793 case MEMediaSample:
794 hr = source_reader_media_sample_handler(reader, stream, event);
795 break;
796 case MEStreamSeeked:
797 case MEStreamStarted:
798 case MEStreamTick:
799 case MEEndOfStream:
800 hr = source_reader_media_stream_state_handler(reader, stream, event);
801 break;
802 default:
806 if (FAILED(hr))
807 WARN("Failed while handling %d event, hr %#x.\n", event_type, hr);
809 IMFMediaEvent_Release(event);
811 IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
813 return S_OK;
816 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl =
818 source_reader_callback_QueryInterface,
819 source_reader_stream_events_callback_AddRef,
820 source_reader_stream_events_callback_Release,
821 source_reader_callback_GetParameters,
822 source_reader_stream_events_callback_Invoke,
825 static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface)
827 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
828 return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
831 static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface)
833 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
834 return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
837 static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response)
839 struct media_stream *stream;
841 list_remove(&response->entry);
843 if (response->stream_index < reader->stream_count)
845 stream = &reader->streams[response->stream_index];
846 if (stream->responses)
847 --stream->responses;
850 return response;
853 static struct stream_response *media_stream_pop_response(struct source_reader *reader, struct media_stream *stream)
855 struct stream_response *response;
856 struct list *head;
858 if (stream)
860 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
862 if (response->stream_index == stream->index)
863 return media_stream_detach_response(reader, response);
866 else
868 if ((head = list_head(&reader->responses)))
869 return media_stream_detach_response(reader, LIST_ENTRY(head, struct stream_response, entry));
872 return NULL;
875 static void source_reader_release_response(struct stream_response *response)
877 if (response->sample)
878 IMFSample_Release(response->sample);
879 heap_free(response);
882 static HRESULT source_reader_get_stream_selection(const struct source_reader *reader, DWORD index, BOOL *selected)
884 IMFStreamDescriptor *sd;
886 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, selected, &sd)))
887 return MF_E_INVALIDSTREAMNUMBER;
888 IMFStreamDescriptor_Release(sd);
890 return S_OK;
893 static HRESULT source_reader_start_source(struct source_reader *reader)
895 BOOL selected, selection_changed = FALSE;
896 PROPVARIANT position;
897 HRESULT hr = S_OK;
898 unsigned int i;
900 for (i = 0; i < reader->stream_count; ++i)
902 source_reader_get_stream_selection(reader, i, &selected);
903 if (selected)
904 reader->streams[i].flags |= STREAM_FLAG_SELECTED;
905 else
906 reader->streams[i].flags &= ~STREAM_FLAG_SELECTED;
909 if (reader->source_state == SOURCE_STATE_STARTED)
911 for (i = 0; i < reader->stream_count; ++i)
913 selection_changed = !!(reader->streams[i].flags & STREAM_FLAG_SELECTED) ^
914 !!(reader->streams[i].flags & STREAM_FLAG_PRESENTED);
915 if (selection_changed)
916 break;
920 position.u.hVal.QuadPart = 0;
921 if (reader->source_state != SOURCE_STATE_STARTED || selection_changed)
923 position.vt = reader->source_state == SOURCE_STATE_STARTED ? VT_EMPTY : VT_I8;
925 /* Update cached stream selection if descriptor was accepted. */
926 if (SUCCEEDED(hr = IMFMediaSource_Start(reader->source, reader->descriptor, &GUID_NULL, &position)))
928 for (i = 0; i < reader->stream_count; ++i)
930 if (reader->streams[i].flags & STREAM_FLAG_SELECTED)
931 reader->streams[i].flags |= STREAM_FLAG_PRESENTED;
936 return hr;
939 static BOOL source_reader_got_response_for_stream(struct source_reader *reader, struct media_stream *stream)
941 struct stream_response *response;
943 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
945 if (response->stream_index == stream->index)
946 return TRUE;
949 return FALSE;
952 static BOOL source_reader_get_read_result(struct source_reader *reader, struct media_stream *stream, DWORD flags,
953 HRESULT *status, DWORD *stream_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
955 struct stream_response *response = NULL;
956 BOOL request_sample = FALSE;
958 if ((response = media_stream_pop_response(reader, stream)))
960 *status = response->status;
961 *stream_index = stream->index;
962 *stream_flags = response->stream_flags;
963 *timestamp = response->timestamp;
964 *sample = response->sample;
965 if (*sample)
966 IMFSample_AddRef(*sample);
968 source_reader_release_response(response);
970 else
972 *status = S_OK;
973 *stream_index = stream->index;
974 *timestamp = 0;
975 *sample = NULL;
977 if (stream->state == STREAM_STATE_EOS)
979 *stream_flags = MF_SOURCE_READERF_ENDOFSTREAM;
981 else
983 request_sample = !(flags & MF_SOURCE_READER_CONTROLF_DRAIN);
984 *stream_flags = 0;
988 return !request_sample;
991 static HRESULT source_reader_get_next_selected_stream(struct source_reader *reader, unsigned int *stream_index)
993 unsigned int i, start_idx, stop_idx, first_selected = ~0u, requests = ~0u;
994 BOOL selected, stream_drained;
996 start_idx = (reader->last_read_index + 1) % reader->stream_count;
997 stop_idx = reader->last_read_index == ~0u ? reader->stream_count : reader->last_read_index;
999 for (i = start_idx; i < reader->stream_count && i != stop_idx; i = (i + 1) % (reader->stream_count + 1))
1001 stream_drained = reader->streams[i].state == STREAM_STATE_EOS && !reader->streams[i].responses;
1002 selected = SUCCEEDED(source_reader_get_stream_selection(reader, i, &selected)) && selected;
1004 if (selected)
1006 if (first_selected == ~0u)
1007 first_selected = i;
1009 /* Try to balance pending reads. */
1010 if (!stream_drained && reader->streams[i].requests < requests)
1012 requests = reader->streams[i].requests;
1013 *stream_index = i;
1018 /* If all selected streams reached EOS, use first selected. */
1019 if (first_selected != ~0u)
1021 if (requests == ~0u)
1022 *stream_index = first_selected;
1023 reader->last_read_index = *stream_index;
1026 return first_selected == ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED : S_OK;
1029 static HRESULT source_reader_get_stream_read_index(struct source_reader *reader, unsigned int index, unsigned int *stream_index)
1031 BOOL selected;
1032 HRESULT hr;
1034 switch (index)
1036 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1037 *stream_index = reader->first_video_stream_index;
1038 break;
1039 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1040 *stream_index = reader->first_audio_stream_index;
1041 break;
1042 case MF_SOURCE_READER_ANY_STREAM:
1043 return source_reader_get_next_selected_stream(reader, stream_index);
1044 default:
1045 *stream_index = index;
1048 /* Can't read from deselected streams. */
1049 if (SUCCEEDED(hr = source_reader_get_stream_selection(reader, *stream_index, &selected)) && !selected)
1050 hr = MF_E_INVALIDREQUEST;
1052 return hr;
1055 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream)
1057 struct stream_response *ptr, *next;
1059 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &reader->responses, struct stream_response, entry)
1061 if (stream && stream->index != ptr->stream_index &&
1062 ptr->stream_index != MF_SOURCE_READER_FIRST_VIDEO_STREAM &&
1063 ptr->stream_index != MF_SOURCE_READER_FIRST_AUDIO_STREAM &&
1064 ptr->stream_index != MF_SOURCE_READER_ANY_STREAM)
1066 continue;
1068 media_stream_detach_response(reader, ptr);
1069 source_reader_release_response(ptr);
1073 static void source_reader_flush_stream(struct source_reader *reader, DWORD stream_index)
1075 struct media_stream *stream = &reader->streams[stream_index];
1077 source_reader_release_responses(reader, stream);
1078 if (stream->decoder)
1079 IMFTransform_ProcessMessage(stream->decoder, MFT_MESSAGE_COMMAND_FLUSH, 0);
1080 stream->requests = 0;
1083 static HRESULT source_reader_flush(struct source_reader *reader, unsigned int index)
1085 unsigned int stream_index;
1086 HRESULT hr = S_OK;
1088 if (index == MF_SOURCE_READER_ALL_STREAMS)
1090 for (stream_index = 0; stream_index < reader->stream_count; ++stream_index)
1091 source_reader_flush_stream(reader, stream_index);
1093 else
1095 switch (index)
1097 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1098 stream_index = reader->first_video_stream_index;
1099 break;
1100 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1101 stream_index = reader->first_audio_stream_index;
1102 break;
1103 default:
1104 stream_index = index;
1107 if (stream_index < reader->stream_count)
1108 source_reader_flush_stream(reader, stream_index);
1109 else
1110 hr = MF_E_INVALIDSTREAMNUMBER;
1113 return hr;
1116 static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1118 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1119 struct media_stream *stream, stub_stream = { .requests = 1 };
1120 struct source_reader_async_command *command;
1121 struct stream_response *response;
1122 DWORD stream_index, stream_flags;
1123 BOOL report_sample = FALSE;
1124 IMFSample *sample = NULL;
1125 LONGLONG timestamp = 0;
1126 HRESULT hr, status;
1127 IUnknown *state;
1129 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
1130 return hr;
1132 command = impl_from_async_command_IUnknown(state);
1134 switch (command->op)
1136 case SOURCE_READER_ASYNC_READ:
1137 EnterCriticalSection(&reader->cs);
1139 if (SUCCEEDED(hr = source_reader_start_source(reader)))
1141 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, command->u.read.stream_index, &stream_index)))
1143 stream = &reader->streams[stream_index];
1145 if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status,
1146 &stream_index, &stream_flags, &timestamp, &sample)))
1148 stream->requests++;
1149 source_reader_request_sample(reader, stream);
1150 /* FIXME: set error stream/reader state on request failure */
1153 else
1155 stub_stream.index = command->u.read.stream_index;
1156 source_reader_queue_response(reader, &stub_stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL);
1160 LeaveCriticalSection(&reader->cs);
1162 if (report_sample)
1163 IMFSourceReaderCallback_OnReadSample(reader->async_callback, status, stream_index, stream_flags,
1164 timestamp, sample);
1166 if (sample)
1167 IMFSample_Release(sample);
1169 break;
1171 case SOURCE_READER_ASYNC_SEEK:
1173 EnterCriticalSection(&reader->cs);
1174 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, &command->u.seek.format,
1175 &command->u.seek.position)))
1177 reader->flags |= SOURCE_READER_SEEKING;
1179 LeaveCriticalSection(&reader->cs);
1181 break;
1183 case SOURCE_READER_ASYNC_SAMPLE_READY:
1185 EnterCriticalSection(&reader->cs);
1186 response = media_stream_pop_response(reader, NULL);
1187 LeaveCriticalSection(&reader->cs);
1189 if (response)
1191 IMFSourceReaderCallback_OnReadSample(reader->async_callback, response->status, response->stream_index,
1192 response->stream_flags, response->timestamp, response->sample);
1193 source_reader_release_response(response);
1196 break;
1197 case SOURCE_READER_ASYNC_FLUSH:
1198 EnterCriticalSection(&reader->cs);
1199 source_reader_flush(reader, command->u.flush.stream_index);
1200 reader->flags &= ~SOURCE_READER_FLUSHING;
1201 LeaveCriticalSection(&reader->cs);
1203 IMFSourceReaderCallback_OnFlush(reader->async_callback, command->u.flush.stream_index);
1204 break;
1205 default:
1209 IUnknown_Release(state);
1211 return S_OK;
1214 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl =
1216 source_reader_callback_QueryInterface,
1217 source_reader_async_commands_callback_AddRef,
1218 source_reader_async_commands_callback_Release,
1219 source_reader_callback_GetParameters,
1220 source_reader_async_commands_callback_Invoke,
1223 static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReader *iface, REFIID riid, void **out)
1225 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1227 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1229 if(IsEqualGUID(riid, &IID_IUnknown) ||
1230 IsEqualGUID(riid, &IID_IMFSourceReader))
1232 *out = &reader->IMFSourceReader_iface;
1234 else
1236 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
1237 *out = NULL;
1238 return E_NOINTERFACE;
1241 IUnknown_AddRef((IUnknown*)*out);
1242 return S_OK;
1245 static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface)
1247 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1248 ULONG refcount = InterlockedIncrement(&reader->refcount);
1250 TRACE("%p, refcount %u.\n", iface, refcount);
1252 return refcount;
1255 static ULONG WINAPI src_reader_Release(IMFSourceReader *iface)
1257 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1258 ULONG refcount = InterlockedDecrement(&reader->refcount);
1259 unsigned int i;
1261 TRACE("%p, refcount %u.\n", iface, refcount);
1263 if (!refcount)
1265 if (reader->async_callback)
1266 IMFSourceReaderCallback_Release(reader->async_callback);
1267 if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE)
1268 IMFMediaSource_Shutdown(reader->source);
1269 if (reader->descriptor)
1270 IMFPresentationDescriptor_Release(reader->descriptor);
1271 IMFMediaSource_Release(reader->source);
1273 for (i = 0; i < reader->stream_count; ++i)
1275 struct media_stream *stream = &reader->streams[i];
1277 if (stream->stream)
1278 IMFMediaStream_Release(stream->stream);
1279 if (stream->current)
1280 IMFMediaType_Release(stream->current);
1281 if (stream->decoder)
1282 IMFTransform_Release(stream->decoder);
1284 source_reader_release_responses(reader, NULL);
1285 heap_free(reader->streams);
1286 DeleteCriticalSection(&reader->cs);
1287 heap_free(reader);
1290 return refcount;
1293 static HRESULT WINAPI src_reader_GetStreamSelection(IMFSourceReader *iface, DWORD index, BOOL *selected)
1295 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1297 TRACE("%p, %#x, %p.\n", iface, index, selected);
1299 switch (index)
1301 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1302 index = reader->first_video_stream_index;
1303 break;
1304 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1305 index = reader->first_audio_stream_index;
1306 break;
1307 default:
1311 return source_reader_get_stream_selection(reader, index, selected);
1314 static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReader *iface, DWORD index, BOOL selection)
1316 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1317 HRESULT hr = S_OK;
1318 BOOL selection_changed = FALSE, selected;
1319 unsigned int i;
1321 TRACE("%p, %#x, %d.\n", iface, index, selection);
1323 selection = !!selection;
1325 EnterCriticalSection(&reader->cs);
1327 if (index == MF_SOURCE_READER_ALL_STREAMS)
1329 for (i = 0; i < reader->stream_count; ++i)
1331 if (!selection_changed)
1333 source_reader_get_stream_selection(reader, i, &selected);
1334 selection_changed = !!(selected ^ selection);
1337 if (selection)
1338 IMFPresentationDescriptor_SelectStream(reader->descriptor, i);
1339 else
1340 IMFPresentationDescriptor_DeselectStream(reader->descriptor, i);
1343 else
1345 switch (index)
1347 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1348 index = reader->first_video_stream_index;
1349 break;
1350 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1351 index = reader->first_audio_stream_index;
1352 break;
1353 default:
1357 source_reader_get_stream_selection(reader, index, &selected);
1358 selection_changed = !!(selected ^ selection);
1360 if (selection)
1361 hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
1362 else
1363 hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
1366 if (selection_changed)
1367 reader->last_read_index = ~0u;
1369 LeaveCriticalSection(&reader->cs);
1371 return SUCCEEDED(hr) ? S_OK : MF_E_INVALIDSTREAMNUMBER;
1374 static HRESULT source_reader_get_native_media_type(struct source_reader *reader, DWORD index, DWORD type_index,
1375 IMFMediaType **type)
1377 IMFMediaTypeHandler *handler;
1378 IMFStreamDescriptor *sd;
1379 IMFMediaType *src_type;
1380 BOOL selected;
1381 HRESULT hr;
1383 switch (index)
1385 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1386 index = reader->first_video_stream_index;
1387 break;
1388 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1389 index = reader->first_audio_stream_index;
1390 break;
1391 default:
1395 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1396 return MF_E_INVALIDSTREAMNUMBER;
1398 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
1399 IMFStreamDescriptor_Release(sd);
1400 if (FAILED(hr))
1401 return hr;
1403 if (type_index == MF_SOURCE_READER_CURRENT_TYPE_INDEX)
1404 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &src_type);
1405 else
1406 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, type_index, &src_type);
1407 IMFMediaTypeHandler_Release(handler);
1409 if (SUCCEEDED(hr))
1411 if (SUCCEEDED(hr = MFCreateMediaType(type)))
1412 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)*type);
1413 IMFMediaType_Release(src_type);
1416 return hr;
1419 static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReader *iface, DWORD index, DWORD type_index,
1420 IMFMediaType **type)
1422 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1424 TRACE("%p, %#x, %#x, %p.\n", iface, index, type_index, type);
1426 return source_reader_get_native_media_type(reader, index, type_index, type);
1429 static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReader *iface, DWORD index, IMFMediaType **type)
1431 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1432 HRESULT hr;
1434 TRACE("%p, %#x, %p.\n", iface, index, type);
1436 switch (index)
1438 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1439 index = reader->first_video_stream_index;
1440 break;
1441 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1442 index = reader->first_audio_stream_index;
1443 break;
1444 default:
1448 if (index >= reader->stream_count)
1449 return MF_E_INVALIDSTREAMNUMBER;
1451 if (FAILED(hr = MFCreateMediaType(type)))
1452 return hr;
1454 EnterCriticalSection(&reader->cs);
1456 hr = IMFMediaType_CopyAllItems(reader->streams[index].current, (IMFAttributes *)*type);
1458 LeaveCriticalSection(&reader->cs);
1460 return hr;
1463 static HRESULT source_reader_get_source_type_handler(struct source_reader *reader, DWORD index,
1464 IMFMediaTypeHandler **handler)
1466 IMFStreamDescriptor *sd;
1467 BOOL selected;
1468 HRESULT hr;
1470 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1471 return hr;
1473 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, handler);
1474 IMFStreamDescriptor_Release(sd);
1476 return hr;
1479 static HRESULT source_reader_set_compatible_media_type(struct source_reader *reader, DWORD index, IMFMediaType *type)
1481 IMFMediaTypeHandler *type_handler;
1482 IMFMediaType *native_type;
1483 BOOL type_set = FALSE;
1484 unsigned int i = 0;
1485 DWORD flags;
1486 HRESULT hr;
1488 if (FAILED(hr = IMFMediaType_IsEqual(type, reader->streams[index].current, &flags)))
1489 return hr;
1491 if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES))
1492 return MF_E_INVALIDMEDIATYPE;
1494 /* No need for a decoder or type change. */
1495 if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
1496 return S_OK;
1498 if (FAILED(hr = source_reader_get_source_type_handler(reader, index, &type_handler)))
1499 return hr;
1501 while (!type_set && IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, i++, &native_type) == S_OK)
1503 static const DWORD compare_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES;
1505 if (SUCCEEDED(IMFMediaType_IsEqual(native_type, type, &flags)) && (flags & compare_flags) == compare_flags)
1507 if ((type_set = SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler, native_type))))
1508 IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)reader->streams[index].current);
1511 IMFMediaType_Release(native_type);
1514 IMFMediaTypeHandler_Release(type_handler);
1516 return type_set ? S_OK : S_FALSE;
1519 static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWORD index, const CLSID *clsid,
1520 IMFMediaType *input_type, IMFMediaType *output_type)
1522 IMFMediaTypeHandler *type_handler;
1523 IMFTransform *transform = NULL;
1524 IMFMediaType *type = NULL;
1525 DWORD flags;
1526 HRESULT hr;
1527 int i = 0;
1529 if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform)))
1531 WARN("Failed to create transform object, hr %#x.\n", hr);
1532 return hr;
1535 if (FAILED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)))
1537 WARN("Failed to set decoder input type, hr %#x.\n", hr);
1538 IMFTransform_Release(transform);
1539 return hr;
1542 /* Find the relevant output type. */
1543 while (IMFTransform_GetOutputAvailableType(transform, 0, i++, &type) == S_OK)
1545 flags = 0;
1547 if (SUCCEEDED(IMFMediaType_IsEqual(type, output_type, &flags)))
1549 if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
1551 if (SUCCEEDED(IMFTransform_SetOutputType(transform, 0, type, 0)))
1553 if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler)))
1555 IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type);
1556 IMFMediaTypeHandler_Release(type_handler);
1559 if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)reader->streams[index].current)))
1560 WARN("Failed to copy attributes, hr %#x.\n", hr);
1561 IMFMediaType_Release(type);
1563 if (reader->streams[index].decoder)
1564 IMFTransform_Release(reader->streams[index].decoder);
1566 reader->streams[index].decoder = transform;
1568 return S_OK;
1573 IMFMediaType_Release(type);
1576 WARN("Failed to find suitable decoder output type.\n");
1578 IMFTransform_Release(transform);
1580 return MF_E_TOPO_CODEC_NOT_FOUND;
1583 static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type)
1585 MFT_REGISTER_TYPE_INFO in_type, out_type;
1586 CLSID *clsids, mft_clsid, category;
1587 unsigned int i = 0, count;
1588 IMFMediaType *input_type;
1589 HRESULT hr;
1591 /* TODO: should we check if the source type is compressed? */
1593 if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType)))
1594 return hr;
1596 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video))
1598 category = MFT_CATEGORY_VIDEO_DECODER;
1600 else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio))
1602 category = MFT_CATEGORY_AUDIO_DECODER;
1604 else
1606 WARN("Unhandled major type %s.\n", debugstr_guid(&out_type.guidMajorType));
1607 return MF_E_TOPO_CODEC_NOT_FOUND;
1610 if (FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype)))
1611 return hr;
1613 in_type.guidMajorType = out_type.guidMajorType;
1615 while (source_reader_get_native_media_type(reader, index, i++, &input_type) == S_OK)
1617 if (SUCCEEDED(IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype)))
1619 count = 0;
1620 if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &clsids, &count)) && count)
1622 mft_clsid = clsids[0];
1623 CoTaskMemFree(clsids);
1625 /* TODO: Should we iterate over all of them? */
1626 if (SUCCEEDED(source_reader_configure_decoder(reader, index, &mft_clsid, input_type, output_type)))
1628 IMFMediaType_Release(input_type);
1629 return S_OK;
1635 IMFMediaType_Release(input_type);
1638 return MF_E_TOPO_CODEC_NOT_FOUND;
1641 static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWORD index, DWORD *reserved,
1642 IMFMediaType *type)
1644 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1645 HRESULT hr;
1647 TRACE("%p, %#x, %p, %p.\n", iface, index, reserved, type);
1649 switch (index)
1651 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1652 index = reader->first_video_stream_index;
1653 break;
1654 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1655 index = reader->first_audio_stream_index;
1656 break;
1657 default:
1661 if (index >= reader->stream_count)
1662 return MF_E_INVALIDSTREAMNUMBER;
1664 /* FIXME: setting the output type while streaming should trigger a flush */
1666 EnterCriticalSection(&reader->cs);
1668 if ((hr = source_reader_set_compatible_media_type(reader, index, type)) == S_FALSE)
1669 hr = source_reader_create_decoder_for_stream(reader, index, type);
1671 LeaveCriticalSection(&reader->cs);
1673 return hr;
1676 static HRESULT WINAPI src_reader_SetCurrentPosition(IMFSourceReader *iface, REFGUID format, REFPROPVARIANT position)
1678 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1679 struct source_reader_async_command *command;
1680 unsigned int i, flags;
1681 HRESULT hr;
1683 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), position);
1685 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
1686 return hr;
1688 if (!(flags & MFMEDIASOURCE_CAN_SEEK))
1689 return MF_E_INVALIDREQUEST;
1691 EnterCriticalSection(&reader->cs);
1693 /* Check if we got pending requests. */
1694 for (i = 0; i < reader->stream_count; ++i)
1696 if (reader->streams[i].requests)
1698 hr = MF_E_INVALIDREQUEST;
1699 break;
1703 if (SUCCEEDED(hr))
1705 if (reader->async_callback)
1707 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK, &command)))
1709 command->u.seek.format = *format;
1710 PropVariantCopy(&command->u.seek.position, position);
1712 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &reader->async_commands_callback,
1713 &command->IUnknown_iface);
1714 IUnknown_Release(&command->IUnknown_iface);
1717 else
1719 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, format, position)))
1721 reader->flags |= SOURCE_READER_SEEKING;
1722 while (reader->flags & SOURCE_READER_SEEKING)
1724 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
1730 LeaveCriticalSection(&reader->cs);
1732 return hr;
1735 static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD index, DWORD flags, DWORD *actual_index,
1736 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1738 unsigned int actual_index_tmp;
1739 struct media_stream *stream;
1740 LONGLONG timestamp_tmp;
1741 DWORD stream_index;
1742 HRESULT hr = S_OK;
1744 if (!stream_flags || !sample)
1745 return E_POINTER;
1747 *sample = NULL;
1749 if (!timestamp)
1750 timestamp = &timestamp_tmp;
1752 if (!actual_index)
1753 actual_index = &actual_index_tmp;
1755 if (SUCCEEDED(hr = source_reader_start_source(reader)))
1757 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, index, &stream_index)))
1759 *actual_index = stream_index;
1761 stream = &reader->streams[stream_index];
1763 if (!source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
1764 timestamp, sample))
1766 while (!source_reader_got_response_for_stream(reader, stream) && stream->state != STREAM_STATE_EOS)
1768 stream->requests++;
1769 if (FAILED(hr = source_reader_request_sample(reader, stream)))
1770 WARN("Failed to request a sample, hr %#x.\n", hr);
1771 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
1773 *stream_flags = MF_SOURCE_READERF_ERROR;
1774 *timestamp = 0;
1775 break;
1777 SleepConditionVariableCS(&reader->sample_event, &reader->cs, INFINITE);
1779 if (SUCCEEDED(hr))
1780 source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
1781 timestamp, sample);
1784 else
1786 *actual_index = index;
1787 *stream_flags = MF_SOURCE_READERF_ERROR;
1788 *timestamp = 0;
1792 TRACE("Stream %u, got sample %p, flags %#x.\n", *actual_index, *sample, *stream_flags);
1794 return hr;
1797 static HRESULT source_reader_read_sample_async(struct source_reader *reader, unsigned int index, unsigned int flags,
1798 unsigned int *actual_index, unsigned int *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1800 struct source_reader_async_command *command;
1801 HRESULT hr;
1803 if (actual_index || stream_flags || timestamp || sample)
1804 return E_INVALIDARG;
1806 if (reader->flags & SOURCE_READER_FLUSHING)
1807 hr = MF_E_NOTACCEPTING;
1808 else
1810 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_READ, &command)))
1812 command->u.read.stream_index = index;
1813 command->u.read.flags = flags;
1815 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &reader->async_commands_callback, &command->IUnknown_iface);
1816 IUnknown_Release(&command->IUnknown_iface);
1820 return hr;
1823 static HRESULT WINAPI src_reader_ReadSample(IMFSourceReader *iface, DWORD index, DWORD flags, DWORD *actual_index,
1824 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1826 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1827 HRESULT hr;
1829 TRACE("%p, %#x, %#x, %p, %p, %p, %p\n", iface, index, flags, actual_index, stream_flags, timestamp, sample);
1831 EnterCriticalSection(&reader->cs);
1833 while (reader->flags & SOURCE_READER_SEEKING)
1835 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
1838 if (reader->async_callback)
1839 hr = source_reader_read_sample_async(reader, index, flags, actual_index, stream_flags, timestamp, sample);
1840 else
1841 hr = source_reader_read_sample(reader, index, flags, actual_index, stream_flags, timestamp, sample);
1843 LeaveCriticalSection(&reader->cs);
1845 return hr;
1848 static HRESULT source_reader_flush_async(struct source_reader *reader, unsigned int index)
1850 struct source_reader_async_command *command;
1851 unsigned int stream_index;
1852 HRESULT hr;
1854 if (reader->flags & SOURCE_READER_FLUSHING)
1855 return MF_E_INVALIDREQUEST;
1857 switch (index)
1859 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1860 stream_index = reader->first_video_stream_index;
1861 break;
1862 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1863 stream_index = reader->first_audio_stream_index;
1864 break;
1865 default:
1866 stream_index = index;
1869 reader->flags |= SOURCE_READER_FLUSHING;
1871 if (stream_index != MF_SOURCE_READER_ALL_STREAMS && stream_index >= reader->stream_count)
1872 return MF_E_INVALIDSTREAMNUMBER;
1874 if (FAILED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH, &command)))
1875 return hr;
1877 command->u.flush.stream_index = stream_index;
1879 hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &reader->async_commands_callback, &command->IUnknown_iface);
1880 IUnknown_Release(&command->IUnknown_iface);
1882 return hr;
1885 static HRESULT WINAPI src_reader_Flush(IMFSourceReader *iface, DWORD index)
1887 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1888 HRESULT hr;
1890 TRACE("%p, %#x.\n", iface, index);
1892 EnterCriticalSection(&reader->cs);
1894 if (reader->async_callback)
1895 hr = source_reader_flush_async(reader, index);
1896 else
1897 hr = source_reader_flush(reader, index);
1899 LeaveCriticalSection(&reader->cs);
1901 return hr;
1904 static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReader *iface, DWORD index, REFGUID service,
1905 REFIID riid, void **object)
1907 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1908 IUnknown *obj = NULL;
1909 HRESULT hr = S_OK;
1911 TRACE("%p, %#x, %s, %s, %p\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object);
1913 EnterCriticalSection(&reader->cs);
1915 switch (index)
1917 case MF_SOURCE_READER_MEDIASOURCE:
1918 obj = (IUnknown *)reader->source;
1919 break;
1920 default:
1921 if (index == MF_SOURCE_READER_FIRST_VIDEO_STREAM)
1922 index = reader->first_video_stream_index;
1923 else if (index == MF_SOURCE_READER_FIRST_AUDIO_STREAM)
1924 index = reader->first_audio_stream_index;
1926 if (index >= reader->stream_count)
1927 hr = MF_E_INVALIDSTREAMNUMBER;
1928 else
1930 obj = (IUnknown *)reader->streams[index].decoder;
1931 if (!obj) hr = E_NOINTERFACE;
1933 break;
1936 if (obj)
1937 IUnknown_AddRef(obj);
1939 LeaveCriticalSection(&reader->cs);
1941 if (obj)
1943 if (IsEqualGUID(service, &GUID_NULL))
1945 hr = IUnknown_QueryInterface(obj, riid, object);
1947 else
1949 IMFGetService *gs;
1951 hr = IUnknown_QueryInterface(obj, &IID_IMFGetService, (void **)&gs);
1952 if (SUCCEEDED(hr))
1954 hr = IMFGetService_GetService(gs, service, riid, object);
1955 IMFGetService_Release(gs);
1960 if (obj)
1961 IUnknown_Release(obj);
1963 return hr;
1966 static HRESULT WINAPI src_reader_GetPresentationAttribute(IMFSourceReader *iface, DWORD index,
1967 REFGUID guid, PROPVARIANT *value)
1969 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1970 IMFStreamDescriptor *sd;
1971 BOOL selected;
1972 HRESULT hr;
1974 TRACE("%p, %#x, %s, %p.\n", iface, index, debugstr_guid(guid), value);
1976 switch (index)
1978 case MF_SOURCE_READER_MEDIASOURCE:
1979 if (IsEqualGUID(guid, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS))
1981 DWORD flags;
1983 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
1984 return hr;
1986 value->vt = VT_UI4;
1987 value->u.ulVal = flags;
1988 return S_OK;
1990 else
1992 return IMFPresentationDescriptor_GetItem(reader->descriptor, guid, value);
1994 break;
1995 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1996 index = reader->first_video_stream_index;
1997 break;
1998 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1999 index = reader->first_audio_stream_index;
2000 break;
2001 default:
2005 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
2006 return hr;
2008 hr = IMFStreamDescriptor_GetItem(sd, guid, value);
2009 IMFStreamDescriptor_Release(sd);
2011 return hr;
2014 static const IMFSourceReaderVtbl srcreader_vtbl =
2016 src_reader_QueryInterface,
2017 src_reader_AddRef,
2018 src_reader_Release,
2019 src_reader_GetStreamSelection,
2020 src_reader_SetStreamSelection,
2021 src_reader_GetNativeMediaType,
2022 src_reader_GetCurrentMediaType,
2023 src_reader_SetCurrentMediaType,
2024 src_reader_SetCurrentPosition,
2025 src_reader_ReadSample,
2026 src_reader_Flush,
2027 src_reader_GetServiceForStream,
2028 src_reader_GetPresentationAttribute
2031 static DWORD reader_get_first_stream_index(IMFPresentationDescriptor *descriptor, const GUID *major)
2033 unsigned int count, i;
2034 BOOL selected;
2035 HRESULT hr;
2036 GUID guid;
2038 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count)))
2039 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2041 for (i = 0; i < count; ++i)
2043 IMFMediaTypeHandler *handler;
2044 IMFStreamDescriptor *sd;
2046 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i, &selected, &sd)))
2048 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2049 IMFStreamDescriptor_Release(sd);
2050 if (SUCCEEDED(hr))
2052 hr = IMFMediaTypeHandler_GetMajorType(handler, &guid);
2053 IMFMediaTypeHandler_Release(handler);
2054 if (FAILED(hr))
2056 WARN("Failed to get stream major type, hr %#x.\n", hr);
2057 continue;
2060 if (IsEqualGUID(&guid, major))
2062 return i;
2068 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2071 static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttributes *attributes,
2072 BOOL shutdown_on_release, REFIID riid, void **out)
2074 struct source_reader *object;
2075 unsigned int i;
2076 HRESULT hr;
2078 object = heap_alloc_zero(sizeof(*object));
2079 if (!object)
2080 return E_OUTOFMEMORY;
2082 object->IMFSourceReader_iface.lpVtbl = &srcreader_vtbl;
2083 object->source_events_callback.lpVtbl = &source_events_callback_vtbl;
2084 object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl;
2085 object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl;
2086 object->refcount = 1;
2087 list_init(&object->responses);
2088 if (shutdown_on_release)
2089 object->flags |= SOURCE_READER_SHUTDOWN_ON_RELEASE;
2090 object->source = source;
2091 IMFMediaSource_AddRef(object->source);
2092 InitializeCriticalSection(&object->cs);
2093 InitializeConditionVariable(&object->sample_event);
2094 InitializeConditionVariable(&object->state_event);
2096 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor)))
2097 goto failed;
2099 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(object->descriptor, &object->stream_count)))
2100 goto failed;
2102 if (!(object->streams = heap_alloc_zero(object->stream_count * sizeof(*object->streams))))
2104 hr = E_OUTOFMEMORY;
2105 goto failed;
2108 /* Set initial current media types. */
2109 for (i = 0; i < object->stream_count; ++i)
2111 IMFMediaTypeHandler *handler;
2112 IMFStreamDescriptor *sd;
2113 IMFMediaType *src_type;
2114 BOOL selected;
2116 if (FAILED(hr = MFCreateMediaType(&object->streams[i].current)))
2117 break;
2119 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(object->descriptor, i, &selected, &sd)))
2120 break;
2122 if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &object->streams[i].id)))
2123 WARN("Failed to get stream identifier, hr %#x.\n", hr);
2125 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2126 IMFStreamDescriptor_Release(sd);
2127 if (FAILED(hr))
2128 break;
2130 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &src_type);
2131 IMFMediaTypeHandler_Release(handler);
2132 if (FAILED(hr))
2133 break;
2135 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)object->streams[i].current);
2136 IMFMediaType_Release(src_type);
2137 if (FAILED(hr))
2138 break;
2140 object->streams[i].index = i;
2143 if (FAILED(hr))
2144 goto failed;
2146 /* At least one major type has to be set. */
2147 object->first_audio_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Audio);
2148 object->first_video_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Video);
2149 object->last_read_index = ~0u;
2151 if (object->first_audio_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX &&
2152 object->first_video_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX)
2154 hr = MF_E_ATTRIBUTENOTFOUND;
2157 if (FAILED(hr = IMFMediaSource_BeginGetEvent(object->source, &object->source_events_callback,
2158 (IUnknown *)object->source)))
2160 goto failed;
2163 if (attributes)
2165 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_ASYNC_CALLBACK, &IID_IMFSourceReaderCallback,
2166 (void **)&object->async_callback);
2167 if (object->async_callback)
2168 TRACE("Using async callback %p.\n", object->async_callback);
2171 hr = IMFSourceReader_QueryInterface(&object->IMFSourceReader_iface, riid, out);
2173 failed:
2174 IMFSourceReader_Release(&object->IMFSourceReader_iface);
2175 return hr;
2178 static HRESULT bytestream_get_url_hint(IMFByteStream *stream, WCHAR const **url)
2180 static const unsigned char asfmagic[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c};
2181 static const unsigned char wavmagic[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '};
2182 static const unsigned char wavmask[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
2183 static const unsigned char isommagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00};
2184 static const unsigned char mp42magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00};
2185 static const unsigned char mp4mask[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00};
2186 static const struct stream_content_url_hint
2188 const unsigned char *magic;
2189 const WCHAR *url;
2190 const unsigned char *mask;
2192 url_hints[] =
2194 { asfmagic, L".asf" },
2195 { wavmagic, L".wav", wavmask },
2196 { isommagic, L".mp4", mp4mask },
2197 { mp42magic, L".mp4", mp4mask },
2199 unsigned char buffer[4 * sizeof(unsigned int)], pattern[4 * sizeof(unsigned int)];
2200 unsigned int i, j, length = 0, caps = 0;
2201 IMFAttributes *attributes;
2202 QWORD position;
2203 HRESULT hr;
2205 *url = NULL;
2207 if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
2209 IMFAttributes_GetStringLength(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &length);
2210 IMFAttributes_Release(attributes);
2213 if (length)
2214 return S_OK;
2216 if (FAILED(hr = IMFByteStream_GetCapabilities(stream, &caps)))
2217 return hr;
2219 if (!(caps & MFBYTESTREAM_IS_SEEKABLE))
2220 return S_OK;
2222 if (FAILED(hr = IMFByteStream_GetCurrentPosition(stream, &position)))
2223 return hr;
2225 hr = IMFByteStream_Read(stream, buffer, sizeof(buffer), &length);
2226 IMFByteStream_SetCurrentPosition(stream, position);
2227 if (FAILED(hr))
2228 return hr;
2230 if (length < sizeof(buffer))
2231 return S_OK;
2233 for (i = 0; i < ARRAY_SIZE(url_hints); ++i)
2235 memcpy(pattern, buffer, sizeof(buffer));
2236 if (url_hints[i].mask)
2238 unsigned int *mask = (unsigned int *)url_hints[i].mask;
2239 unsigned int *data = (unsigned int *)pattern;
2241 for (j = 0; j < sizeof(buffer) / sizeof(unsigned int); ++j)
2242 data[j] &= mask[j];
2245 if (!memcmp(pattern, url_hints[i].magic, sizeof(pattern)))
2247 *url = url_hints[i].url;
2248 break;
2252 if (*url)
2253 TRACE("Stream type guessed as %s from %s.\n", debugstr_w(*url), debugstr_an((char *)buffer, length));
2254 else
2255 WARN("Unrecognized content type %s.\n", debugstr_an((char *)buffer, length));
2257 return S_OK;
2260 static HRESULT create_source_reader_from_stream(IMFByteStream *stream, IMFAttributes *attributes,
2261 REFIID riid, void **out)
2263 IPropertyStore *props = NULL;
2264 IMFSourceResolver *resolver;
2265 MF_OBJECT_TYPE obj_type;
2266 IMFMediaSource *source;
2267 const WCHAR *url;
2268 HRESULT hr;
2270 /* If stream does not have content type set, try to guess from starting byte sequence. */
2271 if (FAILED(hr = bytestream_get_url_hint(stream, &url)))
2272 return hr;
2274 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2275 return hr;
2277 if (attributes)
2278 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2279 (void **)&props);
2281 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, url, MF_RESOLUTION_MEDIASOURCE, props,
2282 &obj_type, (IUnknown **)&source);
2283 IMFSourceResolver_Release(resolver);
2284 if (props)
2285 IPropertyStore_Release(props);
2286 if (FAILED(hr))
2287 return hr;
2289 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2290 IMFMediaSource_Release(source);
2291 return hr;
2294 static HRESULT create_source_reader_from_url(const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2296 IPropertyStore *props = NULL;
2297 IMFSourceResolver *resolver;
2298 IUnknown *object = NULL;
2299 MF_OBJECT_TYPE obj_type;
2300 IMFMediaSource *source;
2301 HRESULT hr;
2303 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2304 return hr;
2306 if (attributes)
2307 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2308 (void **)&props);
2310 hr = IMFSourceResolver_CreateObjectFromURL(resolver, url, MF_RESOLUTION_MEDIASOURCE, props, &obj_type,
2311 &object);
2312 if (SUCCEEDED(hr))
2314 switch (obj_type)
2316 case MF_OBJECT_BYTESTREAM:
2317 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, (IMFByteStream *)object, NULL,
2318 MF_RESOLUTION_MEDIASOURCE, props, &obj_type, (IUnknown **)&source);
2319 break;
2320 case MF_OBJECT_MEDIASOURCE:
2321 source = (IMFMediaSource *)object;
2322 IMFMediaSource_AddRef(source);
2323 break;
2324 default:
2325 WARN("Unknown object type %d.\n", obj_type);
2326 hr = E_UNEXPECTED;
2328 IUnknown_Release(object);
2331 IMFSourceResolver_Release(resolver);
2332 if (props)
2333 IPropertyStore_Release(props);
2334 if (FAILED(hr))
2335 return hr;
2337 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2338 IMFMediaSource_Release(source);
2339 return hr;
2342 static HRESULT create_source_reader_from_object(IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2344 IMFMediaSource *source = NULL;
2345 IMFByteStream *stream = NULL;
2346 HRESULT hr;
2348 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSource, (void **)&source);
2349 if (FAILED(hr))
2350 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2352 if (source)
2354 UINT32 disconnect = 0;
2356 if (attributes)
2357 IMFAttributes_GetUINT32(attributes, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN, &disconnect);
2358 hr = create_source_reader_from_source(source, attributes, !disconnect, riid, out);
2360 else if (stream)
2361 hr = create_source_reader_from_stream(stream, attributes, riid, out);
2363 if (source)
2364 IMFMediaSource_Release(source);
2365 if (stream)
2366 IMFByteStream_Release(stream);
2368 return hr;
2371 /***********************************************************************
2372 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2374 HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes,
2375 IMFSourceReader **reader)
2377 TRACE("%p, %p, %p.\n", stream, attributes, reader);
2379 return create_source_reader_from_object((IUnknown *)stream, attributes, &IID_IMFSourceReader, (void **)reader);
2382 /***********************************************************************
2383 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2385 HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes,
2386 IMFSourceReader **reader)
2388 TRACE("%p, %p, %p.\n", source, attributes, reader);
2390 return create_source_reader_from_object((IUnknown *)source, attributes, &IID_IMFSourceReader, (void **)reader);
2393 /***********************************************************************
2394 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2396 HRESULT WINAPI MFCreateSourceReaderFromURL(const WCHAR *url, IMFAttributes *attributes, IMFSourceReader **reader)
2398 TRACE("%s, %p, %p.\n", debugstr_w(url), attributes, reader);
2400 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, (void **)reader);
2403 static HRESULT WINAPI readwrite_factory_QueryInterface(IMFReadWriteClassFactory *iface, REFIID riid, void **out)
2405 if (IsEqualIID(riid, &IID_IMFReadWriteClassFactory) ||
2406 IsEqualIID(riid, &IID_IUnknown))
2408 *out = iface;
2409 IMFReadWriteClassFactory_AddRef(iface);
2410 return S_OK;
2413 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
2414 *out = NULL;
2415 return E_NOINTERFACE;
2418 static ULONG WINAPI readwrite_factory_AddRef(IMFReadWriteClassFactory *iface)
2420 return 2;
2423 static ULONG WINAPI readwrite_factory_Release(IMFReadWriteClassFactory *iface)
2425 return 1;
2428 static HRESULT WINAPI readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2429 const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2431 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid), debugstr_w(url), attributes, debugstr_guid(riid), out);
2433 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2435 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, out);
2438 FIXME("Unsupported %s.\n", debugstr_guid(clsid));
2440 return E_NOTIMPL;
2443 static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2444 IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2446 HRESULT hr;
2448 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid), unk, attributes, debugstr_guid(riid), out);
2450 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2452 return create_source_reader_from_object(unk, attributes, riid, out);
2454 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
2456 IMFByteStream *stream = NULL;
2457 IMFMediaSink *sink = NULL;
2459 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2460 if (FAILED(hr))
2461 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSink, (void **)&sink);
2463 if (stream)
2464 hr = create_sink_writer_from_stream(stream, attributes, riid, out);
2465 else if (sink)
2466 hr = create_sink_writer_from_sink(sink, attributes, riid, out);
2468 if (sink)
2469 IMFMediaSink_Release(sink);
2470 if (stream)
2471 IMFByteStream_Release(stream);
2473 return hr;
2475 else
2477 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2478 *out = NULL;
2479 return E_FAIL;
2483 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl =
2485 readwrite_factory_QueryInterface,
2486 readwrite_factory_AddRef,
2487 readwrite_factory_Release,
2488 readwrite_factory_CreateInstanceFromURL,
2489 readwrite_factory_CreateInstanceFromObject,
2492 static IMFReadWriteClassFactory readwrite_factory = { &readwrite_factory_vtbl };
2494 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
2496 TRACE("%s, %p.\n", debugstr_guid(riid), out);
2498 if (IsEqualGUID(riid, &IID_IClassFactory) ||
2499 IsEqualGUID(riid, &IID_IUnknown))
2501 IClassFactory_AddRef(iface);
2502 *out = iface;
2503 return S_OK;
2506 WARN("interface %s not implemented\n", debugstr_guid(riid));
2507 *out = NULL;
2508 return E_NOINTERFACE;
2511 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
2513 return 2;
2516 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
2518 return 1;
2521 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out)
2523 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), out);
2525 *out = NULL;
2527 if (outer)
2528 return CLASS_E_NOAGGREGATION;
2530 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory, riid, out);
2533 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
2535 FIXME("%d.\n", dolock);
2536 return S_OK;
2539 static const IClassFactoryVtbl classfactoryvtbl =
2541 classfactory_QueryInterface,
2542 classfactory_AddRef,
2543 classfactory_Release,
2544 classfactory_CreateInstance,
2545 classfactory_LockServer,
2548 static IClassFactory classfactory = { &classfactoryvtbl };
2550 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
2552 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), out);
2554 if (IsEqualGUID(clsid, &CLSID_MFReadWriteClassFactory))
2555 return IClassFactory_QueryInterface(&classfactory, riid, out);
2557 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2558 *out = NULL;
2559 return CLASS_E_CLASSNOTAVAILABLE;