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
32 #include "mfreadwrite.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 #include "mf_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
44 struct stream_response
54 enum media_stream_state
56 STREAM_STATE_READY
= 0,
60 enum media_source_state
62 SOURCE_STATE_STOPPED
= 0,
66 enum media_stream_flags
68 STREAM_FLAG_SAMPLE_REQUESTED
= 0x1, /* Protects from making multiple sample requests. */
69 STREAM_FLAG_SELECTED
= 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
70 STREAM_FLAG_PRESENTED
= 0x4, /* Set if stream was selected last time Start() was called. */
71 STREAM_FLAG_STOPPED
= 0x8, /* Received MEStreamStopped */
74 struct stream_transform
76 IMFTransform
*transform
;
77 unsigned int min_buffer_size
;
82 IMFMediaStream
*stream
;
83 IMFMediaType
*current
;
84 struct stream_transform decoder
;
85 IMFVideoSampleAllocatorEx
*allocator
;
88 enum media_stream_state state
;
90 unsigned int requests
;
91 unsigned int responses
;
92 LONGLONG last_sample_ts
;
93 struct source_reader
*reader
;
96 enum source_reader_async_op
98 SOURCE_READER_ASYNC_READ
,
99 SOURCE_READER_ASYNC_SEEK
,
100 SOURCE_READER_ASYNC_FLUSH
,
101 SOURCE_READER_ASYNC_SAMPLE_READY
,
104 struct source_reader_async_command
106 IUnknown IUnknown_iface
;
108 enum source_reader_async_op op
;
114 unsigned int stream_index
;
119 PROPVARIANT position
;
123 unsigned int stream_index
;
127 unsigned int stream_index
;
131 unsigned int stream_index
;
136 enum source_reader_flags
138 SOURCE_READER_FLUSHING
= 0x1,
139 SOURCE_READER_SEEKING
= 0x2,
140 SOURCE_READER_SHUTDOWN_ON_RELEASE
= 0x4,
141 SOURCE_READER_D3D9_DEVICE_MANAGER
= 0x8,
142 SOURCE_READER_DXGI_DEVICE_MANAGER
= 0x10,
143 SOURCE_READER_HAS_DEVICE_MANAGER
= SOURCE_READER_D3D9_DEVICE_MANAGER
| SOURCE_READER_DXGI_DEVICE_MANAGER
,
148 IMFSourceReader IMFSourceReader_iface
;
149 IMFAsyncCallback source_events_callback
;
150 IMFAsyncCallback stream_events_callback
;
151 IMFAsyncCallback async_commands_callback
;
153 LONG public_refcount
;
154 IMFMediaSource
*source
;
155 IMFPresentationDescriptor
*descriptor
;
156 IMFSourceReaderCallback
*async_callback
;
157 IMFAttributes
*attributes
;
158 IUnknown
*device_manager
;
159 unsigned int first_audio_stream_index
;
160 unsigned int first_video_stream_index
;
164 enum media_source_state source_state
;
165 struct media_stream
*streams
;
166 struct list responses
;
168 CONDITION_VARIABLE sample_event
;
169 CONDITION_VARIABLE state_event
;
170 CONDITION_VARIABLE stop_event
;
173 static inline struct source_reader
*impl_from_IMFSourceReader(IMFSourceReader
*iface
)
175 return CONTAINING_RECORD(iface
, struct source_reader
, IMFSourceReader_iface
);
178 static struct source_reader
*impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
180 return CONTAINING_RECORD(iface
, struct source_reader
, source_events_callback
);
183 static struct source_reader
*impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
185 return CONTAINING_RECORD(iface
, struct source_reader
, stream_events_callback
);
188 static struct source_reader
*impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
190 return CONTAINING_RECORD(iface
, struct source_reader
, async_commands_callback
);
193 static struct source_reader_async_command
*impl_from_async_command_IUnknown(IUnknown
*iface
)
195 return CONTAINING_RECORD(iface
, struct source_reader_async_command
, IUnknown_iface
);
198 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
);
200 static ULONG
source_reader_addref(struct source_reader
*reader
)
202 return InterlockedIncrement(&reader
->refcount
);
205 static ULONG
source_reader_release(struct source_reader
*reader
)
207 ULONG refcount
= InterlockedDecrement(&reader
->refcount
);
212 if (reader
->device_manager
)
213 IUnknown_Release(reader
->device_manager
);
214 if (reader
->async_callback
)
215 IMFSourceReaderCallback_Release(reader
->async_callback
);
216 if (reader
->descriptor
)
217 IMFPresentationDescriptor_Release(reader
->descriptor
);
218 if (reader
->attributes
)
219 IMFAttributes_Release(reader
->attributes
);
220 IMFMediaSource_Release(reader
->source
);
222 for (i
= 0; i
< reader
->stream_count
; ++i
)
224 struct media_stream
*stream
= &reader
->streams
[i
];
227 IMFMediaStream_Release(stream
->stream
);
229 IMFMediaType_Release(stream
->current
);
230 if (stream
->decoder
.transform
)
231 IMFTransform_Release(stream
->decoder
.transform
);
232 if (stream
->allocator
)
233 IMFVideoSampleAllocatorEx_Release(stream
->allocator
);
235 source_reader_release_responses(reader
, NULL
);
236 free(reader
->streams
);
237 MFUnlockWorkQueue(reader
->queue
);
238 DeleteCriticalSection(&reader
->cs
);
245 static HRESULT WINAPI
source_reader_async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
247 if (IsEqualIID(riid
, &IID_IUnknown
))
250 IUnknown_AddRef(iface
);
254 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
256 return E_NOINTERFACE
;
259 static ULONG WINAPI
source_reader_async_command_AddRef(IUnknown
*iface
)
261 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
262 return InterlockedIncrement(&command
->refcount
);
265 static ULONG WINAPI
source_reader_async_command_Release(IUnknown
*iface
)
267 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
268 ULONG refcount
= InterlockedIncrement(&command
->refcount
);
272 if (command
->op
== SOURCE_READER_ASYNC_SEEK
)
273 PropVariantClear(&command
->u
.seek
.position
);
280 static const IUnknownVtbl source_reader_async_command_vtbl
=
282 source_reader_async_command_QueryInterface
,
283 source_reader_async_command_AddRef
,
284 source_reader_async_command_Release
,
287 static HRESULT
source_reader_create_async_op(enum source_reader_async_op op
, struct source_reader_async_command
**ret
)
289 struct source_reader_async_command
*command
;
291 if (!(command
= calloc(1, sizeof(*command
))))
292 return E_OUTOFMEMORY
;
294 command
->IUnknown_iface
.lpVtbl
= &source_reader_async_command_vtbl
;
302 static HRESULT
media_event_get_object(IMFMediaEvent
*event
, REFIID riid
, void **obj
)
307 PropVariantInit(&value
);
308 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
310 WARN("Failed to get event value, hr %#lx.\n", hr
);
314 if (value
.vt
!= VT_UNKNOWN
|| !value
.punkVal
)
316 WARN("Unexpected value type %d.\n", value
.vt
);
317 PropVariantClear(&value
);
321 hr
= IUnknown_QueryInterface(value
.punkVal
, riid
, obj
);
322 PropVariantClear(&value
);
325 WARN("Unexpected object type.\n");
332 static HRESULT
media_stream_get_id(IMFMediaStream
*stream
, DWORD
*id
)
334 IMFStreamDescriptor
*sd
;
337 if (SUCCEEDED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
339 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, id
);
340 IMFStreamDescriptor_Release(sd
);
346 static HRESULT WINAPI
source_reader_callback_QueryInterface(IMFAsyncCallback
*iface
,
347 REFIID riid
, void **obj
)
349 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
351 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
352 IsEqualIID(riid
, &IID_IUnknown
))
355 IMFAsyncCallback_AddRef(iface
);
359 WARN("Unsupported %s.\n", debugstr_guid(riid
));
361 return E_NOINTERFACE
;
364 static ULONG WINAPI
source_reader_source_events_callback_AddRef(IMFAsyncCallback
*iface
)
366 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
367 return source_reader_addref(reader
);
370 static ULONG WINAPI
source_reader_source_events_callback_Release(IMFAsyncCallback
*iface
)
372 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
373 return source_reader_release(reader
);
376 static HRESULT WINAPI
source_reader_callback_GetParameters(IMFAsyncCallback
*iface
,
377 DWORD
*flags
, DWORD
*queue
)
382 static void source_reader_response_ready(struct source_reader
*reader
, struct stream_response
*response
)
384 struct source_reader_async_command
*command
;
385 struct media_stream
*stream
= &reader
->streams
[response
->stream_index
];
388 if (!stream
->requests
)
391 if (reader
->async_callback
)
393 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY
, &command
)))
395 command
->u
.sample
.stream_index
= stream
->index
;
396 if (FAILED(hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
)))
397 WARN("Failed to submit async result, hr %#lx.\n", hr
);
398 IUnknown_Release(&command
->IUnknown_iface
);
402 WakeAllConditionVariable(&reader
->sample_event
);
407 static void source_reader_copy_sample_buffer(IMFSample
*src
, IMFSample
*dst
)
409 IMFMediaBuffer
*buffer
;
414 IMFSample_CopyAllItems(src
, (IMFAttributes
*)dst
);
416 IMFSample_SetSampleDuration(dst
, 0);
417 IMFSample_SetSampleTime(dst
, 0);
418 IMFSample_SetSampleFlags(dst
, 0);
420 if (SUCCEEDED(IMFSample_GetSampleDuration(src
, &time
)))
421 IMFSample_SetSampleDuration(dst
, time
);
423 if (SUCCEEDED(IMFSample_GetSampleTime(src
, &time
)))
424 IMFSample_SetSampleTime(dst
, time
);
426 if (SUCCEEDED(IMFSample_GetSampleFlags(src
, &flags
)))
427 IMFSample_SetSampleFlags(dst
, flags
);
429 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src
, NULL
)))
431 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst
, 0, &buffer
)))
433 if (FAILED(hr
= IMFSample_CopyToBuffer(src
, buffer
)))
434 WARN("Failed to copy a buffer, hr %#lx.\n", hr
);
435 IMFMediaBuffer_Release(buffer
);
440 static HRESULT
source_reader_queue_response(struct source_reader
*reader
, struct media_stream
*stream
, HRESULT status
,
441 DWORD stream_flags
, LONGLONG timestamp
, IMFSample
*sample
)
443 struct stream_response
*response
;
445 if (!(response
= calloc(1, sizeof(*response
))))
446 return E_OUTOFMEMORY
;
448 response
->status
= status
;
449 response
->stream_index
= stream
->index
;
450 response
->stream_flags
= stream_flags
;
451 response
->timestamp
= timestamp
;
452 response
->sample
= sample
;
453 if (response
->sample
)
454 IMFSample_AddRef(response
->sample
);
456 list_add_tail(&reader
->responses
, &response
->entry
);
459 source_reader_response_ready(reader
, response
);
461 stream
->last_sample_ts
= timestamp
;
466 static HRESULT
source_reader_request_sample(struct source_reader
*reader
, struct media_stream
*stream
)
470 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
472 if (FAILED(hr
= IMFMediaStream_RequestSample(stream
->stream
, NULL
)))
473 WARN("Sample request failed, hr %#lx.\n", hr
);
476 stream
->flags
|= STREAM_FLAG_SAMPLE_REQUESTED
;
483 static HRESULT
source_reader_new_stream_handler(struct source_reader
*reader
, IMFMediaEvent
*event
)
485 IMFMediaStream
*stream
;
490 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFMediaStream
, (void **)&stream
)))
492 WARN("Failed to get stream object, hr %#lx.\n", hr
);
496 TRACE("Got new stream %p.\n", stream
);
498 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
500 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
501 IMFMediaStream_Release(stream
);
505 EnterCriticalSection(&reader
->cs
);
507 for (i
= 0; i
< reader
->stream_count
; ++i
)
509 if (id
== reader
->streams
[i
].id
)
511 if (!reader
->streams
[i
].stream
)
513 reader
->streams
[i
].stream
= stream
;
514 IMFMediaStream_AddRef(reader
->streams
[i
].stream
);
515 if (FAILED(hr
= IMFMediaStream_BeginGetEvent(stream
, &reader
->stream_events_callback
,
516 (IUnknown
*)stream
)))
518 WARN("Failed to subscribe to stream events, hr %#lx.\n", hr
);
521 if (reader
->streams
[i
].requests
)
522 if (FAILED(source_reader_request_sample(reader
, &reader
->streams
[i
])))
523 WakeAllConditionVariable(&reader
->sample_event
);
529 if (i
== reader
->stream_count
)
530 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id
);
532 LeaveCriticalSection(&reader
->cs
);
534 IMFMediaStream_Release(stream
);
539 static HRESULT
source_reader_source_state_handler(struct source_reader
*reader
, MediaEventType event_type
)
541 EnterCriticalSection(&reader
->cs
);
545 case MESourceStarted
:
546 reader
->source_state
= SOURCE_STATE_STARTED
;
547 reader
->flags
&= ~SOURCE_READER_SEEKING
;
549 case MESourceStopped
:
550 reader
->source_state
= SOURCE_STATE_STOPPED
;
551 reader
->flags
&= ~SOURCE_READER_SEEKING
;
554 reader
->flags
&= ~SOURCE_READER_SEEKING
;
557 WARN("Unhandled event %ld.\n", event_type
);
560 LeaveCriticalSection(&reader
->cs
);
562 WakeAllConditionVariable(&reader
->state_event
);
563 if (event_type
== MESourceStopped
)
564 WakeAllConditionVariable(&reader
->stop_event
);
569 static HRESULT WINAPI
source_reader_source_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
571 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
572 MediaEventType event_type
;
573 IMFMediaSource
*source
;
574 IMFMediaEvent
*event
;
577 TRACE("%p, %p.\n", iface
, result
);
579 source
= (IMFMediaSource
*)IMFAsyncResult_GetStateNoAddRef(result
);
581 if (FAILED(hr
= IMFMediaSource_EndGetEvent(source
, result
, &event
)))
584 IMFMediaEvent_GetType(event
, &event_type
);
586 TRACE("Got event %lu.\n", event_type
);
591 hr
= source_reader_new_stream_handler(reader
, event
);
593 case MESourceStarted
:
595 case MESourceStopped
:
597 hr
= source_reader_source_state_handler(reader
, event_type
);
599 case MEBufferingStarted
:
600 case MEBufferingStopped
:
604 case MESourceCharacteristicsChanged
:
605 case MESourceMetadataChanged
:
606 case MEContentProtectionMetadata
:
607 case MEDeviceThermalStateChanged
:
608 if (reader
->async_callback
)
609 IMFSourceReaderCallback_OnEvent(reader
->async_callback
, MF_SOURCE_READER_MEDIASOURCE
, event
);
616 WARN("Failed while handling %ld event, hr %#lx.\n", event_type
, hr
);
618 IMFMediaEvent_Release(event
);
620 if (event_type
!= MESourceStopped
)
621 IMFMediaSource_BeginGetEvent(source
, iface
, (IUnknown
*)source
);
626 static const IMFAsyncCallbackVtbl source_events_callback_vtbl
=
628 source_reader_callback_QueryInterface
,
629 source_reader_source_events_callback_AddRef
,
630 source_reader_source_events_callback_Release
,
631 source_reader_callback_GetParameters
,
632 source_reader_source_events_callback_Invoke
,
635 static ULONG WINAPI
source_reader_stream_events_callback_AddRef(IMFAsyncCallback
*iface
)
637 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
638 return source_reader_addref(reader
);
641 static ULONG WINAPI
source_reader_stream_events_callback_Release(IMFAsyncCallback
*iface
)
643 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
644 return source_reader_release(reader
);
647 static HRESULT
source_reader_pull_stream_samples(struct source_reader
*reader
, struct media_stream
*stream
)
649 MFT_OUTPUT_STREAM_INFO stream_info
= { 0 };
650 MFT_OUTPUT_DATA_BUFFER out_buffer
;
651 unsigned int buffer_size
;
652 IMFMediaBuffer
*buffer
;
657 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(stream
->decoder
.transform
, 0, &stream_info
)))
659 WARN("Failed to get output stream info, hr %#lx.\n", hr
);
665 memset(&out_buffer
, 0, sizeof(out_buffer
));
667 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
)))
669 if (FAILED(hr
= MFCreateSample(&out_buffer
.pSample
)))
672 buffer_size
= max(stream_info
.cbSize
, stream
->decoder
.min_buffer_size
);
674 if (FAILED(hr
= MFCreateAlignedMemoryBuffer(buffer_size
, stream_info
.cbAlignment
, &buffer
)))
676 IMFSample_Release(out_buffer
.pSample
);
680 IMFSample_AddBuffer(out_buffer
.pSample
, buffer
);
681 IMFMediaBuffer_Release(buffer
);
684 if (FAILED(hr
= IMFTransform_ProcessOutput(stream
->decoder
.transform
, 0, 1, &out_buffer
, &status
)))
686 if (out_buffer
.pSample
)
687 IMFSample_Release(out_buffer
.pSample
);
692 if (FAILED(IMFSample_GetSampleTime(out_buffer
.pSample
, ×tamp
)))
693 WARN("Sample time wasn't set.\n");
695 source_reader_queue_response(reader
, stream
, S_OK
/* FIXME */, 0, timestamp
, out_buffer
.pSample
);
696 if (out_buffer
.pSample
)
697 IMFSample_Release(out_buffer
.pSample
);
698 if (out_buffer
.pEvents
)
699 IMFCollection_Release(out_buffer
.pEvents
);
705 static HRESULT
source_reader_process_sample(struct source_reader
*reader
, struct media_stream
*stream
,
711 if (!stream
->decoder
.transform
)
714 if (FAILED(IMFSample_GetSampleTime(sample
, ×tamp
)))
715 WARN("Sample time wasn't set.\n");
717 return source_reader_queue_response(reader
, stream
, S_OK
, 0, timestamp
, sample
);
720 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
722 hr
= source_reader_pull_stream_samples(reader
, stream
);
723 if (hr
== MF_E_TRANSFORM_NEED_MORE_INPUT
)
725 if (FAILED(hr
= IMFTransform_ProcessInput(stream
->decoder
.transform
, 0, sample
, 0)))
727 WARN("Transform failed to process input, hr %#lx.\n", hr
);
731 if ((hr
= source_reader_pull_stream_samples(reader
, stream
)) == MF_E_TRANSFORM_NEED_MORE_INPUT
)
735 WARN("Transform failed to process output, hr %#lx.\n", hr
);
740 static HRESULT
source_reader_media_sample_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
741 IMFMediaEvent
*event
)
748 TRACE("Got new sample for stream %p.\n", stream
);
750 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFSample
, (void **)&sample
)))
752 WARN("Failed to get sample object, hr %#lx.\n", hr
);
756 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
758 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
759 IMFSample_Release(sample
);
763 EnterCriticalSection(&reader
->cs
);
765 for (i
= 0; i
< reader
->stream_count
; ++i
)
767 if (id
== reader
->streams
[i
].id
)
769 /* FIXME: propagate processing errors? */
771 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
772 hr
= source_reader_process_sample(reader
, &reader
->streams
[i
], sample
);
773 if (reader
->streams
[i
].requests
)
774 source_reader_request_sample(reader
, &reader
->streams
[i
]);
780 if (i
== reader
->stream_count
)
781 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id
);
783 LeaveCriticalSection(&reader
->cs
);
785 IMFSample_Release(sample
);
790 static HRESULT
source_reader_media_stream_state_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
791 IMFMediaEvent
*event
)
793 MediaEventType event_type
;
800 IMFMediaEvent_GetType(event
, &event_type
);
802 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
804 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
808 EnterCriticalSection(&reader
->cs
);
810 for (i
= 0; i
< reader
->stream_count
; ++i
)
812 struct media_stream
*stream
= &reader
->streams
[i
];
814 if (id
== stream
->id
)
819 stream
->state
= STREAM_STATE_EOS
;
820 stream
->flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
822 if (stream
->decoder
.transform
&& SUCCEEDED(IMFTransform_ProcessMessage(stream
->decoder
.transform
,
823 MFT_MESSAGE_COMMAND_DRAIN
, 0)))
825 if ((hr
= source_reader_pull_stream_samples(reader
, stream
)) != MF_E_TRANSFORM_NEED_MORE_INPUT
)
826 WARN("Failed to pull pending samples, hr %#lx.\n", hr
);
829 while (stream
->requests
)
830 source_reader_queue_response(reader
, stream
, S_OK
, MF_SOURCE_READERF_ENDOFSTREAM
, 0, NULL
);
834 case MEStreamStarted
:
835 stream
->state
= STREAM_STATE_READY
;
837 case MEStreamStopped
:
838 stream
->flags
|= STREAM_FLAG_STOPPED
;
842 hr
= SUCCEEDED(IMFMediaEvent_GetValue(event
, &value
)) && value
.vt
== VT_I8
? S_OK
: E_UNEXPECTED
;
843 timestamp
= SUCCEEDED(hr
) ? value
.hVal
.QuadPart
: 0;
844 PropVariantClear(&value
);
846 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_STREAMTICK
, timestamp
, NULL
);
857 LeaveCriticalSection(&reader
->cs
);
859 if (event_type
== MEStreamStopped
)
860 WakeAllConditionVariable(&reader
->stop_event
);
865 static HRESULT WINAPI
source_reader_stream_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
867 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
868 MediaEventType event_type
;
869 IMFMediaStream
*stream
;
870 IMFMediaEvent
*event
;
873 TRACE("%p, %p.\n", iface
, result
);
875 stream
= (IMFMediaStream
*)IMFAsyncResult_GetStateNoAddRef(result
);
877 if (FAILED(hr
= IMFMediaStream_EndGetEvent(stream
, result
, &event
)))
880 IMFMediaEvent_GetType(event
, &event_type
);
882 TRACE("Got event %lu.\n", event_type
);
887 hr
= source_reader_media_sample_handler(reader
, stream
, event
);
890 case MEStreamStarted
:
891 case MEStreamStopped
:
894 hr
= source_reader_media_stream_state_handler(reader
, stream
, event
);
901 WARN("Failed while handling %ld event, hr %#lx.\n", event_type
, hr
);
903 IMFMediaEvent_Release(event
);
905 if (event_type
!= MEStreamStopped
)
906 IMFMediaStream_BeginGetEvent(stream
, iface
, (IUnknown
*)stream
);
911 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl
=
913 source_reader_callback_QueryInterface
,
914 source_reader_stream_events_callback_AddRef
,
915 source_reader_stream_events_callback_Release
,
916 source_reader_callback_GetParameters
,
917 source_reader_stream_events_callback_Invoke
,
920 static ULONG WINAPI
source_reader_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
922 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
923 return source_reader_addref(reader
);
926 static ULONG WINAPI
source_reader_async_commands_callback_Release(IMFAsyncCallback
*iface
)
928 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
929 return source_reader_release(reader
);
932 static struct stream_response
* media_stream_detach_response(struct source_reader
*reader
, struct stream_response
*response
)
934 struct media_stream
*stream
;
936 list_remove(&response
->entry
);
938 if (response
->stream_index
< reader
->stream_count
)
940 stream
= &reader
->streams
[response
->stream_index
];
941 if (stream
->responses
)
948 static struct stream_response
*media_stream_pop_response(struct source_reader
*reader
, struct media_stream
*stream
)
950 struct stream_response
*response
;
954 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
956 if (stream
&& response
->stream_index
!= stream
->index
)
959 if (!stream
) stream
= &reader
->streams
[response
->stream_index
];
961 if (response
->sample
&& stream
->allocator
)
963 /* Return allocation error to the caller, while keeping original response sample in for later. */
964 if (SUCCEEDED(hr
= IMFVideoSampleAllocatorEx_AllocateSample(stream
->allocator
, &sample
)))
966 source_reader_copy_sample_buffer(response
->sample
, sample
);
967 IMFSample_Release(response
->sample
);
968 response
->sample
= sample
;
972 if (!(response
= calloc(1, sizeof(*response
))))
975 response
->status
= hr
;
976 response
->stream_flags
= MF_SOURCE_READERF_ERROR
;
981 return media_stream_detach_response(reader
, response
);
987 static void source_reader_release_response(struct stream_response
*response
)
989 if (response
->sample
)
990 IMFSample_Release(response
->sample
);
994 static HRESULT
source_reader_get_stream_selection(const struct source_reader
*reader
, DWORD index
, BOOL
*selected
)
996 IMFStreamDescriptor
*sd
;
998 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, selected
, &sd
)))
999 return MF_E_INVALIDSTREAMNUMBER
;
1000 IMFStreamDescriptor_Release(sd
);
1005 static HRESULT
source_reader_start_source(struct source_reader
*reader
)
1007 BOOL selected
, selection_changed
= FALSE
;
1008 PROPVARIANT position
;
1012 for (i
= 0; i
< reader
->stream_count
; ++i
)
1014 source_reader_get_stream_selection(reader
, i
, &selected
);
1016 reader
->streams
[i
].flags
|= STREAM_FLAG_SELECTED
;
1018 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SELECTED
;
1021 if (reader
->source_state
== SOURCE_STATE_STARTED
)
1023 for (i
= 0; i
< reader
->stream_count
; ++i
)
1025 selection_changed
= !!(reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
) ^
1026 !!(reader
->streams
[i
].flags
& STREAM_FLAG_PRESENTED
);
1027 if (selection_changed
)
1032 position
.hVal
.QuadPart
= 0;
1033 if (reader
->source_state
!= SOURCE_STATE_STARTED
|| selection_changed
)
1035 position
.vt
= reader
->source_state
== SOURCE_STATE_STARTED
? VT_EMPTY
: VT_I8
;
1037 /* Update cached stream selection if descriptor was accepted. */
1038 if (SUCCEEDED(hr
= IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &GUID_NULL
, &position
)))
1040 for (i
= 0; i
< reader
->stream_count
; ++i
)
1042 if (reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
)
1043 reader
->streams
[i
].flags
|= STREAM_FLAG_PRESENTED
;
1051 static BOOL
source_reader_got_response_for_stream(struct source_reader
*reader
, struct media_stream
*stream
)
1053 struct stream_response
*response
;
1055 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1057 if (response
->stream_index
== stream
->index
)
1064 static BOOL
source_reader_get_read_result(struct source_reader
*reader
, struct media_stream
*stream
, DWORD flags
,
1065 HRESULT
*status
, DWORD
*stream_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1067 struct stream_response
*response
= NULL
;
1068 BOOL request_sample
= FALSE
;
1070 if ((response
= media_stream_pop_response(reader
, stream
)))
1072 *status
= response
->status
;
1073 *stream_index
= stream
->index
;
1074 *stream_flags
= response
->stream_flags
;
1075 *timestamp
= response
->timestamp
;
1076 *sample
= response
->sample
;
1078 IMFSample_AddRef(*sample
);
1080 source_reader_release_response(response
);
1085 *stream_index
= stream
->index
;
1089 if (stream
->state
== STREAM_STATE_EOS
)
1091 *stream_flags
= MF_SOURCE_READERF_ENDOFSTREAM
;
1095 request_sample
= !(flags
& MF_SOURCE_READER_CONTROLF_DRAIN
);
1100 return !request_sample
;
1103 static HRESULT
source_reader_get_next_selected_stream(struct source_reader
*reader
, DWORD
*stream_index
)
1105 unsigned int i
, first_selected
= ~0u;
1106 BOOL selected
, stream_drained
;
1107 LONGLONG min_ts
= MAXLONGLONG
;
1109 for (i
= 0; i
< reader
->stream_count
; ++i
)
1111 stream_drained
= reader
->streams
[i
].state
== STREAM_STATE_EOS
&& !reader
->streams
[i
].responses
;
1112 selected
= SUCCEEDED(source_reader_get_stream_selection(reader
, i
, &selected
)) && selected
;
1116 if (first_selected
== ~0u)
1119 /* Pick the stream whose last sample had the lowest timestamp. */
1120 if (!stream_drained
&& reader
->streams
[i
].last_sample_ts
< min_ts
)
1122 min_ts
= reader
->streams
[i
].last_sample_ts
;
1128 /* If all selected streams reached EOS, use first selected. */
1129 if (first_selected
!= ~0u)
1131 if (min_ts
== MAXLONGLONG
)
1132 *stream_index
= first_selected
;
1135 return first_selected
== ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED
: S_OK
;
1138 static HRESULT
source_reader_get_stream_read_index(struct source_reader
*reader
, unsigned int index
, DWORD
*stream_index
)
1145 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1146 *stream_index
= reader
->first_video_stream_index
;
1148 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1149 *stream_index
= reader
->first_audio_stream_index
;
1151 case MF_SOURCE_READER_ANY_STREAM
:
1152 return source_reader_get_next_selected_stream(reader
, stream_index
);
1154 *stream_index
= index
;
1157 /* Can't read from deselected streams. */
1158 if (SUCCEEDED(hr
= source_reader_get_stream_selection(reader
, *stream_index
, &selected
)) && !selected
)
1159 hr
= MF_E_INVALIDREQUEST
;
1164 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
)
1166 struct stream_response
*ptr
, *next
;
1168 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &reader
->responses
, struct stream_response
, entry
)
1170 if (stream
&& stream
->index
!= ptr
->stream_index
&&
1171 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_VIDEO_STREAM
&&
1172 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_AUDIO_STREAM
&&
1173 ptr
->stream_index
!= MF_SOURCE_READER_ANY_STREAM
)
1177 media_stream_detach_response(reader
, ptr
);
1178 source_reader_release_response(ptr
);
1182 static void source_reader_flush_stream(struct source_reader
*reader
, DWORD stream_index
)
1184 struct media_stream
*stream
= &reader
->streams
[stream_index
];
1186 source_reader_release_responses(reader
, stream
);
1187 if (stream
->decoder
.transform
)
1188 IMFTransform_ProcessMessage(stream
->decoder
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
1189 stream
->requests
= 0;
1192 static HRESULT
source_reader_flush(struct source_reader
*reader
, unsigned int index
)
1194 unsigned int stream_index
;
1197 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1199 for (stream_index
= 0; stream_index
< reader
->stream_count
; ++stream_index
)
1200 source_reader_flush_stream(reader
, stream_index
);
1206 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1207 stream_index
= reader
->first_video_stream_index
;
1209 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1210 stream_index
= reader
->first_audio_stream_index
;
1213 stream_index
= index
;
1216 if (stream_index
< reader
->stream_count
)
1217 source_reader_flush_stream(reader
, stream_index
);
1219 hr
= MF_E_INVALIDSTREAMNUMBER
;
1225 static HRESULT WINAPI
source_reader_async_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1227 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1228 struct media_stream
*stream
, stub_stream
= { .requests
= 1 };
1229 struct source_reader_async_command
*command
;
1230 struct stream_response
*response
;
1231 DWORD stream_index
, stream_flags
;
1232 BOOL report_sample
= FALSE
;
1233 IMFSample
*sample
= NULL
;
1234 LONGLONG timestamp
= 0;
1238 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
1241 command
= impl_from_async_command_IUnknown(state
);
1243 switch (command
->op
)
1245 case SOURCE_READER_ASYNC_READ
:
1246 EnterCriticalSection(&reader
->cs
);
1248 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1250 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, command
->u
.read
.stream_index
, &stream_index
)))
1252 stream
= &reader
->streams
[stream_index
];
1254 if (!(report_sample
= source_reader_get_read_result(reader
, stream
, command
->u
.read
.flags
, &status
,
1255 &stream_index
, &stream_flags
, ×tamp
, &sample
)))
1258 source_reader_request_sample(reader
, stream
);
1259 /* FIXME: set error stream/reader state on request failure */
1264 stub_stream
.index
= command
->u
.read
.stream_index
;
1265 source_reader_queue_response(reader
, &stub_stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
1269 LeaveCriticalSection(&reader
->cs
);
1272 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, status
, stream_index
, stream_flags
,
1276 IMFSample_Release(sample
);
1280 case SOURCE_READER_ASYNC_SEEK
:
1282 EnterCriticalSection(&reader
->cs
);
1283 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &command
->u
.seek
.format
,
1284 &command
->u
.seek
.position
)))
1286 reader
->flags
|= SOURCE_READER_SEEKING
;
1288 LeaveCriticalSection(&reader
->cs
);
1292 case SOURCE_READER_ASYNC_SAMPLE_READY
:
1294 EnterCriticalSection(&reader
->cs
);
1295 response
= media_stream_pop_response(reader
, NULL
);
1296 LeaveCriticalSection(&reader
->cs
);
1300 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, response
->status
, response
->stream_index
,
1301 response
->stream_flags
, response
->timestamp
, response
->sample
);
1302 source_reader_release_response(response
);
1306 case SOURCE_READER_ASYNC_FLUSH
:
1307 EnterCriticalSection(&reader
->cs
);
1308 source_reader_flush(reader
, command
->u
.flush
.stream_index
);
1309 reader
->flags
&= ~SOURCE_READER_FLUSHING
;
1310 LeaveCriticalSection(&reader
->cs
);
1312 IMFSourceReaderCallback_OnFlush(reader
->async_callback
, command
->u
.flush
.stream_index
);
1318 IUnknown_Release(state
);
1323 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl
=
1325 source_reader_callback_QueryInterface
,
1326 source_reader_async_commands_callback_AddRef
,
1327 source_reader_async_commands_callback_Release
,
1328 source_reader_callback_GetParameters
,
1329 source_reader_async_commands_callback_Invoke
,
1332 static HRESULT WINAPI
src_reader_QueryInterface(IMFSourceReader
*iface
, REFIID riid
, void **out
)
1334 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1336 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1338 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
1339 IsEqualGUID(riid
, &IID_IMFSourceReader
))
1341 *out
= &reader
->IMFSourceReader_iface
;
1345 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1347 return E_NOINTERFACE
;
1350 IUnknown_AddRef((IUnknown
*)*out
);
1354 static ULONG WINAPI
src_reader_AddRef(IMFSourceReader
*iface
)
1356 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1357 ULONG refcount
= InterlockedIncrement(&reader
->public_refcount
);
1359 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1364 static BOOL
source_reader_is_source_stopped(const struct source_reader
*reader
)
1368 if (reader
->source_state
!= SOURCE_STATE_STOPPED
)
1371 for (i
= 0; i
< reader
->stream_count
; ++i
)
1373 if (reader
->streams
[i
].stream
&& !(reader
->streams
[i
].flags
& STREAM_FLAG_STOPPED
))
1380 static ULONG WINAPI
src_reader_Release(IMFSourceReader
*iface
)
1382 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1383 ULONG refcount
= InterlockedDecrement(&reader
->public_refcount
);
1386 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1390 if (reader
->flags
& SOURCE_READER_SHUTDOWN_ON_RELEASE
)
1391 IMFMediaSource_Shutdown(reader
->source
);
1392 else if (SUCCEEDED(IMFMediaSource_Stop(reader
->source
)))
1394 EnterCriticalSection(&reader
->cs
);
1396 while (!source_reader_is_source_stopped(reader
))
1398 SleepConditionVariableCS(&reader
->stop_event
, &reader
->cs
, INFINITE
);
1401 LeaveCriticalSection(&reader
->cs
);
1404 for (i
= 0; i
< reader
->stream_count
; ++i
)
1406 struct media_stream
*stream
= &reader
->streams
[i
];
1407 IMFVideoSampleAllocatorCallback
*callback
;
1409 if (!stream
->allocator
)
1412 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream
->allocator
, &IID_IMFVideoSampleAllocatorCallback
,
1413 (void **)&callback
)))
1415 IMFVideoSampleAllocatorCallback_SetCallback(callback
, NULL
);
1416 IMFVideoSampleAllocatorCallback_Release(callback
);
1420 source_reader_release(reader
);
1426 static HRESULT WINAPI
src_reader_GetStreamSelection(IMFSourceReader
*iface
, DWORD index
, BOOL
*selected
)
1428 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1430 TRACE("%p, %#lx, %p.\n", iface
, index
, selected
);
1434 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1435 index
= reader
->first_video_stream_index
;
1437 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1438 index
= reader
->first_audio_stream_index
;
1444 return source_reader_get_stream_selection(reader
, index
, selected
);
1447 static HRESULT WINAPI
src_reader_SetStreamSelection(IMFSourceReader
*iface
, DWORD index
, BOOL selection
)
1449 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1451 BOOL selection_changed
= FALSE
, selected
;
1454 TRACE("%p, %#lx, %d.\n", iface
, index
, selection
);
1456 selection
= !!selection
;
1458 EnterCriticalSection(&reader
->cs
);
1460 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1462 for (i
= 0; i
< reader
->stream_count
; ++i
)
1464 if (!selection_changed
)
1466 source_reader_get_stream_selection(reader
, i
, &selected
);
1467 selection_changed
= !!(selected
^ selection
);
1471 IMFPresentationDescriptor_SelectStream(reader
->descriptor
, i
);
1473 IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, i
);
1480 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1481 index
= reader
->first_video_stream_index
;
1483 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1484 index
= reader
->first_audio_stream_index
;
1490 source_reader_get_stream_selection(reader
, index
, &selected
);
1491 selection_changed
= !!(selected
^ selection
);
1494 hr
= IMFPresentationDescriptor_SelectStream(reader
->descriptor
, index
);
1496 hr
= IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, index
);
1499 if (selection_changed
)
1501 for (i
= 0; i
< reader
->stream_count
; ++i
)
1503 reader
->streams
[i
].last_sample_ts
= 0;
1507 LeaveCriticalSection(&reader
->cs
);
1509 return SUCCEEDED(hr
) ? S_OK
: MF_E_INVALIDSTREAMNUMBER
;
1512 static HRESULT
source_reader_get_native_media_type(struct source_reader
*reader
, DWORD index
, DWORD type_index
,
1513 IMFMediaType
**type
)
1515 IMFMediaTypeHandler
*handler
;
1516 IMFStreamDescriptor
*sd
;
1517 IMFMediaType
*src_type
;
1523 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1524 index
= reader
->first_video_stream_index
;
1526 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1527 index
= reader
->first_audio_stream_index
;
1533 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1534 return MF_E_INVALIDSTREAMNUMBER
;
1536 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
1537 IMFStreamDescriptor_Release(sd
);
1541 if (type_index
== MF_SOURCE_READER_CURRENT_TYPE_INDEX
)
1542 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &src_type
);
1544 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, type_index
, &src_type
);
1545 IMFMediaTypeHandler_Release(handler
);
1549 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
1550 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)*type
);
1551 IMFMediaType_Release(src_type
);
1557 static HRESULT WINAPI
src_reader_GetNativeMediaType(IMFSourceReader
*iface
, DWORD index
, DWORD type_index
,
1558 IMFMediaType
**type
)
1560 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1562 TRACE("%p, %#lx, %#lx, %p.\n", iface
, index
, type_index
, type
);
1564 return source_reader_get_native_media_type(reader
, index
, type_index
, type
);
1567 static HRESULT WINAPI
src_reader_GetCurrentMediaType(IMFSourceReader
*iface
, DWORD index
, IMFMediaType
**type
)
1569 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1572 TRACE("%p, %#lx, %p.\n", iface
, index
, type
);
1576 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1577 index
= reader
->first_video_stream_index
;
1579 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1580 index
= reader
->first_audio_stream_index
;
1586 if (index
>= reader
->stream_count
)
1587 return MF_E_INVALIDSTREAMNUMBER
;
1589 if (FAILED(hr
= MFCreateMediaType(type
)))
1592 EnterCriticalSection(&reader
->cs
);
1594 hr
= IMFMediaType_CopyAllItems(reader
->streams
[index
].current
, (IMFAttributes
*)*type
);
1596 LeaveCriticalSection(&reader
->cs
);
1601 static HRESULT
source_reader_get_source_type_handler(struct source_reader
*reader
, DWORD index
,
1602 IMFMediaTypeHandler
**handler
)
1604 IMFStreamDescriptor
*sd
;
1608 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1611 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, handler
);
1612 IMFStreamDescriptor_Release(sd
);
1617 static HRESULT
source_reader_set_compatible_media_type(struct source_reader
*reader
, DWORD index
, IMFMediaType
*type
)
1619 IMFMediaTypeHandler
*type_handler
;
1620 IMFMediaType
*native_type
;
1621 BOOL type_set
= FALSE
;
1626 if (FAILED(hr
= IMFMediaType_IsEqual(type
, reader
->streams
[index
].current
, &flags
)))
1629 if (!(flags
& MF_MEDIATYPE_EQUAL_MAJOR_TYPES
))
1630 return MF_E_INVALIDMEDIATYPE
;
1632 /* No need for a decoder or type change. */
1633 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_DATA
)
1636 if (FAILED(hr
= source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1639 while (!type_set
&& IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler
, i
++, &native_type
) == S_OK
)
1641 static const DWORD compare_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_DATA
;
1643 if (SUCCEEDED(IMFMediaType_IsEqual(native_type
, type
, &flags
)) && (flags
& compare_flags
) == compare_flags
)
1645 if ((type_set
= SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, native_type
))))
1646 IMFMediaType_CopyAllItems(native_type
, (IMFAttributes
*)reader
->streams
[index
].current
);
1649 IMFMediaType_Release(native_type
);
1652 IMFMediaTypeHandler_Release(type_handler
);
1654 return type_set
? S_OK
: S_FALSE
;
1657 static HRESULT
source_reader_create_sample_allocator_attributes(const struct source_reader
*reader
,
1658 IMFAttributes
**attributes
)
1660 UINT32 shared
= 0, shared_without_mutex
= 0;
1663 if (FAILED(hr
= MFCreateAttributes(attributes
, 1)))
1666 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED
, &shared
);
1667 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, &shared_without_mutex
);
1669 if (shared_without_mutex
)
1670 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, TRUE
);
1672 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED
, TRUE
);
1677 static HRESULT
source_reader_setup_sample_allocator(struct source_reader
*reader
, unsigned int index
)
1679 struct media_stream
*stream
= &reader
->streams
[index
];
1680 IMFAttributes
*attributes
= NULL
;
1684 IMFMediaType_GetMajorType(stream
->current
, &major
);
1685 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
1688 if (!(reader
->flags
& SOURCE_READER_HAS_DEVICE_MANAGER
))
1691 if (!stream
->allocator
)
1693 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&stream
->allocator
)))
1695 WARN("Failed to create sample allocator, hr %#lx.\n", hr
);
1700 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream
->allocator
);
1701 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(stream
->allocator
, reader
->device_manager
)))
1703 WARN("Failed to set device manager, hr %#lx.\n", hr
);
1707 if (FAILED(hr
= source_reader_create_sample_allocator_attributes(reader
, &attributes
)))
1708 WARN("Failed to create allocator attributes, hr %#lx.\n", hr
);
1710 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream
->allocator
, 2, 8,
1711 attributes
, stream
->current
)))
1713 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr
);
1717 IMFAttributes_Release(attributes
);
1722 static HRESULT
source_reader_configure_decoder(struct source_reader
*reader
, DWORD index
, const CLSID
*clsid
,
1723 IMFMediaType
*input_type
, IMFMediaType
*output_type
)
1725 IMFMediaTypeHandler
*type_handler
;
1726 unsigned int block_alignment
= 0;
1727 IMFTransform
*transform
= NULL
;
1728 IMFMediaType
*type
= NULL
;
1734 if (FAILED(hr
= CoCreateInstance(clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTransform
, (void **)&transform
)))
1736 WARN("Failed to create transform object, hr %#lx.\n", hr
);
1740 if (FAILED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0)))
1742 WARN("Failed to set decoder input type, hr %#lx.\n", hr
);
1743 IMFTransform_Release(transform
);
1747 /* Find the relevant output type. */
1748 while (IMFTransform_GetOutputAvailableType(transform
, 0, i
++, &type
) == S_OK
)
1752 if (SUCCEEDED(IMFMediaType_IsEqual(type
, output_type
, &flags
)))
1754 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_TYPES
)
1756 if (SUCCEEDED(IMFTransform_SetOutputType(transform
, 0, type
, 0)))
1758 if (SUCCEEDED(source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1760 IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, input_type
);
1761 IMFMediaTypeHandler_Release(type_handler
);
1764 if (FAILED(hr
= IMFMediaType_CopyAllItems(type
, (IMFAttributes
*)reader
->streams
[index
].current
)))
1765 WARN("Failed to copy attributes, hr %#lx.\n", hr
);
1766 if (SUCCEEDED(IMFMediaType_GetMajorType(type
, &major
)) && IsEqualGUID(&major
, &MFMediaType_Audio
))
1767 IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
);
1768 IMFMediaType_Release(type
);
1770 if (reader
->streams
[index
].decoder
.transform
)
1771 IMFTransform_Release(reader
->streams
[index
].decoder
.transform
);
1773 reader
->streams
[index
].decoder
.transform
= transform
;
1774 reader
->streams
[index
].decoder
.min_buffer_size
= block_alignment
;
1781 IMFMediaType_Release(type
);
1784 WARN("Failed to find suitable decoder output type.\n");
1786 IMFTransform_Release(transform
);
1788 return MF_E_TOPO_CODEC_NOT_FOUND
;
1791 static HRESULT
source_reader_create_decoder_for_stream(struct source_reader
*reader
, DWORD index
, IMFMediaType
*output_type
)
1793 MFT_REGISTER_TYPE_INFO in_type
, out_type
;
1794 CLSID
*clsids
, mft_clsid
, category
;
1795 unsigned int i
= 0, count
;
1796 IMFMediaType
*input_type
;
1799 /* TODO: should we check if the source type is compressed? */
1801 if (FAILED(hr
= IMFMediaType_GetMajorType(output_type
, &out_type
.guidMajorType
)))
1804 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
))
1806 category
= MFT_CATEGORY_VIDEO_DECODER
;
1808 else if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1810 category
= MFT_CATEGORY_AUDIO_DECODER
;
1814 WARN("Unhandled major type %s.\n", debugstr_guid(&out_type
.guidMajorType
));
1815 return MF_E_TOPO_CODEC_NOT_FOUND
;
1818 if (FAILED(hr
= IMFMediaType_GetGUID(output_type
, &MF_MT_SUBTYPE
, &out_type
.guidSubtype
)))
1821 in_type
.guidMajorType
= out_type
.guidMajorType
;
1823 while (source_reader_get_native_media_type(reader
, index
, i
++, &input_type
) == S_OK
)
1825 if (SUCCEEDED(IMFMediaType_GetGUID(input_type
, &MF_MT_SUBTYPE
, &in_type
.guidSubtype
)))
1828 if (SUCCEEDED(hr
= MFTEnum(category
, 0, &in_type
, &out_type
, NULL
, &clsids
, &count
)) && count
)
1830 mft_clsid
= clsids
[0];
1831 CoTaskMemFree(clsids
);
1833 /* TODO: Should we iterate over all of them? */
1834 if (SUCCEEDED(source_reader_configure_decoder(reader
, index
, &mft_clsid
, input_type
, output_type
)))
1836 IMFMediaType_Release(input_type
);
1843 IMFMediaType_Release(input_type
);
1846 return MF_E_TOPO_CODEC_NOT_FOUND
;
1849 static HRESULT WINAPI
src_reader_SetCurrentMediaType(IMFSourceReader
*iface
, DWORD index
, DWORD
*reserved
,
1852 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1855 TRACE("%p, %#lx, %p, %p.\n", iface
, index
, reserved
, type
);
1859 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1860 index
= reader
->first_video_stream_index
;
1862 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1863 index
= reader
->first_audio_stream_index
;
1869 if (index
>= reader
->stream_count
)
1870 return MF_E_INVALIDSTREAMNUMBER
;
1872 /* FIXME: setting the output type while streaming should trigger a flush */
1874 EnterCriticalSection(&reader
->cs
);
1876 hr
= source_reader_set_compatible_media_type(reader
, index
, type
);
1878 hr
= source_reader_create_decoder_for_stream(reader
, index
, type
);
1880 hr
= source_reader_setup_sample_allocator(reader
, index
);
1882 LeaveCriticalSection(&reader
->cs
);
1887 static HRESULT WINAPI
src_reader_SetCurrentPosition(IMFSourceReader
*iface
, REFGUID format
, REFPROPVARIANT position
)
1889 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1890 struct source_reader_async_command
*command
;
1895 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), position
);
1897 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
1900 if (!(flags
& MFMEDIASOURCE_CAN_SEEK
))
1901 return MF_E_INVALIDREQUEST
;
1903 EnterCriticalSection(&reader
->cs
);
1905 /* Check if we got pending requests. */
1906 for (i
= 0; i
< reader
->stream_count
; ++i
)
1908 if (reader
->streams
[i
].requests
)
1910 hr
= MF_E_INVALIDREQUEST
;
1917 for (i
= 0; i
< reader
->stream_count
; ++i
)
1919 reader
->streams
[i
].last_sample_ts
= 0;
1922 if (reader
->async_callback
)
1924 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK
, &command
)))
1926 command
->u
.seek
.format
= *format
;
1927 PropVariantCopy(&command
->u
.seek
.position
, position
);
1929 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
1930 IUnknown_Release(&command
->IUnknown_iface
);
1935 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, format
, position
)))
1937 reader
->flags
|= SOURCE_READER_SEEKING
;
1938 while (reader
->flags
& SOURCE_READER_SEEKING
)
1940 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
1946 LeaveCriticalSection(&reader
->cs
);
1951 static HRESULT
source_reader_read_sample(struct source_reader
*reader
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
1952 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1954 struct media_stream
*stream
;
1955 DWORD actual_index_tmp
;
1956 LONGLONG timestamp_tmp
;
1960 if (!stream_flags
|| !sample
)
1966 timestamp
= ×tamp_tmp
;
1969 actual_index
= &actual_index_tmp
;
1971 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1973 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, index
, &stream_index
)))
1975 *actual_index
= stream_index
;
1977 stream
= &reader
->streams
[stream_index
];
1979 if (!source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
1982 while (!source_reader_got_response_for_stream(reader
, stream
) && stream
->state
!= STREAM_STATE_EOS
)
1985 if (FAILED(hr
= source_reader_request_sample(reader
, stream
)))
1986 WARN("Failed to request a sample, hr %#lx.\n", hr
);
1987 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
1989 *stream_flags
= MF_SOURCE_READERF_ERROR
;
1993 SleepConditionVariableCS(&reader
->sample_event
, &reader
->cs
, INFINITE
);
1996 source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
2002 *actual_index
= index
;
2003 *stream_flags
= MF_SOURCE_READERF_ERROR
;
2008 TRACE("Stream %lu, got sample %p, flags %#lx.\n", *actual_index
, *sample
, *stream_flags
);
2013 static HRESULT
source_reader_read_sample_async(struct source_reader
*reader
, unsigned int index
, unsigned int flags
,
2014 DWORD
*actual_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2016 struct source_reader_async_command
*command
;
2019 if (actual_index
|| stream_flags
|| timestamp
|| sample
)
2020 return E_INVALIDARG
;
2022 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2023 hr
= MF_E_NOTACCEPTING
;
2026 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_READ
, &command
)))
2028 command
->u
.read
.stream_index
= index
;
2029 command
->u
.read
.flags
= flags
;
2031 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2032 IUnknown_Release(&command
->IUnknown_iface
);
2039 static HRESULT WINAPI
src_reader_ReadSample(IMFSourceReader
*iface
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
2040 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2042 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
2045 TRACE("%p, %#lx, %#lx, %p, %p, %p, %p\n", iface
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2047 EnterCriticalSection(&reader
->cs
);
2049 while (reader
->flags
& SOURCE_READER_SEEKING
)
2051 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2054 if (reader
->async_callback
)
2055 hr
= source_reader_read_sample_async(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2057 hr
= source_reader_read_sample(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2059 LeaveCriticalSection(&reader
->cs
);
2064 static HRESULT
source_reader_flush_async(struct source_reader
*reader
, unsigned int index
)
2066 struct source_reader_async_command
*command
;
2067 unsigned int stream_index
;
2070 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2071 return MF_E_INVALIDREQUEST
;
2075 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2076 stream_index
= reader
->first_video_stream_index
;
2078 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2079 stream_index
= reader
->first_audio_stream_index
;
2082 stream_index
= index
;
2085 reader
->flags
|= SOURCE_READER_FLUSHING
;
2087 if (stream_index
!= MF_SOURCE_READER_ALL_STREAMS
&& stream_index
>= reader
->stream_count
)
2088 return MF_E_INVALIDSTREAMNUMBER
;
2090 if (FAILED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH
, &command
)))
2093 command
->u
.flush
.stream_index
= stream_index
;
2095 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2096 IUnknown_Release(&command
->IUnknown_iface
);
2101 static HRESULT WINAPI
src_reader_Flush(IMFSourceReader
*iface
, DWORD index
)
2103 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
2106 TRACE("%p, %#lx.\n", iface
, index
);
2108 EnterCriticalSection(&reader
->cs
);
2110 if (reader
->async_callback
)
2111 hr
= source_reader_flush_async(reader
, index
);
2113 hr
= source_reader_flush(reader
, index
);
2115 LeaveCriticalSection(&reader
->cs
);
2120 static HRESULT WINAPI
src_reader_GetServiceForStream(IMFSourceReader
*iface
, DWORD index
, REFGUID service
,
2121 REFIID riid
, void **object
)
2123 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
2124 IUnknown
*obj
= NULL
;
2127 TRACE("%p, %#lx, %s, %s, %p\n", iface
, index
, debugstr_guid(service
), debugstr_guid(riid
), object
);
2129 EnterCriticalSection(&reader
->cs
);
2133 case MF_SOURCE_READER_MEDIASOURCE
:
2134 obj
= (IUnknown
*)reader
->source
;
2137 if (index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2138 index
= reader
->first_video_stream_index
;
2139 else if (index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2140 index
= reader
->first_audio_stream_index
;
2142 if (index
>= reader
->stream_count
)
2143 hr
= MF_E_INVALIDSTREAMNUMBER
;
2146 obj
= (IUnknown
*)reader
->streams
[index
].decoder
.transform
;
2147 if (!obj
) hr
= E_NOINTERFACE
;
2153 IUnknown_AddRef(obj
);
2155 LeaveCriticalSection(&reader
->cs
);
2159 if (IsEqualGUID(service
, &GUID_NULL
))
2161 hr
= IUnknown_QueryInterface(obj
, riid
, object
);
2167 hr
= IUnknown_QueryInterface(obj
, &IID_IMFGetService
, (void **)&gs
);
2170 hr
= IMFGetService_GetService(gs
, service
, riid
, object
);
2171 IMFGetService_Release(gs
);
2177 IUnknown_Release(obj
);
2182 static HRESULT WINAPI
src_reader_GetPresentationAttribute(IMFSourceReader
*iface
, DWORD index
,
2183 REFGUID guid
, PROPVARIANT
*value
)
2185 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
2186 IMFStreamDescriptor
*sd
;
2190 TRACE("%p, %#lx, %s, %p.\n", iface
, index
, debugstr_guid(guid
), value
);
2194 case MF_SOURCE_READER_MEDIASOURCE
:
2195 if (IsEqualGUID(guid
, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS
))
2199 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2203 value
->ulVal
= flags
;
2208 return IMFPresentationDescriptor_GetItem(reader
->descriptor
, guid
, value
);
2211 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2212 index
= reader
->first_video_stream_index
;
2214 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2215 index
= reader
->first_audio_stream_index
;
2221 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
2224 hr
= IMFStreamDescriptor_GetItem(sd
, guid
, value
);
2225 IMFStreamDescriptor_Release(sd
);
2230 static const IMFSourceReaderVtbl srcreader_vtbl
=
2232 src_reader_QueryInterface
,
2235 src_reader_GetStreamSelection
,
2236 src_reader_SetStreamSelection
,
2237 src_reader_GetNativeMediaType
,
2238 src_reader_GetCurrentMediaType
,
2239 src_reader_SetCurrentMediaType
,
2240 src_reader_SetCurrentPosition
,
2241 src_reader_ReadSample
,
2243 src_reader_GetServiceForStream
,
2244 src_reader_GetPresentationAttribute
2247 static DWORD
reader_get_first_stream_index(IMFPresentationDescriptor
*descriptor
, const GUID
*major
)
2254 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
2255 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2257 for (i
= 0; i
< count
; ++i
)
2259 IMFMediaTypeHandler
*handler
;
2260 IMFStreamDescriptor
*sd
;
2262 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
, &selected
, &sd
)))
2264 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2265 IMFStreamDescriptor_Release(sd
);
2268 hr
= IMFMediaTypeHandler_GetMajorType(handler
, &guid
);
2269 IMFMediaTypeHandler_Release(handler
);
2272 WARN("Failed to get stream major type, hr %#lx.\n", hr
);
2276 if (IsEqualGUID(&guid
, major
))
2284 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2287 static HRESULT
create_source_reader_from_source(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2288 BOOL shutdown_on_release
, REFIID riid
, void **out
)
2290 struct source_reader
*object
;
2294 object
= calloc(1, sizeof(*object
));
2296 return E_OUTOFMEMORY
;
2298 object
->IMFSourceReader_iface
.lpVtbl
= &srcreader_vtbl
;
2299 object
->source_events_callback
.lpVtbl
= &source_events_callback_vtbl
;
2300 object
->stream_events_callback
.lpVtbl
= &stream_events_callback_vtbl
;
2301 object
->async_commands_callback
.lpVtbl
= &async_commands_callback_vtbl
;
2302 object
->public_refcount
= 1;
2303 object
->refcount
= 1;
2304 list_init(&object
->responses
);
2305 if (shutdown_on_release
)
2306 object
->flags
|= SOURCE_READER_SHUTDOWN_ON_RELEASE
;
2307 object
->source
= source
;
2308 IMFMediaSource_AddRef(object
->source
);
2309 InitializeCriticalSection(&object
->cs
);
2310 InitializeConditionVariable(&object
->sample_event
);
2311 InitializeConditionVariable(&object
->state_event
);
2312 InitializeConditionVariable(&object
->stop_event
);
2314 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(object
->source
, &object
->descriptor
)))
2317 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(object
->descriptor
, &object
->stream_count
)))
2320 if (!(object
->streams
= calloc(object
->stream_count
, sizeof(*object
->streams
))))
2326 /* Set initial current media types. */
2327 for (i
= 0; i
< object
->stream_count
; ++i
)
2329 IMFMediaTypeHandler
*handler
;
2330 IMFStreamDescriptor
*sd
;
2331 IMFMediaType
*src_type
;
2334 if (FAILED(hr
= MFCreateMediaType(&object
->streams
[i
].current
)))
2337 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(object
->descriptor
, i
, &selected
, &sd
)))
2340 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &object
->streams
[i
].id
)))
2341 WARN("Failed to get stream identifier, hr %#lx.\n", hr
);
2343 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2344 IMFStreamDescriptor_Release(sd
);
2348 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, 0, &src_type
);
2349 IMFMediaTypeHandler_Release(handler
);
2353 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)object
->streams
[i
].current
);
2354 IMFMediaType_Release(src_type
);
2358 object
->streams
[i
].reader
= object
;
2359 object
->streams
[i
].index
= i
;
2365 /* At least one major type has to be set. */
2366 object
->first_audio_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Audio
);
2367 object
->first_video_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Video
);
2369 if (object
->first_audio_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
&&
2370 object
->first_video_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
)
2372 hr
= MF_E_ATTRIBUTENOTFOUND
;
2375 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(object
->source
, &object
->source_events_callback
,
2376 (IUnknown
*)object
->source
)))
2383 object
->attributes
= attributes
;
2384 IMFAttributes_AddRef(object
->attributes
);
2386 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_ASYNC_CALLBACK
, &IID_IMFSourceReaderCallback
,
2387 (void **)&object
->async_callback
);
2388 if (object
->async_callback
)
2389 TRACE("Using async callback %p.\n", object
->async_callback
);
2391 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_D3D_MANAGER
, &IID_IUnknown
, (void **)&object
->device_manager
);
2392 if (object
->device_manager
)
2394 IUnknown
*unk
= NULL
;
2396 if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IMFDXGIDeviceManager
, (void **)&unk
)))
2397 object
->flags
|= SOURCE_READER_DXGI_DEVICE_MANAGER
;
2398 else if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IDirect3DDeviceManager9
, (void **)&unk
)))
2399 object
->flags
|= SOURCE_READER_D3D9_DEVICE_MANAGER
;
2401 if (!(object
->flags
& (SOURCE_READER_HAS_DEVICE_MANAGER
)))
2403 WARN("Unknown device manager.\n");
2404 IUnknown_Release(object
->device_manager
);
2405 object
->device_manager
= NULL
;
2409 IUnknown_Release(unk
);
2413 if (FAILED(hr
= MFLockSharedWorkQueue(L
"", 0, NULL
, &object
->queue
)))
2414 WARN("Failed to acquired shared queue, hr %#lx.\n", hr
);
2417 hr
= IMFSourceReader_QueryInterface(&object
->IMFSourceReader_iface
, riid
, out
);
2420 IMFSourceReader_Release(&object
->IMFSourceReader_iface
);
2424 static HRESULT
create_source_reader_from_stream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2425 REFIID riid
, void **out
)
2427 IPropertyStore
*props
= NULL
;
2428 IMFSourceResolver
*resolver
;
2429 MF_OBJECT_TYPE obj_type
;
2430 IMFMediaSource
*source
;
2433 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2437 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2440 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, stream
, NULL
, MF_RESOLUTION_MEDIASOURCE
2441 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE
, props
, &obj_type
, (IUnknown
**)&source
);
2442 IMFSourceResolver_Release(resolver
);
2444 IPropertyStore_Release(props
);
2448 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2449 IMFMediaSource_Release(source
);
2453 static HRESULT
create_source_reader_from_url(const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2455 IPropertyStore
*props
= NULL
;
2456 IMFSourceResolver
*resolver
;
2457 IUnknown
*object
= NULL
;
2458 MF_OBJECT_TYPE obj_type
;
2459 IMFMediaSource
*source
;
2462 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2466 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2469 hr
= IMFSourceResolver_CreateObjectFromURL(resolver
, url
, MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
,
2475 case MF_OBJECT_BYTESTREAM
:
2476 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, (IMFByteStream
*)object
, NULL
,
2477 MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
, (IUnknown
**)&source
);
2479 case MF_OBJECT_MEDIASOURCE
:
2480 source
= (IMFMediaSource
*)object
;
2481 IMFMediaSource_AddRef(source
);
2484 WARN("Unknown object type %d.\n", obj_type
);
2487 IUnknown_Release(object
);
2490 IMFSourceResolver_Release(resolver
);
2492 IPropertyStore_Release(props
);
2496 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2497 IMFMediaSource_Release(source
);
2501 static HRESULT
create_source_reader_from_object(IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2503 IMFMediaSource
*source
= NULL
;
2504 IMFByteStream
*stream
= NULL
;
2507 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSource
, (void **)&source
);
2509 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2513 UINT32 disconnect
= 0;
2516 IMFAttributes_GetUINT32(attributes
, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN
, &disconnect
);
2517 hr
= create_source_reader_from_source(source
, attributes
, !disconnect
, riid
, out
);
2520 hr
= create_source_reader_from_stream(stream
, attributes
, riid
, out
);
2523 IMFMediaSource_Release(source
);
2525 IMFByteStream_Release(stream
);
2530 /***********************************************************************
2531 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2533 HRESULT WINAPI
MFCreateSourceReaderFromByteStream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2534 IMFSourceReader
**reader
)
2536 TRACE("%p, %p, %p.\n", stream
, attributes
, reader
);
2538 return create_source_reader_from_object((IUnknown
*)stream
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2541 /***********************************************************************
2542 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2544 HRESULT WINAPI
MFCreateSourceReaderFromMediaSource(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2545 IMFSourceReader
**reader
)
2547 TRACE("%p, %p, %p.\n", source
, attributes
, reader
);
2549 return create_source_reader_from_object((IUnknown
*)source
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2552 /***********************************************************************
2553 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2555 HRESULT WINAPI
MFCreateSourceReaderFromURL(const WCHAR
*url
, IMFAttributes
*attributes
, IMFSourceReader
**reader
)
2557 TRACE("%s, %p, %p.\n", debugstr_w(url
), attributes
, reader
);
2559 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2562 static HRESULT WINAPI
readwrite_factory_QueryInterface(IMFReadWriteClassFactory
*iface
, REFIID riid
, void **out
)
2564 if (IsEqualIID(riid
, &IID_IMFReadWriteClassFactory
) ||
2565 IsEqualIID(riid
, &IID_IUnknown
))
2568 IMFReadWriteClassFactory_AddRef(iface
);
2572 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2574 return E_NOINTERFACE
;
2577 static ULONG WINAPI
readwrite_factory_AddRef(IMFReadWriteClassFactory
*iface
)
2582 static ULONG WINAPI
readwrite_factory_Release(IMFReadWriteClassFactory
*iface
)
2587 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2588 const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2590 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid
), debugstr_w(url
), attributes
, debugstr_guid(riid
), out
);
2592 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2594 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, out
);
2596 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2598 return create_sink_writer_from_url(url
, NULL
, attributes
, riid
, out
);
2601 FIXME("Unsupported %s.\n", debugstr_guid(clsid
));
2606 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2607 IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2611 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid
), unk
, attributes
, debugstr_guid(riid
), out
);
2613 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2615 return create_source_reader_from_object(unk
, attributes
, riid
, out
);
2617 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2619 IMFByteStream
*stream
= NULL
;
2620 IMFMediaSink
*sink
= NULL
;
2622 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2624 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSink
, (void **)&sink
);
2627 hr
= create_sink_writer_from_url(NULL
, stream
, attributes
, riid
, out
);
2629 hr
= create_sink_writer_from_sink(sink
, attributes
, riid
, out
);
2632 IMFMediaSink_Release(sink
);
2634 IMFByteStream_Release(stream
);
2640 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2646 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl
=
2648 readwrite_factory_QueryInterface
,
2649 readwrite_factory_AddRef
,
2650 readwrite_factory_Release
,
2651 readwrite_factory_CreateInstanceFromURL
,
2652 readwrite_factory_CreateInstanceFromObject
,
2655 static IMFReadWriteClassFactory readwrite_factory
= { &readwrite_factory_vtbl
};
2657 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **out
)
2659 TRACE("%s, %p.\n", debugstr_guid(riid
), out
);
2661 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2662 IsEqualGUID(riid
, &IID_IUnknown
))
2664 IClassFactory_AddRef(iface
);
2669 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2671 return E_NOINTERFACE
;
2674 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2679 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2684 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **out
)
2686 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), out
);
2691 return CLASS_E_NOAGGREGATION
;
2693 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory
, riid
, out
);
2696 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2698 FIXME("%d.\n", dolock
);
2702 static const IClassFactoryVtbl classfactoryvtbl
=
2704 classfactory_QueryInterface
,
2705 classfactory_AddRef
,
2706 classfactory_Release
,
2707 classfactory_CreateInstance
,
2708 classfactory_LockServer
,
2711 static IClassFactory classfactory
= { &classfactoryvtbl
};
2713 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
2715 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
2717 if (IsEqualGUID(clsid
, &CLSID_MFReadWriteClassFactory
))
2718 return IClassFactory_QueryInterface(&classfactory
, riid
, out
);
2720 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2722 return CLASS_E_CLASSNOTAVAILABLE
;