hidclass.sys: Pass sizeof(packet) as input for IOCTL_HID_SET_OUTPUT_REPORT.
[wine.git] / dlls / mfreadwrite / reader.c
blobd26778dad36e247573971692e186cb652fb1c9fa
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"
36 #include "d3d9.h"
37 #include "initguid.h"
38 #include "dxva2api.h"
40 #include "wine/debug.h"
41 #include "wine/list.h"
43 #include "mf_private.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
47 struct stream_response
49 struct list entry;
50 HRESULT status;
51 DWORD stream_index;
52 DWORD stream_flags;
53 LONGLONG timestamp;
54 IMFSample *sample;
55 unsigned int sa_pending : 1;
58 enum media_stream_state
60 STREAM_STATE_READY = 0,
61 STREAM_STATE_EOS,
64 enum media_source_state
66 SOURCE_STATE_STOPPED = 0,
67 SOURCE_STATE_STARTED,
70 enum media_stream_flags
72 STREAM_FLAG_SAMPLE_REQUESTED = 0x1, /* Protects from making multiple sample requests. */
73 STREAM_FLAG_SELECTED = 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
74 STREAM_FLAG_PRESENTED = 0x4, /* Set if stream was selected last time Start() was called. */
77 struct stream_transform
79 IMFTransform *transform;
80 unsigned int min_buffer_size;
83 struct media_stream
85 IMFMediaStream *stream;
86 IMFMediaType *current;
87 struct stream_transform decoder;
88 IMFVideoSampleAllocatorEx *allocator;
89 IMFVideoSampleAllocatorNotify notify_cb;
90 unsigned int id;
91 unsigned int index;
92 enum media_stream_state state;
93 unsigned int flags;
94 unsigned int requests;
95 unsigned int responses;
96 struct source_reader *reader;
99 enum source_reader_async_op
101 SOURCE_READER_ASYNC_READ,
102 SOURCE_READER_ASYNC_SEEK,
103 SOURCE_READER_ASYNC_FLUSH,
104 SOURCE_READER_ASYNC_SAMPLE_READY,
105 SOURCE_READER_ASYNC_SA_READY,
108 struct source_reader_async_command
110 IUnknown IUnknown_iface;
111 LONG refcount;
112 enum source_reader_async_op op;
113 union
115 struct
117 unsigned int flags;
118 unsigned int stream_index;
119 } read;
120 struct
122 GUID format;
123 PROPVARIANT position;
124 } seek;
125 struct
127 unsigned int stream_index;
128 } flush;
129 struct
131 unsigned int stream_index;
132 } sample;
133 struct
135 unsigned int stream_index;
136 } sa;
137 } u;
140 enum source_reader_flags
142 SOURCE_READER_FLUSHING = 0x1,
143 SOURCE_READER_SEEKING = 0x2,
144 SOURCE_READER_SHUTDOWN_ON_RELEASE = 0x4,
145 SOURCE_READER_D3D9_DEVICE_MANAGER = 0x8,
146 SOURCE_READER_DXGI_DEVICE_MANAGER = 0x10,
147 SOURCE_READER_HAS_DEVICE_MANAGER = SOURCE_READER_D3D9_DEVICE_MANAGER | SOURCE_READER_DXGI_DEVICE_MANAGER,
150 struct source_reader
152 IMFSourceReader IMFSourceReader_iface;
153 IMFAsyncCallback source_events_callback;
154 IMFAsyncCallback stream_events_callback;
155 IMFAsyncCallback async_commands_callback;
156 LONG refcount;
157 IMFMediaSource *source;
158 IMFPresentationDescriptor *descriptor;
159 IMFSourceReaderCallback *async_callback;
160 IMFAttributes *attributes;
161 IUnknown *device_manager;
162 unsigned int first_audio_stream_index;
163 unsigned int first_video_stream_index;
164 unsigned int last_read_index;
165 unsigned int stream_count;
166 unsigned int flags;
167 unsigned int queue;
168 enum media_source_state source_state;
169 struct media_stream *streams;
170 struct list responses;
171 CRITICAL_SECTION cs;
172 CONDITION_VARIABLE sample_event;
173 CONDITION_VARIABLE state_event;
176 static inline struct source_reader *impl_from_IMFSourceReader(IMFSourceReader *iface)
178 return CONTAINING_RECORD(iface, struct source_reader, IMFSourceReader_iface);
181 static struct source_reader *impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
183 return CONTAINING_RECORD(iface, struct source_reader, source_events_callback);
186 static struct source_reader *impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
188 return CONTAINING_RECORD(iface, struct source_reader, stream_events_callback);
191 static struct source_reader *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
193 return CONTAINING_RECORD(iface, struct source_reader, async_commands_callback);
196 static struct source_reader_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
198 return CONTAINING_RECORD(iface, struct source_reader_async_command, IUnknown_iface);
201 static struct media_stream *impl_stream_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify *iface)
203 return CONTAINING_RECORD(iface, struct media_stream, notify_cb);
206 static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
208 if (IsEqualIID(riid, &IID_IUnknown))
210 *obj = iface;
211 IUnknown_AddRef(iface);
212 return S_OK;
215 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
216 *obj = NULL;
217 return E_NOINTERFACE;
220 static ULONG WINAPI source_reader_async_command_AddRef(IUnknown *iface)
222 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
223 return InterlockedIncrement(&command->refcount);
226 static ULONG WINAPI source_reader_async_command_Release(IUnknown *iface)
228 struct source_reader_async_command *command = impl_from_async_command_IUnknown(iface);
229 ULONG refcount = InterlockedIncrement(&command->refcount);
231 if (!refcount)
233 if (command->op == SOURCE_READER_ASYNC_SEEK)
234 PropVariantClear(&command->u.seek.position);
235 free(command);
238 return refcount;
241 static const IUnknownVtbl source_reader_async_command_vtbl =
243 source_reader_async_command_QueryInterface,
244 source_reader_async_command_AddRef,
245 source_reader_async_command_Release,
248 static HRESULT source_reader_create_async_op(enum source_reader_async_op op, struct source_reader_async_command **ret)
250 struct source_reader_async_command *command;
252 if (!(command = calloc(1, sizeof(*command))))
253 return E_OUTOFMEMORY;
255 command->IUnknown_iface.lpVtbl = &source_reader_async_command_vtbl;
256 command->op = op;
258 *ret = command;
260 return S_OK;
263 static HRESULT media_event_get_object(IMFMediaEvent *event, REFIID riid, void **obj)
265 PROPVARIANT value;
266 HRESULT hr;
268 PropVariantInit(&value);
269 if (FAILED(hr = IMFMediaEvent_GetValue(event, &value)))
271 WARN("Failed to get event value, hr %#x.\n", hr);
272 return hr;
275 if (value.vt != VT_UNKNOWN || !value.punkVal)
277 WARN("Unexpected value type %d.\n", value.vt);
278 PropVariantClear(&value);
279 return E_UNEXPECTED;
282 hr = IUnknown_QueryInterface(value.punkVal, riid, obj);
283 PropVariantClear(&value);
284 if (FAILED(hr))
286 WARN("Unexpected object type.\n");
287 return hr;
290 return hr;
293 static HRESULT media_stream_get_id(IMFMediaStream *stream, DWORD *id)
295 IMFStreamDescriptor *sd;
296 HRESULT hr;
298 if (SUCCEEDED(hr = IMFMediaStream_GetStreamDescriptor(stream, &sd)))
300 hr = IMFStreamDescriptor_GetStreamIdentifier(sd, id);
301 IMFStreamDescriptor_Release(sd);
304 return hr;
307 static HRESULT WINAPI source_reader_callback_QueryInterface(IMFAsyncCallback *iface,
308 REFIID riid, void **obj)
310 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
312 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
313 IsEqualIID(riid, &IID_IUnknown))
315 *obj = iface;
316 IMFAsyncCallback_AddRef(iface);
317 return S_OK;
320 WARN("Unsupported %s.\n", debugstr_guid(riid));
321 *obj = NULL;
322 return E_NOINTERFACE;
325 static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface)
327 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
328 return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
331 static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface)
333 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
334 return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
337 static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface,
338 DWORD *flags, DWORD *queue)
340 return E_NOTIMPL;
343 static void source_reader_response_ready(struct source_reader *reader, struct stream_response *response)
345 struct source_reader_async_command *command;
346 struct media_stream *stream = &reader->streams[response->stream_index];
347 HRESULT hr;
349 if (!stream->requests || response->sa_pending)
350 return;
352 if (reader->async_callback)
354 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY, &command)))
356 command->u.sample.stream_index = stream->index;
357 if (FAILED(hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface)))
358 WARN("Failed to submit async result, hr %#x.\n", hr);
359 IUnknown_Release(&command->IUnknown_iface);
362 else
363 WakeAllConditionVariable(&reader->sample_event);
365 stream->requests--;
368 static void source_reader_copy_sample_buffer(IMFSample *src, IMFSample *dst)
370 IMFMediaBuffer *buffer;
371 unsigned int flags;
372 LONGLONG time;
373 HRESULT hr;
375 IMFSample_CopyAllItems(src, (IMFAttributes *)dst);
377 IMFSample_SetSampleDuration(dst, 0);
378 IMFSample_SetSampleTime(dst, 0);
379 IMFSample_SetSampleFlags(dst, 0);
381 if (SUCCEEDED(IMFSample_GetSampleDuration(src, &time)))
382 IMFSample_SetSampleDuration(dst, time);
384 if (SUCCEEDED(IMFSample_GetSampleTime(src, &time)))
385 IMFSample_SetSampleTime(dst, time);
387 if (SUCCEEDED(IMFSample_GetSampleFlags(src, &flags)))
388 IMFSample_SetSampleFlags(dst, flags);
390 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src, NULL)))
392 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst, 0, &buffer)))
394 if (FAILED(hr = IMFSample_CopyToBuffer(src, buffer)))
395 WARN("Failed to copy a buffer, hr %#x.\n", hr);
396 IMFMediaBuffer_Release(buffer);
401 static void source_reader_set_sa_response(struct source_reader *reader, struct stream_response *response)
403 struct media_stream *stream = &reader->streams[response->stream_index];
404 IMFSample *sample;
406 if (SUCCEEDED(IMFVideoSampleAllocatorEx_AllocateSample(stream->allocator, &sample)))
408 source_reader_copy_sample_buffer(response->sample, sample);
409 response->sa_pending = 0;
410 IMFSample_Release(response->sample);
411 response->sample = sample;
415 static HRESULT source_reader_queue_response(struct source_reader *reader, struct media_stream *stream, HRESULT status,
416 DWORD stream_flags, LONGLONG timestamp, IMFSample *sample)
418 struct stream_response *response;
420 if (!(response = calloc(1, sizeof(*response))))
421 return E_OUTOFMEMORY;
423 response->status = status;
424 response->stream_index = stream->index;
425 response->stream_flags = stream_flags;
426 response->timestamp = timestamp;
427 response->sample = sample;
428 if (response->sample)
429 IMFSample_AddRef(response->sample);
431 if (response->sample && stream->allocator)
433 response->sa_pending = 1;
434 source_reader_set_sa_response(reader, response);
437 list_add_tail(&reader->responses, &response->entry);
438 stream->responses++;
440 source_reader_response_ready(reader, response);
442 return S_OK;
445 static HRESULT source_reader_request_sample(struct source_reader *reader, struct media_stream *stream)
447 HRESULT hr = S_OK;
449 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
451 if (FAILED(hr = IMFMediaStream_RequestSample(stream->stream, NULL)))
452 WARN("Sample request failed, hr %#x.\n", hr);
453 else
455 stream->flags |= STREAM_FLAG_SAMPLE_REQUESTED;
459 return hr;
462 static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IMFMediaEvent *event)
464 IMFMediaStream *stream;
465 unsigned int i;
466 DWORD id = 0;
467 HRESULT hr;
469 if (FAILED(hr = media_event_get_object(event, &IID_IMFMediaStream, (void **)&stream)))
471 WARN("Failed to get stream object, hr %#x.\n", hr);
472 return hr;
475 TRACE("Got new stream %p.\n", stream);
477 if (FAILED(hr = media_stream_get_id(stream, &id)))
479 WARN("Unidentified stream %p, hr %#x.\n", stream, hr);
480 IMFMediaStream_Release(stream);
481 return hr;
484 EnterCriticalSection(&reader->cs);
486 for (i = 0; i < reader->stream_count; ++i)
488 if (id == reader->streams[i].id)
490 if (!reader->streams[i].stream)
492 reader->streams[i].stream = stream;
493 IMFMediaStream_AddRef(reader->streams[i].stream);
494 if (FAILED(hr = IMFMediaStream_BeginGetEvent(stream, &reader->stream_events_callback,
495 (IUnknown *)stream)))
497 WARN("Failed to subscribe to stream events, hr %#x.\n", hr);
500 if (reader->streams[i].requests)
501 if (FAILED(source_reader_request_sample(reader, &reader->streams[i])))
502 WakeAllConditionVariable(&reader->sample_event);
504 break;
508 if (i == reader->stream_count)
509 WARN("Stream with id %#x was not present in presentation descriptor.\n", id);
511 LeaveCriticalSection(&reader->cs);
513 IMFMediaStream_Release(stream);
515 return hr;
518 static HRESULT source_reader_source_state_handler(struct source_reader *reader, MediaEventType event_type)
520 EnterCriticalSection(&reader->cs);
522 switch (event_type)
524 case MESourceStarted:
525 reader->source_state = SOURCE_STATE_STARTED;
526 reader->flags &= ~SOURCE_READER_SEEKING;
527 break;
528 case MESourceStopped:
529 reader->source_state = SOURCE_STATE_STOPPED;
530 reader->flags &= ~SOURCE_READER_SEEKING;
531 break;
532 case MESourceSeeked:
533 reader->flags &= ~SOURCE_READER_SEEKING;
534 break;
535 default:
536 WARN("Unhandled event %d.\n", event_type);
539 LeaveCriticalSection(&reader->cs);
541 WakeAllConditionVariable(&reader->state_event);
543 return S_OK;
546 static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
548 struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
549 MediaEventType event_type;
550 IMFMediaSource *source;
551 IMFMediaEvent *event;
552 HRESULT hr;
554 TRACE("%p, %p.\n", iface, result);
556 source = (IMFMediaSource *)IMFAsyncResult_GetStateNoAddRef(result);
558 if (FAILED(hr = IMFMediaSource_EndGetEvent(source, result, &event)))
559 return hr;
561 IMFMediaEvent_GetType(event, &event_type);
563 TRACE("Got event %u.\n", event_type);
565 switch (event_type)
567 case MENewStream:
568 hr = source_reader_new_stream_handler(reader, event);
569 break;
570 case MESourceStarted:
571 case MESourcePaused:
572 case MESourceStopped:
573 case MESourceSeeked:
574 hr = source_reader_source_state_handler(reader, event_type);
575 break;
576 case MEBufferingStarted:
577 case MEBufferingStopped:
578 case MEConnectStart:
579 case MEConnectEnd:
580 case MEExtendedType:
581 case MESourceCharacteristicsChanged:
582 case MESourceMetadataChanged:
583 case MEContentProtectionMetadata:
584 case MEDeviceThermalStateChanged:
585 if (reader->async_callback)
586 IMFSourceReaderCallback_OnEvent(reader->async_callback, MF_SOURCE_READER_MEDIASOURCE, event);
587 break;
588 default:
592 if (FAILED(hr))
593 WARN("Failed while handling %d event, hr %#x.\n", event_type, hr);
595 IMFMediaEvent_Release(event);
597 IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
599 return S_OK;
602 static const IMFAsyncCallbackVtbl source_events_callback_vtbl =
604 source_reader_callback_QueryInterface,
605 source_reader_source_events_callback_AddRef,
606 source_reader_source_events_callback_Release,
607 source_reader_callback_GetParameters,
608 source_reader_source_events_callback_Invoke,
611 static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface)
613 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
614 return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
617 static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface)
619 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
620 return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
623 static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, struct media_stream *stream)
625 MFT_OUTPUT_STREAM_INFO stream_info = { 0 };
626 MFT_OUTPUT_DATA_BUFFER out_buffer;
627 unsigned int buffer_size;
628 IMFMediaBuffer *buffer;
629 LONGLONG timestamp;
630 DWORD status;
631 HRESULT hr;
633 if (FAILED(hr = IMFTransform_GetOutputStreamInfo(stream->decoder.transform, 0, &stream_info)))
635 WARN("Failed to get output stream info, hr %#x.\n", hr);
636 return hr;
639 for (;;)
641 memset(&out_buffer, 0, sizeof(out_buffer));
643 if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)))
645 if (FAILED(hr = MFCreateSample(&out_buffer.pSample)))
646 break;
648 buffer_size = max(stream_info.cbSize, stream->decoder.min_buffer_size);
650 if (FAILED(hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info.cbAlignment, &buffer)))
652 IMFSample_Release(out_buffer.pSample);
653 break;
656 IMFSample_AddBuffer(out_buffer.pSample, buffer);
657 IMFMediaBuffer_Release(buffer);
660 if (FAILED(hr = IMFTransform_ProcessOutput(stream->decoder.transform, 0, 1, &out_buffer, &status)))
662 if (out_buffer.pSample)
663 IMFSample_Release(out_buffer.pSample);
664 break;
667 timestamp = 0;
668 if (FAILED(IMFSample_GetSampleTime(out_buffer.pSample, &timestamp)))
669 WARN("Sample time wasn't set.\n");
671 source_reader_queue_response(reader, stream, S_OK /* FIXME */, 0, timestamp, out_buffer.pSample);
672 if (out_buffer.pSample)
673 IMFSample_Release(out_buffer.pSample);
674 if (out_buffer.pEvents)
675 IMFCollection_Release(out_buffer.pEvents);
678 return hr;
681 static HRESULT source_reader_process_sample(struct source_reader *reader, struct media_stream *stream,
682 IMFSample *sample)
684 LONGLONG timestamp;
685 HRESULT hr;
687 if (!stream->decoder.transform)
689 timestamp = 0;
690 if (FAILED(IMFSample_GetSampleTime(sample, &timestamp)))
691 WARN("Sample time wasn't set.\n");
693 return source_reader_queue_response(reader, stream, S_OK, 0, timestamp, sample);
696 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
698 hr = source_reader_pull_stream_samples(reader, stream);
699 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
701 if (FAILED(hr = IMFTransform_ProcessInput(stream->decoder.transform, 0, sample, 0)))
703 WARN("Transform failed to process input, hr %#x.\n", hr);
704 return hr;
707 if ((hr = source_reader_pull_stream_samples(reader, stream)) == MF_E_TRANSFORM_NEED_MORE_INPUT)
708 return S_OK;
710 else
711 WARN("Transform failed to process output, hr %#x.\n", hr);
713 return hr;
716 static HRESULT source_reader_media_sample_handler(struct source_reader *reader, IMFMediaStream *stream,
717 IMFMediaEvent *event)
719 IMFSample *sample;
720 unsigned int i;
721 DWORD id = 0;
722 HRESULT hr;
724 TRACE("Got new sample for stream %p.\n", stream);
726 if (FAILED(hr = media_event_get_object(event, &IID_IMFSample, (void **)&sample)))
728 WARN("Failed to get sample object, hr %#x.\n", hr);
729 return hr;
732 if (FAILED(hr = media_stream_get_id(stream, &id)))
734 WARN("Unidentified stream %p, hr %#x.\n", stream, hr);
735 IMFSample_Release(sample);
736 return hr;
739 EnterCriticalSection(&reader->cs);
741 for (i = 0; i < reader->stream_count; ++i)
743 if (id == reader->streams[i].id)
745 /* FIXME: propagate processing errors? */
747 reader->streams[i].flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
748 hr = source_reader_process_sample(reader, &reader->streams[i], sample);
749 if (reader->streams[i].requests)
750 source_reader_request_sample(reader, &reader->streams[i]);
752 break;
756 if (i == reader->stream_count)
757 WARN("Stream with id %#x was not present in presentation descriptor.\n", id);
759 LeaveCriticalSection(&reader->cs);
761 IMFSample_Release(sample);
763 return hr;
766 static HRESULT source_reader_media_stream_state_handler(struct source_reader *reader, IMFMediaStream *stream,
767 IMFMediaEvent *event)
769 MediaEventType event_type;
770 LONGLONG timestamp;
771 PROPVARIANT value;
772 unsigned int i;
773 HRESULT hr;
774 DWORD id;
776 IMFMediaEvent_GetType(event, &event_type);
778 if (FAILED(hr = media_stream_get_id(stream, &id)))
780 WARN("Unidentified stream %p, hr %#x.\n", stream, hr);
781 return hr;
784 EnterCriticalSection(&reader->cs);
786 for (i = 0; i < reader->stream_count; ++i)
788 struct media_stream *stream = &reader->streams[i];
790 if (id == stream->id)
792 switch (event_type)
794 case MEEndOfStream:
795 stream->state = STREAM_STATE_EOS;
796 stream->flags &= ~STREAM_FLAG_SAMPLE_REQUESTED;
798 if (stream->decoder.transform && SUCCEEDED(IMFTransform_ProcessMessage(stream->decoder.transform,
799 MFT_MESSAGE_COMMAND_DRAIN, 0)))
801 if ((hr = source_reader_pull_stream_samples(reader, stream)) != MF_E_TRANSFORM_NEED_MORE_INPUT)
802 WARN("Failed to pull pending samples, hr %#x.\n", hr);
805 while (stream->requests)
806 source_reader_queue_response(reader, stream, S_OK, MF_SOURCE_READERF_ENDOFSTREAM, 0, NULL);
808 break;
809 case MEStreamSeeked:
810 case MEStreamStarted:
811 stream->state = STREAM_STATE_READY;
812 break;
813 case MEStreamTick:
814 value.vt = VT_EMPTY;
815 hr = SUCCEEDED(IMFMediaEvent_GetValue(event, &value)) && value.vt == VT_I8 ? S_OK : E_UNEXPECTED;
816 timestamp = SUCCEEDED(hr) ? value.hVal.QuadPart : 0;
817 PropVariantClear(&value);
819 source_reader_queue_response(reader, stream, hr, MF_SOURCE_READERF_STREAMTICK, timestamp, NULL);
821 break;
822 default:
826 break;
830 LeaveCriticalSection(&reader->cs);
832 return S_OK;
835 static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
837 struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
838 MediaEventType event_type;
839 IMFMediaStream *stream;
840 IMFMediaEvent *event;
841 HRESULT hr;
843 TRACE("%p, %p.\n", iface, result);
845 stream = (IMFMediaStream *)IMFAsyncResult_GetStateNoAddRef(result);
847 if (FAILED(hr = IMFMediaStream_EndGetEvent(stream, result, &event)))
848 return hr;
850 IMFMediaEvent_GetType(event, &event_type);
852 TRACE("Got event %u.\n", event_type);
854 switch (event_type)
856 case MEMediaSample:
857 hr = source_reader_media_sample_handler(reader, stream, event);
858 break;
859 case MEStreamSeeked:
860 case MEStreamStarted:
861 case MEStreamTick:
862 case MEEndOfStream:
863 hr = source_reader_media_stream_state_handler(reader, stream, event);
864 break;
865 default:
869 if (FAILED(hr))
870 WARN("Failed while handling %d event, hr %#x.\n", event_type, hr);
872 IMFMediaEvent_Release(event);
874 IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
876 return S_OK;
879 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl =
881 source_reader_callback_QueryInterface,
882 source_reader_stream_events_callback_AddRef,
883 source_reader_stream_events_callback_Release,
884 source_reader_callback_GetParameters,
885 source_reader_stream_events_callback_Invoke,
888 static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface)
890 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
891 return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
894 static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface)
896 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
897 return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
900 static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response)
902 struct media_stream *stream;
904 list_remove(&response->entry);
906 if (response->stream_index < reader->stream_count)
908 stream = &reader->streams[response->stream_index];
909 if (stream->responses)
910 --stream->responses;
913 return response;
916 static struct stream_response *media_stream_pop_response(struct source_reader *reader, struct media_stream *stream)
918 struct stream_response *response;
920 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
922 if ((stream && response->stream_index != stream->index) || response->sa_pending)
923 continue;
925 return media_stream_detach_response(reader, response);
928 return NULL;
931 static struct stream_response *media_stream_pick_pending_response(struct source_reader *reader, unsigned int stream)
933 struct stream_response *response;
935 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
937 if (response->stream_index == stream && response->sa_pending)
938 return response;
941 return NULL;
944 static void source_reader_release_response(struct stream_response *response)
946 if (response->sample)
947 IMFSample_Release(response->sample);
948 free(response);
951 static HRESULT source_reader_get_stream_selection(const struct source_reader *reader, DWORD index, BOOL *selected)
953 IMFStreamDescriptor *sd;
955 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, selected, &sd)))
956 return MF_E_INVALIDSTREAMNUMBER;
957 IMFStreamDescriptor_Release(sd);
959 return S_OK;
962 static HRESULT source_reader_start_source(struct source_reader *reader)
964 BOOL selected, selection_changed = FALSE;
965 PROPVARIANT position;
966 HRESULT hr = S_OK;
967 unsigned int i;
969 for (i = 0; i < reader->stream_count; ++i)
971 source_reader_get_stream_selection(reader, i, &selected);
972 if (selected)
973 reader->streams[i].flags |= STREAM_FLAG_SELECTED;
974 else
975 reader->streams[i].flags &= ~STREAM_FLAG_SELECTED;
978 if (reader->source_state == SOURCE_STATE_STARTED)
980 for (i = 0; i < reader->stream_count; ++i)
982 selection_changed = !!(reader->streams[i].flags & STREAM_FLAG_SELECTED) ^
983 !!(reader->streams[i].flags & STREAM_FLAG_PRESENTED);
984 if (selection_changed)
985 break;
989 position.hVal.QuadPart = 0;
990 if (reader->source_state != SOURCE_STATE_STARTED || selection_changed)
992 position.vt = reader->source_state == SOURCE_STATE_STARTED ? VT_EMPTY : VT_I8;
994 /* Update cached stream selection if descriptor was accepted. */
995 if (SUCCEEDED(hr = IMFMediaSource_Start(reader->source, reader->descriptor, &GUID_NULL, &position)))
997 for (i = 0; i < reader->stream_count; ++i)
999 if (reader->streams[i].flags & STREAM_FLAG_SELECTED)
1000 reader->streams[i].flags |= STREAM_FLAG_PRESENTED;
1005 return hr;
1008 static BOOL source_reader_got_response_for_stream(struct source_reader *reader, struct media_stream *stream)
1010 struct stream_response *response;
1012 LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry)
1014 if (response->stream_index == stream->index && !response->sa_pending)
1015 return TRUE;
1018 return FALSE;
1021 static BOOL source_reader_get_read_result(struct source_reader *reader, struct media_stream *stream, DWORD flags,
1022 HRESULT *status, DWORD *stream_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1024 struct stream_response *response = NULL;
1025 BOOL request_sample = FALSE;
1027 if ((response = media_stream_pop_response(reader, stream)))
1029 *status = response->status;
1030 *stream_index = stream->index;
1031 *stream_flags = response->stream_flags;
1032 *timestamp = response->timestamp;
1033 *sample = response->sample;
1034 if (*sample)
1035 IMFSample_AddRef(*sample);
1037 source_reader_release_response(response);
1039 else
1041 *status = S_OK;
1042 *stream_index = stream->index;
1043 *timestamp = 0;
1044 *sample = NULL;
1046 if (stream->state == STREAM_STATE_EOS)
1048 *stream_flags = MF_SOURCE_READERF_ENDOFSTREAM;
1050 else
1052 request_sample = !(flags & MF_SOURCE_READER_CONTROLF_DRAIN);
1053 *stream_flags = 0;
1057 return !request_sample;
1060 static HRESULT source_reader_get_next_selected_stream(struct source_reader *reader, unsigned int *stream_index)
1062 unsigned int i, first_selected = ~0u, requests = ~0u;
1063 BOOL selected, stream_drained;
1065 for (i = (reader->last_read_index + 1) % reader->stream_count; ; i = (i + 1) % reader->stream_count)
1067 stream_drained = reader->streams[i].state == STREAM_STATE_EOS && !reader->streams[i].responses;
1068 selected = SUCCEEDED(source_reader_get_stream_selection(reader, i, &selected)) && selected;
1070 if (selected)
1072 if (first_selected == ~0u)
1073 first_selected = i;
1075 /* Try to balance pending reads. */
1076 if (!stream_drained && reader->streams[i].requests < requests)
1078 requests = reader->streams[i].requests;
1079 *stream_index = i;
1083 if (i == reader->last_read_index)
1084 break;
1087 /* If all selected streams reached EOS, use first selected. */
1088 if (first_selected != ~0u)
1090 if (requests == ~0u)
1091 *stream_index = first_selected;
1092 reader->last_read_index = *stream_index;
1095 return first_selected == ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED : S_OK;
1098 static HRESULT source_reader_get_stream_read_index(struct source_reader *reader, unsigned int index, unsigned int *stream_index)
1100 BOOL selected;
1101 HRESULT hr;
1103 switch (index)
1105 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1106 *stream_index = reader->first_video_stream_index;
1107 break;
1108 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1109 *stream_index = reader->first_audio_stream_index;
1110 break;
1111 case MF_SOURCE_READER_ANY_STREAM:
1112 return source_reader_get_next_selected_stream(reader, stream_index);
1113 default:
1114 *stream_index = index;
1117 /* Can't read from deselected streams. */
1118 if (SUCCEEDED(hr = source_reader_get_stream_selection(reader, *stream_index, &selected)) && !selected)
1119 hr = MF_E_INVALIDREQUEST;
1121 return hr;
1124 static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream)
1126 struct stream_response *ptr, *next;
1128 LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &reader->responses, struct stream_response, entry)
1130 if (stream && stream->index != ptr->stream_index &&
1131 ptr->stream_index != MF_SOURCE_READER_FIRST_VIDEO_STREAM &&
1132 ptr->stream_index != MF_SOURCE_READER_FIRST_AUDIO_STREAM &&
1133 ptr->stream_index != MF_SOURCE_READER_ANY_STREAM)
1135 continue;
1137 media_stream_detach_response(reader, ptr);
1138 source_reader_release_response(ptr);
1142 static void source_reader_flush_stream(struct source_reader *reader, DWORD stream_index)
1144 struct media_stream *stream = &reader->streams[stream_index];
1146 source_reader_release_responses(reader, stream);
1147 if (stream->decoder.transform)
1148 IMFTransform_ProcessMessage(stream->decoder.transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
1149 stream->requests = 0;
1152 static HRESULT source_reader_flush(struct source_reader *reader, unsigned int index)
1154 unsigned int stream_index;
1155 HRESULT hr = S_OK;
1157 if (index == MF_SOURCE_READER_ALL_STREAMS)
1159 for (stream_index = 0; stream_index < reader->stream_count; ++stream_index)
1160 source_reader_flush_stream(reader, stream_index);
1162 else
1164 switch (index)
1166 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1167 stream_index = reader->first_video_stream_index;
1168 break;
1169 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1170 stream_index = reader->first_audio_stream_index;
1171 break;
1172 default:
1173 stream_index = index;
1176 if (stream_index < reader->stream_count)
1177 source_reader_flush_stream(reader, stream_index);
1178 else
1179 hr = MF_E_INVALIDSTREAMNUMBER;
1182 return hr;
1185 static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1187 struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
1188 struct media_stream *stream, stub_stream = { .requests = 1 };
1189 struct source_reader_async_command *command;
1190 struct stream_response *response;
1191 DWORD stream_index, stream_flags;
1192 BOOL report_sample = FALSE;
1193 IMFSample *sample = NULL;
1194 LONGLONG timestamp = 0;
1195 HRESULT hr, status;
1196 IUnknown *state;
1198 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
1199 return hr;
1201 command = impl_from_async_command_IUnknown(state);
1203 switch (command->op)
1205 case SOURCE_READER_ASYNC_READ:
1206 EnterCriticalSection(&reader->cs);
1208 if (SUCCEEDED(hr = source_reader_start_source(reader)))
1210 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, command->u.read.stream_index, &stream_index)))
1212 stream = &reader->streams[stream_index];
1214 if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status,
1215 &stream_index, &stream_flags, &timestamp, &sample)))
1217 stream->requests++;
1218 source_reader_request_sample(reader, stream);
1219 /* FIXME: set error stream/reader state on request failure */
1222 else
1224 stub_stream.index = command->u.read.stream_index;
1225 source_reader_queue_response(reader, &stub_stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL);
1229 LeaveCriticalSection(&reader->cs);
1231 if (report_sample)
1232 IMFSourceReaderCallback_OnReadSample(reader->async_callback, status, stream_index, stream_flags,
1233 timestamp, sample);
1235 if (sample)
1236 IMFSample_Release(sample);
1238 break;
1240 case SOURCE_READER_ASYNC_SEEK:
1242 EnterCriticalSection(&reader->cs);
1243 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, &command->u.seek.format,
1244 &command->u.seek.position)))
1246 reader->flags |= SOURCE_READER_SEEKING;
1248 LeaveCriticalSection(&reader->cs);
1250 break;
1252 case SOURCE_READER_ASYNC_SA_READY:
1254 EnterCriticalSection(&reader->cs);
1255 if ((response = media_stream_pick_pending_response(reader, command->u.sa.stream_index)))
1257 source_reader_set_sa_response(reader, response);
1258 source_reader_response_ready(reader, response);
1260 LeaveCriticalSection(&reader->cs);
1262 break;
1264 case SOURCE_READER_ASYNC_SAMPLE_READY:
1266 EnterCriticalSection(&reader->cs);
1267 response = media_stream_pop_response(reader, NULL);
1268 LeaveCriticalSection(&reader->cs);
1270 if (response)
1272 IMFSourceReaderCallback_OnReadSample(reader->async_callback, response->status, response->stream_index,
1273 response->stream_flags, response->timestamp, response->sample);
1274 source_reader_release_response(response);
1277 break;
1278 case SOURCE_READER_ASYNC_FLUSH:
1279 EnterCriticalSection(&reader->cs);
1280 source_reader_flush(reader, command->u.flush.stream_index);
1281 reader->flags &= ~SOURCE_READER_FLUSHING;
1282 LeaveCriticalSection(&reader->cs);
1284 IMFSourceReaderCallback_OnFlush(reader->async_callback, command->u.flush.stream_index);
1285 break;
1286 default:
1290 IUnknown_Release(state);
1292 return S_OK;
1295 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl =
1297 source_reader_callback_QueryInterface,
1298 source_reader_async_commands_callback_AddRef,
1299 source_reader_async_commands_callback_Release,
1300 source_reader_callback_GetParameters,
1301 source_reader_async_commands_callback_Invoke,
1304 static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReader *iface, REFIID riid, void **out)
1306 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1308 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1310 if(IsEqualGUID(riid, &IID_IUnknown) ||
1311 IsEqualGUID(riid, &IID_IMFSourceReader))
1313 *out = &reader->IMFSourceReader_iface;
1315 else
1317 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
1318 *out = NULL;
1319 return E_NOINTERFACE;
1322 IUnknown_AddRef((IUnknown*)*out);
1323 return S_OK;
1326 static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface)
1328 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1329 ULONG refcount = InterlockedIncrement(&reader->refcount);
1331 TRACE("%p, refcount %u.\n", iface, refcount);
1333 return refcount;
1336 static ULONG WINAPI src_reader_Release(IMFSourceReader *iface)
1338 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1339 ULONG refcount = InterlockedDecrement(&reader->refcount);
1340 unsigned int i;
1342 TRACE("%p, refcount %u.\n", iface, refcount);
1344 if (!refcount)
1346 if (reader->async_callback)
1347 IMFSourceReaderCallback_Release(reader->async_callback);
1348 if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE)
1349 IMFMediaSource_Shutdown(reader->source);
1350 if (reader->descriptor)
1351 IMFPresentationDescriptor_Release(reader->descriptor);
1352 if (reader->attributes)
1353 IMFAttributes_Release(reader->attributes);
1354 IMFMediaSource_Release(reader->source);
1356 for (i = 0; i < reader->stream_count; ++i)
1358 struct media_stream *stream = &reader->streams[i];
1360 if (stream->stream)
1361 IMFMediaStream_Release(stream->stream);
1362 if (stream->current)
1363 IMFMediaType_Release(stream->current);
1364 if (stream->decoder.transform)
1365 IMFTransform_Release(stream->decoder.transform);
1366 if (stream->allocator)
1367 IMFVideoSampleAllocatorEx_Release(stream->allocator);
1369 source_reader_release_responses(reader, NULL);
1370 free(reader->streams);
1371 MFUnlockWorkQueue(reader->queue);
1372 DeleteCriticalSection(&reader->cs);
1373 free(reader);
1376 return refcount;
1379 static HRESULT WINAPI src_reader_GetStreamSelection(IMFSourceReader *iface, DWORD index, BOOL *selected)
1381 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1383 TRACE("%p, %#x, %p.\n", iface, index, selected);
1385 switch (index)
1387 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1388 index = reader->first_video_stream_index;
1389 break;
1390 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1391 index = reader->first_audio_stream_index;
1392 break;
1393 default:
1397 return source_reader_get_stream_selection(reader, index, selected);
1400 static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReader *iface, DWORD index, BOOL selection)
1402 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1403 HRESULT hr = S_OK;
1404 BOOL selection_changed = FALSE, selected;
1405 unsigned int i;
1407 TRACE("%p, %#x, %d.\n", iface, index, selection);
1409 selection = !!selection;
1411 EnterCriticalSection(&reader->cs);
1413 if (index == MF_SOURCE_READER_ALL_STREAMS)
1415 for (i = 0; i < reader->stream_count; ++i)
1417 if (!selection_changed)
1419 source_reader_get_stream_selection(reader, i, &selected);
1420 selection_changed = !!(selected ^ selection);
1423 if (selection)
1424 IMFPresentationDescriptor_SelectStream(reader->descriptor, i);
1425 else
1426 IMFPresentationDescriptor_DeselectStream(reader->descriptor, i);
1429 else
1431 switch (index)
1433 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1434 index = reader->first_video_stream_index;
1435 break;
1436 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1437 index = reader->first_audio_stream_index;
1438 break;
1439 default:
1443 source_reader_get_stream_selection(reader, index, &selected);
1444 selection_changed = !!(selected ^ selection);
1446 if (selection)
1447 hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
1448 else
1449 hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
1452 if (selection_changed)
1453 reader->last_read_index = reader->stream_count - 1;
1455 LeaveCriticalSection(&reader->cs);
1457 return SUCCEEDED(hr) ? S_OK : MF_E_INVALIDSTREAMNUMBER;
1460 static HRESULT source_reader_get_native_media_type(struct source_reader *reader, DWORD index, DWORD type_index,
1461 IMFMediaType **type)
1463 IMFMediaTypeHandler *handler;
1464 IMFStreamDescriptor *sd;
1465 IMFMediaType *src_type;
1466 BOOL selected;
1467 HRESULT hr;
1469 switch (index)
1471 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1472 index = reader->first_video_stream_index;
1473 break;
1474 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1475 index = reader->first_audio_stream_index;
1476 break;
1477 default:
1481 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1482 return MF_E_INVALIDSTREAMNUMBER;
1484 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
1485 IMFStreamDescriptor_Release(sd);
1486 if (FAILED(hr))
1487 return hr;
1489 if (type_index == MF_SOURCE_READER_CURRENT_TYPE_INDEX)
1490 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &src_type);
1491 else
1492 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, type_index, &src_type);
1493 IMFMediaTypeHandler_Release(handler);
1495 if (SUCCEEDED(hr))
1497 if (SUCCEEDED(hr = MFCreateMediaType(type)))
1498 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)*type);
1499 IMFMediaType_Release(src_type);
1502 return hr;
1505 static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReader *iface, DWORD index, DWORD type_index,
1506 IMFMediaType **type)
1508 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1510 TRACE("%p, %#x, %#x, %p.\n", iface, index, type_index, type);
1512 return source_reader_get_native_media_type(reader, index, type_index, type);
1515 static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReader *iface, DWORD index, IMFMediaType **type)
1517 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1518 HRESULT hr;
1520 TRACE("%p, %#x, %p.\n", iface, index, type);
1522 switch (index)
1524 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1525 index = reader->first_video_stream_index;
1526 break;
1527 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1528 index = reader->first_audio_stream_index;
1529 break;
1530 default:
1534 if (index >= reader->stream_count)
1535 return MF_E_INVALIDSTREAMNUMBER;
1537 if (FAILED(hr = MFCreateMediaType(type)))
1538 return hr;
1540 EnterCriticalSection(&reader->cs);
1542 hr = IMFMediaType_CopyAllItems(reader->streams[index].current, (IMFAttributes *)*type);
1544 LeaveCriticalSection(&reader->cs);
1546 return hr;
1549 static HRESULT source_reader_get_source_type_handler(struct source_reader *reader, DWORD index,
1550 IMFMediaTypeHandler **handler)
1552 IMFStreamDescriptor *sd;
1553 BOOL selected;
1554 HRESULT hr;
1556 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
1557 return hr;
1559 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, handler);
1560 IMFStreamDescriptor_Release(sd);
1562 return hr;
1565 static HRESULT source_reader_set_compatible_media_type(struct source_reader *reader, DWORD index, IMFMediaType *type)
1567 IMFMediaTypeHandler *type_handler;
1568 IMFMediaType *native_type;
1569 BOOL type_set = FALSE;
1570 unsigned int i = 0;
1571 DWORD flags;
1572 HRESULT hr;
1574 if (FAILED(hr = IMFMediaType_IsEqual(type, reader->streams[index].current, &flags)))
1575 return hr;
1577 if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES))
1578 return MF_E_INVALIDMEDIATYPE;
1580 /* No need for a decoder or type change. */
1581 if (flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)
1582 return S_OK;
1584 if (FAILED(hr = source_reader_get_source_type_handler(reader, index, &type_handler)))
1585 return hr;
1587 while (!type_set && IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, i++, &native_type) == S_OK)
1589 static const DWORD compare_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_DATA;
1591 if (SUCCEEDED(IMFMediaType_IsEqual(native_type, type, &flags)) && (flags & compare_flags) == compare_flags)
1593 if ((type_set = SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler, native_type))))
1594 IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)reader->streams[index].current);
1597 IMFMediaType_Release(native_type);
1600 IMFMediaTypeHandler_Release(type_handler);
1602 return type_set ? S_OK : S_FALSE;
1605 static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index)
1607 struct media_stream *stream = &reader->streams[index];
1608 IMFVideoSampleAllocatorCallback *callback;
1609 GUID major = { 0 };
1610 HRESULT hr;
1612 IMFMediaType_GetMajorType(stream->current, &major);
1613 if (!IsEqualGUID(&major, &MFMediaType_Video))
1614 return S_OK;
1616 if (!(reader->flags & SOURCE_READER_HAS_DEVICE_MANAGER))
1617 return S_OK;
1619 if (!stream->allocator)
1621 if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&stream->allocator)))
1623 WARN("Failed to create sample allocator, hr %#x.\n", hr);
1624 return hr;
1628 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream->allocator);
1629 if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(stream->allocator, reader->device_manager)))
1631 WARN("Failed to set device manager, hr %#x.\n", hr);
1632 return hr;
1635 if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8, NULL, stream->current)))
1636 WARN("Failed to initialize sample allocator, hr %#x.\n", hr);
1638 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream->allocator, &IID_IMFVideoSampleAllocatorCallback, (void **)&callback)))
1640 if (FAILED(hr = IMFVideoSampleAllocatorCallback_SetCallback(callback, &stream->notify_cb)))
1641 WARN("Failed to set allocator callback, hr %#x.\n", hr);
1642 IMFVideoSampleAllocatorCallback_Release(callback);
1645 return hr;
1648 static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWORD index, const CLSID *clsid,
1649 IMFMediaType *input_type, IMFMediaType *output_type)
1651 IMFMediaTypeHandler *type_handler;
1652 unsigned int block_alignment = 0;
1653 IMFTransform *transform = NULL;
1654 IMFMediaType *type = NULL;
1655 GUID major = { 0 };
1656 DWORD flags;
1657 HRESULT hr;
1658 int i = 0;
1660 if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform)))
1662 WARN("Failed to create transform object, hr %#x.\n", hr);
1663 return hr;
1666 if (FAILED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)))
1668 WARN("Failed to set decoder input type, hr %#x.\n", hr);
1669 IMFTransform_Release(transform);
1670 return hr;
1673 /* Find the relevant output type. */
1674 while (IMFTransform_GetOutputAvailableType(transform, 0, i++, &type) == S_OK)
1676 flags = 0;
1678 if (SUCCEEDED(IMFMediaType_IsEqual(type, output_type, &flags)))
1680 if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
1682 if (SUCCEEDED(IMFTransform_SetOutputType(transform, 0, type, 0)))
1684 if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler)))
1686 IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type);
1687 IMFMediaTypeHandler_Release(type_handler);
1690 if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)reader->streams[index].current)))
1691 WARN("Failed to copy attributes, hr %#x.\n", hr);
1692 if (SUCCEEDED(IMFMediaType_GetMajorType(type, &major)) && IsEqualGUID(&major, &MFMediaType_Audio))
1693 IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment);
1694 IMFMediaType_Release(type);
1696 if (reader->streams[index].decoder.transform)
1697 IMFTransform_Release(reader->streams[index].decoder.transform);
1699 reader->streams[index].decoder.transform = transform;
1700 reader->streams[index].decoder.min_buffer_size = block_alignment;
1702 return S_OK;
1707 IMFMediaType_Release(type);
1710 WARN("Failed to find suitable decoder output type.\n");
1712 IMFTransform_Release(transform);
1714 return MF_E_TOPO_CODEC_NOT_FOUND;
1717 static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type)
1719 MFT_REGISTER_TYPE_INFO in_type, out_type;
1720 CLSID *clsids, mft_clsid, category;
1721 unsigned int i = 0, count;
1722 IMFMediaType *input_type;
1723 HRESULT hr;
1725 /* TODO: should we check if the source type is compressed? */
1727 if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType)))
1728 return hr;
1730 if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video))
1732 category = MFT_CATEGORY_VIDEO_DECODER;
1734 else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio))
1736 category = MFT_CATEGORY_AUDIO_DECODER;
1738 else
1740 WARN("Unhandled major type %s.\n", debugstr_guid(&out_type.guidMajorType));
1741 return MF_E_TOPO_CODEC_NOT_FOUND;
1744 if (FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype)))
1745 return hr;
1747 in_type.guidMajorType = out_type.guidMajorType;
1749 while (source_reader_get_native_media_type(reader, index, i++, &input_type) == S_OK)
1751 if (SUCCEEDED(IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype)))
1753 count = 0;
1754 if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &clsids, &count)) && count)
1756 mft_clsid = clsids[0];
1757 CoTaskMemFree(clsids);
1759 /* TODO: Should we iterate over all of them? */
1760 if (SUCCEEDED(source_reader_configure_decoder(reader, index, &mft_clsid, input_type, output_type)))
1762 IMFMediaType_Release(input_type);
1763 return S_OK;
1769 IMFMediaType_Release(input_type);
1772 return MF_E_TOPO_CODEC_NOT_FOUND;
1775 static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWORD index, DWORD *reserved,
1776 IMFMediaType *type)
1778 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1779 HRESULT hr;
1781 TRACE("%p, %#x, %p, %p.\n", iface, index, reserved, type);
1783 switch (index)
1785 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1786 index = reader->first_video_stream_index;
1787 break;
1788 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1789 index = reader->first_audio_stream_index;
1790 break;
1791 default:
1795 if (index >= reader->stream_count)
1796 return MF_E_INVALIDSTREAMNUMBER;
1798 /* FIXME: setting the output type while streaming should trigger a flush */
1800 EnterCriticalSection(&reader->cs);
1802 hr = source_reader_set_compatible_media_type(reader, index, type);
1803 if (hr == S_FALSE)
1804 hr = source_reader_create_decoder_for_stream(reader, index, type);
1805 if (SUCCEEDED(hr))
1806 hr = source_reader_setup_sample_allocator(reader, index);
1808 LeaveCriticalSection(&reader->cs);
1810 return hr;
1813 static HRESULT WINAPI src_reader_SetCurrentPosition(IMFSourceReader *iface, REFGUID format, REFPROPVARIANT position)
1815 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1816 struct source_reader_async_command *command;
1817 unsigned int i, flags;
1818 HRESULT hr;
1820 TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), position);
1822 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
1823 return hr;
1825 if (!(flags & MFMEDIASOURCE_CAN_SEEK))
1826 return MF_E_INVALIDREQUEST;
1828 EnterCriticalSection(&reader->cs);
1830 /* Check if we got pending requests. */
1831 for (i = 0; i < reader->stream_count; ++i)
1833 if (reader->streams[i].requests)
1835 hr = MF_E_INVALIDREQUEST;
1836 break;
1840 if (SUCCEEDED(hr))
1842 if (reader->async_callback)
1844 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK, &command)))
1846 command->u.seek.format = *format;
1847 PropVariantCopy(&command->u.seek.position, position);
1849 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
1850 IUnknown_Release(&command->IUnknown_iface);
1853 else
1855 if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, format, position)))
1857 reader->flags |= SOURCE_READER_SEEKING;
1858 while (reader->flags & SOURCE_READER_SEEKING)
1860 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
1866 LeaveCriticalSection(&reader->cs);
1868 return hr;
1871 static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD index, DWORD flags, DWORD *actual_index,
1872 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1874 unsigned int actual_index_tmp;
1875 struct media_stream *stream;
1876 LONGLONG timestamp_tmp;
1877 DWORD stream_index;
1878 HRESULT hr = S_OK;
1880 if (!stream_flags || !sample)
1881 return E_POINTER;
1883 *sample = NULL;
1885 if (!timestamp)
1886 timestamp = &timestamp_tmp;
1888 if (!actual_index)
1889 actual_index = &actual_index_tmp;
1891 if (SUCCEEDED(hr = source_reader_start_source(reader)))
1893 if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, index, &stream_index)))
1895 *actual_index = stream_index;
1897 stream = &reader->streams[stream_index];
1899 if (!source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
1900 timestamp, sample))
1902 while (!source_reader_got_response_for_stream(reader, stream) && stream->state != STREAM_STATE_EOS)
1904 stream->requests++;
1905 if (FAILED(hr = source_reader_request_sample(reader, stream)))
1906 WARN("Failed to request a sample, hr %#x.\n", hr);
1907 if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
1909 *stream_flags = MF_SOURCE_READERF_ERROR;
1910 *timestamp = 0;
1911 break;
1913 SleepConditionVariableCS(&reader->sample_event, &reader->cs, INFINITE);
1915 if (SUCCEEDED(hr))
1916 source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
1917 timestamp, sample);
1920 else
1922 *actual_index = index;
1923 *stream_flags = MF_SOURCE_READERF_ERROR;
1924 *timestamp = 0;
1928 TRACE("Stream %u, got sample %p, flags %#x.\n", *actual_index, *sample, *stream_flags);
1930 return hr;
1933 static HRESULT source_reader_read_sample_async(struct source_reader *reader, unsigned int index, unsigned int flags,
1934 unsigned int *actual_index, unsigned int *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1936 struct source_reader_async_command *command;
1937 HRESULT hr;
1939 if (actual_index || stream_flags || timestamp || sample)
1940 return E_INVALIDARG;
1942 if (reader->flags & SOURCE_READER_FLUSHING)
1943 hr = MF_E_NOTACCEPTING;
1944 else
1946 if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_READ, &command)))
1948 command->u.read.stream_index = index;
1949 command->u.read.flags = flags;
1951 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
1952 IUnknown_Release(&command->IUnknown_iface);
1956 return hr;
1959 static HRESULT WINAPI src_reader_ReadSample(IMFSourceReader *iface, DWORD index, DWORD flags, DWORD *actual_index,
1960 DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample)
1962 struct source_reader *reader = impl_from_IMFSourceReader(iface);
1963 HRESULT hr;
1965 TRACE("%p, %#x, %#x, %p, %p, %p, %p\n", iface, index, flags, actual_index, stream_flags, timestamp, sample);
1967 EnterCriticalSection(&reader->cs);
1969 while (reader->flags & SOURCE_READER_SEEKING)
1971 SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
1974 if (reader->async_callback)
1975 hr = source_reader_read_sample_async(reader, index, flags, actual_index, stream_flags, timestamp, sample);
1976 else
1977 hr = source_reader_read_sample(reader, index, flags, actual_index, stream_flags, timestamp, sample);
1979 LeaveCriticalSection(&reader->cs);
1981 return hr;
1984 static HRESULT source_reader_flush_async(struct source_reader *reader, unsigned int index)
1986 struct source_reader_async_command *command;
1987 unsigned int stream_index;
1988 HRESULT hr;
1990 if (reader->flags & SOURCE_READER_FLUSHING)
1991 return MF_E_INVALIDREQUEST;
1993 switch (index)
1995 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
1996 stream_index = reader->first_video_stream_index;
1997 break;
1998 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
1999 stream_index = reader->first_audio_stream_index;
2000 break;
2001 default:
2002 stream_index = index;
2005 reader->flags |= SOURCE_READER_FLUSHING;
2007 if (stream_index != MF_SOURCE_READER_ALL_STREAMS && stream_index >= reader->stream_count)
2008 return MF_E_INVALIDSTREAMNUMBER;
2010 if (FAILED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH, &command)))
2011 return hr;
2013 command->u.flush.stream_index = stream_index;
2015 hr = MFPutWorkItem(reader->queue, &reader->async_commands_callback, &command->IUnknown_iface);
2016 IUnknown_Release(&command->IUnknown_iface);
2018 return hr;
2021 static HRESULT WINAPI src_reader_Flush(IMFSourceReader *iface, DWORD index)
2023 struct source_reader *reader = impl_from_IMFSourceReader(iface);
2024 HRESULT hr;
2026 TRACE("%p, %#x.\n", iface, index);
2028 EnterCriticalSection(&reader->cs);
2030 if (reader->async_callback)
2031 hr = source_reader_flush_async(reader, index);
2032 else
2033 hr = source_reader_flush(reader, index);
2035 LeaveCriticalSection(&reader->cs);
2037 return hr;
2040 static HRESULT WINAPI src_reader_GetServiceForStream(IMFSourceReader *iface, DWORD index, REFGUID service,
2041 REFIID riid, void **object)
2043 struct source_reader *reader = impl_from_IMFSourceReader(iface);
2044 IUnknown *obj = NULL;
2045 HRESULT hr = S_OK;
2047 TRACE("%p, %#x, %s, %s, %p\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object);
2049 EnterCriticalSection(&reader->cs);
2051 switch (index)
2053 case MF_SOURCE_READER_MEDIASOURCE:
2054 obj = (IUnknown *)reader->source;
2055 break;
2056 default:
2057 if (index == MF_SOURCE_READER_FIRST_VIDEO_STREAM)
2058 index = reader->first_video_stream_index;
2059 else if (index == MF_SOURCE_READER_FIRST_AUDIO_STREAM)
2060 index = reader->first_audio_stream_index;
2062 if (index >= reader->stream_count)
2063 hr = MF_E_INVALIDSTREAMNUMBER;
2064 else
2066 obj = (IUnknown *)reader->streams[index].decoder.transform;
2067 if (!obj) hr = E_NOINTERFACE;
2069 break;
2072 if (obj)
2073 IUnknown_AddRef(obj);
2075 LeaveCriticalSection(&reader->cs);
2077 if (obj)
2079 if (IsEqualGUID(service, &GUID_NULL))
2081 hr = IUnknown_QueryInterface(obj, riid, object);
2083 else
2085 IMFGetService *gs;
2087 hr = IUnknown_QueryInterface(obj, &IID_IMFGetService, (void **)&gs);
2088 if (SUCCEEDED(hr))
2090 hr = IMFGetService_GetService(gs, service, riid, object);
2091 IMFGetService_Release(gs);
2096 if (obj)
2097 IUnknown_Release(obj);
2099 return hr;
2102 static HRESULT WINAPI src_reader_GetPresentationAttribute(IMFSourceReader *iface, DWORD index,
2103 REFGUID guid, PROPVARIANT *value)
2105 struct source_reader *reader = impl_from_IMFSourceReader(iface);
2106 IMFStreamDescriptor *sd;
2107 BOOL selected;
2108 HRESULT hr;
2110 TRACE("%p, %#x, %s, %p.\n", iface, index, debugstr_guid(guid), value);
2112 switch (index)
2114 case MF_SOURCE_READER_MEDIASOURCE:
2115 if (IsEqualGUID(guid, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS))
2117 DWORD flags;
2119 if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
2120 return hr;
2122 value->vt = VT_UI4;
2123 value->ulVal = flags;
2124 return S_OK;
2126 else
2128 return IMFPresentationDescriptor_GetItem(reader->descriptor, guid, value);
2130 break;
2131 case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
2132 index = reader->first_video_stream_index;
2133 break;
2134 case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
2135 index = reader->first_audio_stream_index;
2136 break;
2137 default:
2141 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
2142 return hr;
2144 hr = IMFStreamDescriptor_GetItem(sd, guid, value);
2145 IMFStreamDescriptor_Release(sd);
2147 return hr;
2150 static const IMFSourceReaderVtbl srcreader_vtbl =
2152 src_reader_QueryInterface,
2153 src_reader_AddRef,
2154 src_reader_Release,
2155 src_reader_GetStreamSelection,
2156 src_reader_SetStreamSelection,
2157 src_reader_GetNativeMediaType,
2158 src_reader_GetCurrentMediaType,
2159 src_reader_SetCurrentMediaType,
2160 src_reader_SetCurrentPosition,
2161 src_reader_ReadSample,
2162 src_reader_Flush,
2163 src_reader_GetServiceForStream,
2164 src_reader_GetPresentationAttribute
2167 static DWORD reader_get_first_stream_index(IMFPresentationDescriptor *descriptor, const GUID *major)
2169 unsigned int count, i;
2170 BOOL selected;
2171 HRESULT hr;
2172 GUID guid;
2174 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count)))
2175 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2177 for (i = 0; i < count; ++i)
2179 IMFMediaTypeHandler *handler;
2180 IMFStreamDescriptor *sd;
2182 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i, &selected, &sd)))
2184 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2185 IMFStreamDescriptor_Release(sd);
2186 if (SUCCEEDED(hr))
2188 hr = IMFMediaTypeHandler_GetMajorType(handler, &guid);
2189 IMFMediaTypeHandler_Release(handler);
2190 if (FAILED(hr))
2192 WARN("Failed to get stream major type, hr %#x.\n", hr);
2193 continue;
2196 if (IsEqualGUID(&guid, major))
2198 return i;
2204 return MF_SOURCE_READER_INVALID_STREAM_INDEX;
2207 static HRESULT WINAPI stream_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify *iface,
2208 REFIID riid, void **obj)
2210 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorNotify) ||
2211 IsEqualIID(riid, &IID_IUnknown))
2213 *obj = iface;
2214 IMFVideoSampleAllocatorNotify_AddRef(iface);
2215 return S_OK;
2218 *obj = NULL;
2219 return E_NOINTERFACE;
2222 static ULONG WINAPI stream_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify *iface)
2224 return 2;
2227 static ULONG WINAPI stream_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify *iface)
2229 return 1;
2232 static HRESULT WINAPI stream_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify *iface)
2234 struct media_stream *stream = impl_stream_from_IMFVideoSampleAllocatorNotify(iface);
2235 struct source_reader_async_command *command;
2237 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SA_READY, &command)))
2239 command->u.sa.stream_index = stream->index;
2240 MFPutWorkItem(stream->reader->queue, &stream->reader->async_commands_callback, &command->IUnknown_iface);
2241 IUnknown_Release(&command->IUnknown_iface);
2244 return S_OK;
2247 static const IMFVideoSampleAllocatorNotifyVtbl stream_sample_allocator_cb_vtbl =
2249 stream_sample_allocator_cb_QueryInterface,
2250 stream_sample_allocator_cb_AddRef,
2251 stream_sample_allocator_cb_Release,
2252 stream_sample_allocator_cb_NotifyRelease,
2255 static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttributes *attributes,
2256 BOOL shutdown_on_release, REFIID riid, void **out)
2258 struct source_reader *object;
2259 unsigned int i;
2260 HRESULT hr;
2262 object = calloc(1, sizeof(*object));
2263 if (!object)
2264 return E_OUTOFMEMORY;
2266 object->IMFSourceReader_iface.lpVtbl = &srcreader_vtbl;
2267 object->source_events_callback.lpVtbl = &source_events_callback_vtbl;
2268 object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl;
2269 object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl;
2270 object->refcount = 1;
2271 list_init(&object->responses);
2272 if (shutdown_on_release)
2273 object->flags |= SOURCE_READER_SHUTDOWN_ON_RELEASE;
2274 object->source = source;
2275 IMFMediaSource_AddRef(object->source);
2276 InitializeCriticalSection(&object->cs);
2277 InitializeConditionVariable(&object->sample_event);
2278 InitializeConditionVariable(&object->state_event);
2280 if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor)))
2281 goto failed;
2283 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(object->descriptor, &object->stream_count)))
2284 goto failed;
2286 if (!(object->streams = calloc(object->stream_count, sizeof(*object->streams))))
2288 hr = E_OUTOFMEMORY;
2289 goto failed;
2292 /* Set initial current media types. */
2293 for (i = 0; i < object->stream_count; ++i)
2295 IMFMediaTypeHandler *handler;
2296 IMFStreamDescriptor *sd;
2297 IMFMediaType *src_type;
2298 BOOL selected;
2300 if (FAILED(hr = MFCreateMediaType(&object->streams[i].current)))
2301 break;
2303 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(object->descriptor, i, &selected, &sd)))
2304 break;
2306 if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(sd, &object->streams[i].id)))
2307 WARN("Failed to get stream identifier, hr %#x.\n", hr);
2309 hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler);
2310 IMFStreamDescriptor_Release(sd);
2311 if (FAILED(hr))
2312 break;
2314 hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, 0, &src_type);
2315 IMFMediaTypeHandler_Release(handler);
2316 if (FAILED(hr))
2317 break;
2319 hr = IMFMediaType_CopyAllItems(src_type, (IMFAttributes *)object->streams[i].current);
2320 IMFMediaType_Release(src_type);
2321 if (FAILED(hr))
2322 break;
2324 object->streams[i].notify_cb.lpVtbl = &stream_sample_allocator_cb_vtbl;
2325 object->streams[i].reader = object;
2326 object->streams[i].index = i;
2329 if (FAILED(hr))
2330 goto failed;
2332 /* At least one major type has to be set. */
2333 object->first_audio_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Audio);
2334 object->first_video_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Video);
2335 object->last_read_index = object->stream_count - 1;
2337 if (object->first_audio_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX &&
2338 object->first_video_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX)
2340 hr = MF_E_ATTRIBUTENOTFOUND;
2343 if (FAILED(hr = IMFMediaSource_BeginGetEvent(object->source, &object->source_events_callback,
2344 (IUnknown *)object->source)))
2346 goto failed;
2349 if (attributes)
2351 object->attributes = attributes;
2352 IMFAttributes_AddRef(object->attributes);
2354 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_ASYNC_CALLBACK, &IID_IMFSourceReaderCallback,
2355 (void **)&object->async_callback);
2356 if (object->async_callback)
2357 TRACE("Using async callback %p.\n", object->async_callback);
2359 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_D3D_MANAGER, &IID_IUnknown, (void **)&object->device_manager);
2360 if (object->device_manager)
2362 IUnknown *unk = NULL;
2364 if (SUCCEEDED(IUnknown_QueryInterface(object->device_manager, &IID_IMFDXGIDeviceManager, (void **)&unk)))
2365 object->flags |= SOURCE_READER_DXGI_DEVICE_MANAGER;
2366 else if (SUCCEEDED(IUnknown_QueryInterface(object->device_manager, &IID_IDirect3DDeviceManager9, (void **)&unk)))
2367 object->flags |= SOURCE_READER_D3D9_DEVICE_MANAGER;
2369 if (!(object->flags & (SOURCE_READER_HAS_DEVICE_MANAGER)))
2371 WARN("Unknown device manager.\n");
2372 IUnknown_Release(object->device_manager);
2373 object->device_manager = NULL;
2376 if (unk)
2377 IUnknown_Release(unk);
2381 if (FAILED(hr = MFLockSharedWorkQueue(L"", 0, NULL, &object->queue)))
2382 WARN("Failed to acquired shared queue, hr %#x.\n", hr);
2384 if (SUCCEEDED(hr))
2385 hr = IMFSourceReader_QueryInterface(&object->IMFSourceReader_iface, riid, out);
2387 failed:
2388 IMFSourceReader_Release(&object->IMFSourceReader_iface);
2389 return hr;
2392 static HRESULT bytestream_get_url_hint(IMFByteStream *stream, WCHAR const **url)
2394 static const unsigned char asfmagic[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c};
2395 static const unsigned char wavmagic[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '};
2396 static const unsigned char wavmask[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
2397 static const unsigned char isommagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00};
2398 static const unsigned char mp42magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00};
2399 static const unsigned char mp4mask[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00};
2400 static const struct stream_content_url_hint
2402 const unsigned char *magic;
2403 const WCHAR *url;
2404 const unsigned char *mask;
2406 url_hints[] =
2408 { asfmagic, L".asf" },
2409 { wavmagic, L".wav", wavmask },
2410 { isommagic, L".mp4", mp4mask },
2411 { mp42magic, L".mp4", mp4mask },
2413 unsigned char buffer[4 * sizeof(unsigned int)], pattern[4 * sizeof(unsigned int)];
2414 unsigned int i, j, length = 0, caps = 0;
2415 IMFAttributes *attributes;
2416 QWORD position;
2417 HRESULT hr;
2419 *url = NULL;
2421 if (SUCCEEDED(IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes)))
2423 IMFAttributes_GetStringLength(attributes, &MF_BYTESTREAM_CONTENT_TYPE, &length);
2424 IMFAttributes_Release(attributes);
2427 if (length)
2428 return S_OK;
2430 if (FAILED(hr = IMFByteStream_GetCapabilities(stream, &caps)))
2431 return hr;
2433 if (!(caps & MFBYTESTREAM_IS_SEEKABLE))
2434 return S_OK;
2436 if (FAILED(hr = IMFByteStream_GetCurrentPosition(stream, &position)))
2437 return hr;
2439 hr = IMFByteStream_Read(stream, buffer, sizeof(buffer), &length);
2440 IMFByteStream_SetCurrentPosition(stream, position);
2441 if (FAILED(hr))
2442 return hr;
2444 if (length < sizeof(buffer))
2445 return S_OK;
2447 for (i = 0; i < ARRAY_SIZE(url_hints); ++i)
2449 memcpy(pattern, buffer, sizeof(buffer));
2450 if (url_hints[i].mask)
2452 unsigned int *mask = (unsigned int *)url_hints[i].mask;
2453 unsigned int *data = (unsigned int *)pattern;
2455 for (j = 0; j < sizeof(buffer) / sizeof(unsigned int); ++j)
2456 data[j] &= mask[j];
2459 if (!memcmp(pattern, url_hints[i].magic, sizeof(pattern)))
2461 *url = url_hints[i].url;
2462 break;
2466 if (*url)
2467 TRACE("Stream type guessed as %s from %s.\n", debugstr_w(*url), debugstr_an((char *)buffer, length));
2468 else
2469 WARN("Unrecognized content type %s.\n", debugstr_an((char *)buffer, length));
2471 return S_OK;
2474 static HRESULT create_source_reader_from_stream(IMFByteStream *stream, IMFAttributes *attributes,
2475 REFIID riid, void **out)
2477 IPropertyStore *props = NULL;
2478 IMFSourceResolver *resolver;
2479 MF_OBJECT_TYPE obj_type;
2480 IMFMediaSource *source;
2481 const WCHAR *url;
2482 HRESULT hr;
2484 /* If stream does not have content type set, try to guess from starting byte sequence. */
2485 if (FAILED(hr = bytestream_get_url_hint(stream, &url)))
2486 return hr;
2488 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2489 return hr;
2491 if (attributes)
2492 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2493 (void **)&props);
2495 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, url, MF_RESOLUTION_MEDIASOURCE, props,
2496 &obj_type, (IUnknown **)&source);
2497 IMFSourceResolver_Release(resolver);
2498 if (props)
2499 IPropertyStore_Release(props);
2500 if (FAILED(hr))
2501 return hr;
2503 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2504 IMFMediaSource_Release(source);
2505 return hr;
2508 static HRESULT create_source_reader_from_url(const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2510 IPropertyStore *props = NULL;
2511 IMFSourceResolver *resolver;
2512 IUnknown *object = NULL;
2513 MF_OBJECT_TYPE obj_type;
2514 IMFMediaSource *source;
2515 HRESULT hr;
2517 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
2518 return hr;
2520 if (attributes)
2521 IMFAttributes_GetUnknown(attributes, &MF_SOURCE_READER_MEDIASOURCE_CONFIG, &IID_IPropertyStore,
2522 (void **)&props);
2524 hr = IMFSourceResolver_CreateObjectFromURL(resolver, url, MF_RESOLUTION_MEDIASOURCE, props, &obj_type,
2525 &object);
2526 if (SUCCEEDED(hr))
2528 switch (obj_type)
2530 case MF_OBJECT_BYTESTREAM:
2531 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, (IMFByteStream *)object, NULL,
2532 MF_RESOLUTION_MEDIASOURCE, props, &obj_type, (IUnknown **)&source);
2533 break;
2534 case MF_OBJECT_MEDIASOURCE:
2535 source = (IMFMediaSource *)object;
2536 IMFMediaSource_AddRef(source);
2537 break;
2538 default:
2539 WARN("Unknown object type %d.\n", obj_type);
2540 hr = E_UNEXPECTED;
2542 IUnknown_Release(object);
2545 IMFSourceResolver_Release(resolver);
2546 if (props)
2547 IPropertyStore_Release(props);
2548 if (FAILED(hr))
2549 return hr;
2551 hr = create_source_reader_from_source(source, attributes, TRUE, riid, out);
2552 IMFMediaSource_Release(source);
2553 return hr;
2556 static HRESULT create_source_reader_from_object(IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2558 IMFMediaSource *source = NULL;
2559 IMFByteStream *stream = NULL;
2560 HRESULT hr;
2562 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSource, (void **)&source);
2563 if (FAILED(hr))
2564 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2566 if (source)
2568 UINT32 disconnect = 0;
2570 if (attributes)
2571 IMFAttributes_GetUINT32(attributes, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN, &disconnect);
2572 hr = create_source_reader_from_source(source, attributes, !disconnect, riid, out);
2574 else if (stream)
2575 hr = create_source_reader_from_stream(stream, attributes, riid, out);
2577 if (source)
2578 IMFMediaSource_Release(source);
2579 if (stream)
2580 IMFByteStream_Release(stream);
2582 return hr;
2585 /***********************************************************************
2586 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2588 HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes,
2589 IMFSourceReader **reader)
2591 TRACE("%p, %p, %p.\n", stream, attributes, reader);
2593 return create_source_reader_from_object((IUnknown *)stream, attributes, &IID_IMFSourceReader, (void **)reader);
2596 /***********************************************************************
2597 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2599 HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes,
2600 IMFSourceReader **reader)
2602 TRACE("%p, %p, %p.\n", source, attributes, reader);
2604 return create_source_reader_from_object((IUnknown *)source, attributes, &IID_IMFSourceReader, (void **)reader);
2607 /***********************************************************************
2608 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2610 HRESULT WINAPI MFCreateSourceReaderFromURL(const WCHAR *url, IMFAttributes *attributes, IMFSourceReader **reader)
2612 TRACE("%s, %p, %p.\n", debugstr_w(url), attributes, reader);
2614 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, (void **)reader);
2617 static HRESULT WINAPI readwrite_factory_QueryInterface(IMFReadWriteClassFactory *iface, REFIID riid, void **out)
2619 if (IsEqualIID(riid, &IID_IMFReadWriteClassFactory) ||
2620 IsEqualIID(riid, &IID_IUnknown))
2622 *out = iface;
2623 IMFReadWriteClassFactory_AddRef(iface);
2624 return S_OK;
2627 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
2628 *out = NULL;
2629 return E_NOINTERFACE;
2632 static ULONG WINAPI readwrite_factory_AddRef(IMFReadWriteClassFactory *iface)
2634 return 2;
2637 static ULONG WINAPI readwrite_factory_Release(IMFReadWriteClassFactory *iface)
2639 return 1;
2642 static HRESULT WINAPI readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2643 const WCHAR *url, IMFAttributes *attributes, REFIID riid, void **out)
2645 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid), debugstr_w(url), attributes, debugstr_guid(riid), out);
2647 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2649 return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, out);
2652 FIXME("Unsupported %s.\n", debugstr_guid(clsid));
2654 return E_NOTIMPL;
2657 static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory *iface, REFCLSID clsid,
2658 IUnknown *unk, IMFAttributes *attributes, REFIID riid, void **out)
2660 HRESULT hr;
2662 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid), unk, attributes, debugstr_guid(riid), out);
2664 if (IsEqualGUID(clsid, &CLSID_MFSourceReader))
2666 return create_source_reader_from_object(unk, attributes, riid, out);
2668 else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter))
2670 IMFByteStream *stream = NULL;
2671 IMFMediaSink *sink = NULL;
2673 hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream);
2674 if (FAILED(hr))
2675 hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSink, (void **)&sink);
2677 if (stream)
2678 hr = create_sink_writer_from_stream(stream, attributes, riid, out);
2679 else if (sink)
2680 hr = create_sink_writer_from_sink(sink, attributes, riid, out);
2682 if (sink)
2683 IMFMediaSink_Release(sink);
2684 if (stream)
2685 IMFByteStream_Release(stream);
2687 return hr;
2689 else
2691 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2692 *out = NULL;
2693 return E_FAIL;
2697 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl =
2699 readwrite_factory_QueryInterface,
2700 readwrite_factory_AddRef,
2701 readwrite_factory_Release,
2702 readwrite_factory_CreateInstanceFromURL,
2703 readwrite_factory_CreateInstanceFromObject,
2706 static IMFReadWriteClassFactory readwrite_factory = { &readwrite_factory_vtbl };
2708 static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
2710 TRACE("%s, %p.\n", debugstr_guid(riid), out);
2712 if (IsEqualGUID(riid, &IID_IClassFactory) ||
2713 IsEqualGUID(riid, &IID_IUnknown))
2715 IClassFactory_AddRef(iface);
2716 *out = iface;
2717 return S_OK;
2720 WARN("interface %s not implemented\n", debugstr_guid(riid));
2721 *out = NULL;
2722 return E_NOINTERFACE;
2725 static ULONG WINAPI classfactory_AddRef(IClassFactory *iface)
2727 return 2;
2730 static ULONG WINAPI classfactory_Release(IClassFactory *iface)
2732 return 1;
2735 static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out)
2737 TRACE("%p, %s, %p.\n", outer, debugstr_guid(riid), out);
2739 *out = NULL;
2741 if (outer)
2742 return CLASS_E_NOAGGREGATION;
2744 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory, riid, out);
2747 static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock)
2749 FIXME("%d.\n", dolock);
2750 return S_OK;
2753 static const IClassFactoryVtbl classfactoryvtbl =
2755 classfactory_QueryInterface,
2756 classfactory_AddRef,
2757 classfactory_Release,
2758 classfactory_CreateInstance,
2759 classfactory_LockServer,
2762 static IClassFactory classfactory = { &classfactoryvtbl };
2764 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
2766 TRACE("%s, %s, %p.\n", debugstr_guid(clsid), debugstr_guid(riid), out);
2768 if (IsEqualGUID(clsid, &CLSID_MFReadWriteClassFactory))
2769 return IClassFactory_QueryInterface(&classfactory, riid, out);
2771 WARN("Unsupported class %s.\n", debugstr_guid(clsid));
2772 *out = NULL;
2773 return CLASS_E_CLASSNOTAVAILABLE;