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 IMFSourceReaderEx IMFSourceReaderEx_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_IMFSourceReaderEx(IMFSourceReaderEx
*iface
)
175 return CONTAINING_RECORD(iface
, struct source_reader
, IMFSourceReaderEx_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(IMFSourceReaderEx
*iface
, REFIID riid
, void **out
)
1334 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1336 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1338 if (IsEqualGUID(riid
, &IID_IUnknown
)
1339 || IsEqualGUID(riid
, &IID_IMFSourceReader
)
1340 || IsEqualGUID(riid
, &IID_IMFSourceReaderEx
))
1342 *out
= &reader
->IMFSourceReaderEx_iface
;
1346 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1348 return E_NOINTERFACE
;
1351 IUnknown_AddRef((IUnknown
*)*out
);
1355 static ULONG WINAPI
src_reader_AddRef(IMFSourceReaderEx
*iface
)
1357 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1358 ULONG refcount
= InterlockedIncrement(&reader
->public_refcount
);
1360 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1365 static BOOL
source_reader_is_source_stopped(const struct source_reader
*reader
)
1369 if (reader
->source_state
!= SOURCE_STATE_STOPPED
)
1372 for (i
= 0; i
< reader
->stream_count
; ++i
)
1374 if (reader
->streams
[i
].stream
&& !(reader
->streams
[i
].flags
& STREAM_FLAG_STOPPED
))
1381 static ULONG WINAPI
src_reader_Release(IMFSourceReaderEx
*iface
)
1383 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1384 ULONG refcount
= InterlockedDecrement(&reader
->public_refcount
);
1387 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1391 if (reader
->flags
& SOURCE_READER_SHUTDOWN_ON_RELEASE
)
1392 IMFMediaSource_Shutdown(reader
->source
);
1393 else if (SUCCEEDED(IMFMediaSource_Stop(reader
->source
)))
1395 EnterCriticalSection(&reader
->cs
);
1397 while (!source_reader_is_source_stopped(reader
))
1399 SleepConditionVariableCS(&reader
->stop_event
, &reader
->cs
, INFINITE
);
1402 LeaveCriticalSection(&reader
->cs
);
1405 for (i
= 0; i
< reader
->stream_count
; ++i
)
1407 struct media_stream
*stream
= &reader
->streams
[i
];
1408 IMFVideoSampleAllocatorCallback
*callback
;
1410 if (!stream
->allocator
)
1413 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream
->allocator
, &IID_IMFVideoSampleAllocatorCallback
,
1414 (void **)&callback
)))
1416 IMFVideoSampleAllocatorCallback_SetCallback(callback
, NULL
);
1417 IMFVideoSampleAllocatorCallback_Release(callback
);
1421 source_reader_release(reader
);
1427 static HRESULT WINAPI
src_reader_GetStreamSelection(IMFSourceReaderEx
*iface
, DWORD index
, BOOL
*selected
)
1429 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1431 TRACE("%p, %#lx, %p.\n", iface
, index
, selected
);
1435 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1436 index
= reader
->first_video_stream_index
;
1438 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1439 index
= reader
->first_audio_stream_index
;
1445 return source_reader_get_stream_selection(reader
, index
, selected
);
1448 static HRESULT WINAPI
src_reader_SetStreamSelection(IMFSourceReaderEx
*iface
, DWORD index
, BOOL selection
)
1450 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1452 BOOL selection_changed
= FALSE
, selected
;
1455 TRACE("%p, %#lx, %d.\n", iface
, index
, selection
);
1457 selection
= !!selection
;
1459 EnterCriticalSection(&reader
->cs
);
1461 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1463 for (i
= 0; i
< reader
->stream_count
; ++i
)
1465 if (!selection_changed
)
1467 source_reader_get_stream_selection(reader
, i
, &selected
);
1468 selection_changed
= !!(selected
^ selection
);
1472 IMFPresentationDescriptor_SelectStream(reader
->descriptor
, i
);
1474 IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, i
);
1481 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1482 index
= reader
->first_video_stream_index
;
1484 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1485 index
= reader
->first_audio_stream_index
;
1491 source_reader_get_stream_selection(reader
, index
, &selected
);
1492 selection_changed
= !!(selected
^ selection
);
1495 hr
= IMFPresentationDescriptor_SelectStream(reader
->descriptor
, index
);
1497 hr
= IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, index
);
1500 if (selection_changed
)
1502 for (i
= 0; i
< reader
->stream_count
; ++i
)
1504 reader
->streams
[i
].last_sample_ts
= 0;
1508 LeaveCriticalSection(&reader
->cs
);
1510 return SUCCEEDED(hr
) ? S_OK
: MF_E_INVALIDSTREAMNUMBER
;
1513 static HRESULT
source_reader_get_native_media_type(struct source_reader
*reader
, DWORD index
, DWORD type_index
,
1514 IMFMediaType
**type
)
1516 IMFMediaTypeHandler
*handler
;
1517 IMFStreamDescriptor
*sd
;
1518 IMFMediaType
*src_type
;
1524 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1525 index
= reader
->first_video_stream_index
;
1527 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1528 index
= reader
->first_audio_stream_index
;
1534 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1535 return MF_E_INVALIDSTREAMNUMBER
;
1537 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
1538 IMFStreamDescriptor_Release(sd
);
1542 if (type_index
== MF_SOURCE_READER_CURRENT_TYPE_INDEX
)
1543 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &src_type
);
1545 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, type_index
, &src_type
);
1546 IMFMediaTypeHandler_Release(handler
);
1550 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
1551 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)*type
);
1552 IMFMediaType_Release(src_type
);
1558 static HRESULT WINAPI
src_reader_GetNativeMediaType(IMFSourceReaderEx
*iface
, DWORD index
, DWORD type_index
,
1559 IMFMediaType
**type
)
1561 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1563 TRACE("%p, %#lx, %#lx, %p.\n", iface
, index
, type_index
, type
);
1565 return source_reader_get_native_media_type(reader
, index
, type_index
, type
);
1568 static HRESULT WINAPI
src_reader_GetCurrentMediaType(IMFSourceReaderEx
*iface
, DWORD index
, IMFMediaType
**type
)
1570 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1573 TRACE("%p, %#lx, %p.\n", iface
, index
, type
);
1577 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1578 index
= reader
->first_video_stream_index
;
1580 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1581 index
= reader
->first_audio_stream_index
;
1587 if (index
>= reader
->stream_count
)
1588 return MF_E_INVALIDSTREAMNUMBER
;
1590 if (FAILED(hr
= MFCreateMediaType(type
)))
1593 EnterCriticalSection(&reader
->cs
);
1595 hr
= IMFMediaType_CopyAllItems(reader
->streams
[index
].current
, (IMFAttributes
*)*type
);
1597 LeaveCriticalSection(&reader
->cs
);
1602 static HRESULT
source_reader_get_source_type_handler(struct source_reader
*reader
, DWORD index
,
1603 IMFMediaTypeHandler
**handler
)
1605 IMFStreamDescriptor
*sd
;
1609 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1612 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, handler
);
1613 IMFStreamDescriptor_Release(sd
);
1618 static HRESULT
source_reader_set_compatible_media_type(struct source_reader
*reader
, DWORD index
, IMFMediaType
*type
)
1620 IMFMediaTypeHandler
*type_handler
;
1621 IMFMediaType
*native_type
;
1622 BOOL type_set
= FALSE
;
1627 if (FAILED(hr
= IMFMediaType_IsEqual(type
, reader
->streams
[index
].current
, &flags
)))
1630 if (!(flags
& MF_MEDIATYPE_EQUAL_MAJOR_TYPES
))
1631 return MF_E_INVALIDMEDIATYPE
;
1633 /* No need for a decoder or type change. */
1634 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_DATA
)
1637 if (FAILED(hr
= source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1640 while (!type_set
&& IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler
, i
++, &native_type
) == S_OK
)
1642 static const DWORD compare_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_DATA
;
1644 if (SUCCEEDED(IMFMediaType_IsEqual(native_type
, type
, &flags
)) && (flags
& compare_flags
) == compare_flags
)
1646 if ((type_set
= SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, native_type
))))
1647 IMFMediaType_CopyAllItems(native_type
, (IMFAttributes
*)reader
->streams
[index
].current
);
1650 IMFMediaType_Release(native_type
);
1653 IMFMediaTypeHandler_Release(type_handler
);
1655 return type_set
? S_OK
: S_FALSE
;
1658 static HRESULT
source_reader_create_sample_allocator_attributes(const struct source_reader
*reader
,
1659 IMFAttributes
**attributes
)
1661 UINT32 shared
= 0, shared_without_mutex
= 0;
1664 if (FAILED(hr
= MFCreateAttributes(attributes
, 1)))
1667 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED
, &shared
);
1668 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, &shared_without_mutex
);
1670 if (shared_without_mutex
)
1671 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, TRUE
);
1673 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED
, TRUE
);
1678 static HRESULT
source_reader_setup_sample_allocator(struct source_reader
*reader
, unsigned int index
)
1680 struct media_stream
*stream
= &reader
->streams
[index
];
1681 IMFAttributes
*attributes
= NULL
;
1685 IMFMediaType_GetMajorType(stream
->current
, &major
);
1686 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
1689 if (!(reader
->flags
& SOURCE_READER_HAS_DEVICE_MANAGER
))
1692 if (!stream
->allocator
)
1694 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&stream
->allocator
)))
1696 WARN("Failed to create sample allocator, hr %#lx.\n", hr
);
1701 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream
->allocator
);
1702 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(stream
->allocator
, reader
->device_manager
)))
1704 WARN("Failed to set device manager, hr %#lx.\n", hr
);
1708 if (FAILED(hr
= source_reader_create_sample_allocator_attributes(reader
, &attributes
)))
1709 WARN("Failed to create allocator attributes, hr %#lx.\n", hr
);
1711 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream
->allocator
, 2, 8,
1712 attributes
, stream
->current
)))
1714 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr
);
1718 IMFAttributes_Release(attributes
);
1723 static HRESULT
source_reader_configure_decoder(struct source_reader
*reader
, DWORD index
, const CLSID
*clsid
,
1724 IMFMediaType
*input_type
, IMFMediaType
*output_type
)
1726 IMFMediaTypeHandler
*type_handler
;
1727 unsigned int block_alignment
= 0;
1728 IMFTransform
*transform
= NULL
;
1729 IMFMediaType
*type
= NULL
;
1735 if (FAILED(hr
= CoCreateInstance(clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTransform
, (void **)&transform
)))
1737 WARN("Failed to create transform object, hr %#lx.\n", hr
);
1741 if (FAILED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0)))
1743 WARN("Failed to set decoder input type, hr %#lx.\n", hr
);
1744 IMFTransform_Release(transform
);
1748 /* Find the relevant output type. */
1749 while (IMFTransform_GetOutputAvailableType(transform
, 0, i
++, &type
) == S_OK
)
1753 if (SUCCEEDED(IMFMediaType_IsEqual(type
, output_type
, &flags
)))
1755 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_TYPES
)
1757 if (SUCCEEDED(IMFTransform_SetOutputType(transform
, 0, type
, 0)))
1759 if (SUCCEEDED(source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1761 IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, input_type
);
1762 IMFMediaTypeHandler_Release(type_handler
);
1765 if (FAILED(hr
= IMFMediaType_CopyAllItems(type
, (IMFAttributes
*)reader
->streams
[index
].current
)))
1766 WARN("Failed to copy attributes, hr %#lx.\n", hr
);
1767 if (SUCCEEDED(IMFMediaType_GetMajorType(type
, &major
)) && IsEqualGUID(&major
, &MFMediaType_Audio
))
1768 IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
);
1769 IMFMediaType_Release(type
);
1771 if (reader
->streams
[index
].decoder
.transform
)
1772 IMFTransform_Release(reader
->streams
[index
].decoder
.transform
);
1774 reader
->streams
[index
].decoder
.transform
= transform
;
1775 reader
->streams
[index
].decoder
.min_buffer_size
= block_alignment
;
1782 IMFMediaType_Release(type
);
1785 WARN("Failed to find suitable decoder output type.\n");
1787 IMFTransform_Release(transform
);
1789 return MF_E_TOPO_CODEC_NOT_FOUND
;
1792 static HRESULT
source_reader_create_decoder_for_stream(struct source_reader
*reader
, DWORD index
, IMFMediaType
*output_type
)
1794 MFT_REGISTER_TYPE_INFO in_type
, out_type
;
1795 CLSID
*clsids
, mft_clsid
, category
;
1796 unsigned int i
= 0, count
;
1797 IMFMediaType
*input_type
;
1800 /* TODO: should we check if the source type is compressed? */
1802 if (FAILED(hr
= IMFMediaType_GetMajorType(output_type
, &out_type
.guidMajorType
)))
1805 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
))
1807 category
= MFT_CATEGORY_VIDEO_DECODER
;
1809 else if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1811 category
= MFT_CATEGORY_AUDIO_DECODER
;
1815 WARN("Unhandled major type %s.\n", debugstr_guid(&out_type
.guidMajorType
));
1816 return MF_E_TOPO_CODEC_NOT_FOUND
;
1819 if (FAILED(hr
= IMFMediaType_GetGUID(output_type
, &MF_MT_SUBTYPE
, &out_type
.guidSubtype
)))
1822 in_type
.guidMajorType
= out_type
.guidMajorType
;
1824 while (source_reader_get_native_media_type(reader
, index
, i
++, &input_type
) == S_OK
)
1826 if (SUCCEEDED(IMFMediaType_GetGUID(input_type
, &MF_MT_SUBTYPE
, &in_type
.guidSubtype
)))
1829 if (SUCCEEDED(hr
= MFTEnum(category
, 0, &in_type
, &out_type
, NULL
, &clsids
, &count
)) && count
)
1831 mft_clsid
= clsids
[0];
1832 CoTaskMemFree(clsids
);
1834 /* TODO: Should we iterate over all of them? */
1835 if (SUCCEEDED(source_reader_configure_decoder(reader
, index
, &mft_clsid
, input_type
, output_type
)))
1837 IMFMediaType_Release(input_type
);
1844 IMFMediaType_Release(input_type
);
1847 return MF_E_TOPO_CODEC_NOT_FOUND
;
1850 static HRESULT WINAPI
src_reader_SetCurrentMediaType(IMFSourceReaderEx
*iface
, DWORD index
, DWORD
*reserved
,
1853 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1856 TRACE("%p, %#lx, %p, %p.\n", iface
, index
, reserved
, type
);
1860 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1861 index
= reader
->first_video_stream_index
;
1863 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1864 index
= reader
->first_audio_stream_index
;
1870 if (index
>= reader
->stream_count
)
1871 return MF_E_INVALIDSTREAMNUMBER
;
1873 /* FIXME: setting the output type while streaming should trigger a flush */
1875 EnterCriticalSection(&reader
->cs
);
1877 hr
= source_reader_set_compatible_media_type(reader
, index
, type
);
1879 hr
= source_reader_create_decoder_for_stream(reader
, index
, type
);
1881 hr
= source_reader_setup_sample_allocator(reader
, index
);
1883 LeaveCriticalSection(&reader
->cs
);
1888 static HRESULT WINAPI
src_reader_SetCurrentPosition(IMFSourceReaderEx
*iface
, REFGUID format
, REFPROPVARIANT position
)
1890 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1891 struct source_reader_async_command
*command
;
1896 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), position
);
1898 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
1901 if (!(flags
& MFMEDIASOURCE_CAN_SEEK
))
1902 return MF_E_INVALIDREQUEST
;
1904 EnterCriticalSection(&reader
->cs
);
1906 /* Check if we got pending requests. */
1907 for (i
= 0; i
< reader
->stream_count
; ++i
)
1909 if (reader
->streams
[i
].requests
)
1911 hr
= MF_E_INVALIDREQUEST
;
1918 for (i
= 0; i
< reader
->stream_count
; ++i
)
1920 reader
->streams
[i
].last_sample_ts
= 0;
1923 if (reader
->async_callback
)
1925 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK
, &command
)))
1927 command
->u
.seek
.format
= *format
;
1928 PropVariantCopy(&command
->u
.seek
.position
, position
);
1930 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
1931 IUnknown_Release(&command
->IUnknown_iface
);
1936 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, format
, position
)))
1938 reader
->flags
|= SOURCE_READER_SEEKING
;
1939 while (reader
->flags
& SOURCE_READER_SEEKING
)
1941 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
1947 LeaveCriticalSection(&reader
->cs
);
1952 static HRESULT
source_reader_read_sample(struct source_reader
*reader
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
1953 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1955 struct media_stream
*stream
;
1956 DWORD actual_index_tmp
;
1957 LONGLONG timestamp_tmp
;
1961 if (!stream_flags
|| !sample
)
1967 timestamp
= ×tamp_tmp
;
1970 actual_index
= &actual_index_tmp
;
1972 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1974 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, index
, &stream_index
)))
1976 *actual_index
= stream_index
;
1978 stream
= &reader
->streams
[stream_index
];
1980 if (!source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
1983 while (!source_reader_got_response_for_stream(reader
, stream
) && stream
->state
!= STREAM_STATE_EOS
)
1986 if (FAILED(hr
= source_reader_request_sample(reader
, stream
)))
1987 WARN("Failed to request a sample, hr %#lx.\n", hr
);
1988 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
1990 *stream_flags
= MF_SOURCE_READERF_ERROR
;
1994 SleepConditionVariableCS(&reader
->sample_event
, &reader
->cs
, INFINITE
);
1997 source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
2003 *actual_index
= index
;
2004 *stream_flags
= MF_SOURCE_READERF_ERROR
;
2009 TRACE("Stream %lu, got sample %p, flags %#lx.\n", *actual_index
, *sample
, *stream_flags
);
2014 static HRESULT
source_reader_read_sample_async(struct source_reader
*reader
, unsigned int index
, unsigned int flags
,
2015 DWORD
*actual_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2017 struct source_reader_async_command
*command
;
2020 if (actual_index
|| stream_flags
|| timestamp
|| sample
)
2021 return E_INVALIDARG
;
2023 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2024 hr
= MF_E_NOTACCEPTING
;
2027 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_READ
, &command
)))
2029 command
->u
.read
.stream_index
= index
;
2030 command
->u
.read
.flags
= flags
;
2032 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2033 IUnknown_Release(&command
->IUnknown_iface
);
2040 static HRESULT WINAPI
src_reader_ReadSample(IMFSourceReaderEx
*iface
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
2041 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2043 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2046 TRACE("%p, %#lx, %#lx, %p, %p, %p, %p\n", iface
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2048 EnterCriticalSection(&reader
->cs
);
2050 while (reader
->flags
& SOURCE_READER_SEEKING
)
2052 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2055 if (reader
->async_callback
)
2056 hr
= source_reader_read_sample_async(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2058 hr
= source_reader_read_sample(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2060 LeaveCriticalSection(&reader
->cs
);
2065 static HRESULT
source_reader_flush_async(struct source_reader
*reader
, unsigned int index
)
2067 struct source_reader_async_command
*command
;
2068 unsigned int stream_index
;
2071 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2072 return MF_E_INVALIDREQUEST
;
2076 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2077 stream_index
= reader
->first_video_stream_index
;
2079 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2080 stream_index
= reader
->first_audio_stream_index
;
2083 stream_index
= index
;
2086 reader
->flags
|= SOURCE_READER_FLUSHING
;
2088 if (stream_index
!= MF_SOURCE_READER_ALL_STREAMS
&& stream_index
>= reader
->stream_count
)
2089 return MF_E_INVALIDSTREAMNUMBER
;
2091 if (FAILED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH
, &command
)))
2094 command
->u
.flush
.stream_index
= stream_index
;
2096 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2097 IUnknown_Release(&command
->IUnknown_iface
);
2102 static HRESULT WINAPI
src_reader_Flush(IMFSourceReaderEx
*iface
, DWORD index
)
2104 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2107 TRACE("%p, %#lx.\n", iface
, index
);
2109 EnterCriticalSection(&reader
->cs
);
2111 if (reader
->async_callback
)
2112 hr
= source_reader_flush_async(reader
, index
);
2114 hr
= source_reader_flush(reader
, index
);
2116 LeaveCriticalSection(&reader
->cs
);
2121 static HRESULT WINAPI
src_reader_GetServiceForStream(IMFSourceReaderEx
*iface
, DWORD index
, REFGUID service
,
2122 REFIID riid
, void **object
)
2124 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2125 IUnknown
*obj
= NULL
;
2128 TRACE("%p, %#lx, %s, %s, %p\n", iface
, index
, debugstr_guid(service
), debugstr_guid(riid
), object
);
2130 EnterCriticalSection(&reader
->cs
);
2134 case MF_SOURCE_READER_MEDIASOURCE
:
2135 obj
= (IUnknown
*)reader
->source
;
2138 if (index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2139 index
= reader
->first_video_stream_index
;
2140 else if (index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2141 index
= reader
->first_audio_stream_index
;
2143 if (index
>= reader
->stream_count
)
2144 hr
= MF_E_INVALIDSTREAMNUMBER
;
2147 obj
= (IUnknown
*)reader
->streams
[index
].decoder
.transform
;
2148 if (!obj
) hr
= E_NOINTERFACE
;
2154 IUnknown_AddRef(obj
);
2156 LeaveCriticalSection(&reader
->cs
);
2160 if (IsEqualGUID(service
, &GUID_NULL
))
2162 hr
= IUnknown_QueryInterface(obj
, riid
, object
);
2168 hr
= IUnknown_QueryInterface(obj
, &IID_IMFGetService
, (void **)&gs
);
2171 hr
= IMFGetService_GetService(gs
, service
, riid
, object
);
2172 IMFGetService_Release(gs
);
2178 IUnknown_Release(obj
);
2183 static HRESULT WINAPI
src_reader_GetPresentationAttribute(IMFSourceReaderEx
*iface
, DWORD index
,
2184 REFGUID guid
, PROPVARIANT
*value
)
2186 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2187 IMFStreamDescriptor
*sd
;
2191 TRACE("%p, %#lx, %s, %p.\n", iface
, index
, debugstr_guid(guid
), value
);
2195 case MF_SOURCE_READER_MEDIASOURCE
:
2196 if (IsEqualGUID(guid
, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS
))
2200 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2204 value
->ulVal
= flags
;
2209 return IMFPresentationDescriptor_GetItem(reader
->descriptor
, guid
, value
);
2212 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2213 index
= reader
->first_video_stream_index
;
2215 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2216 index
= reader
->first_audio_stream_index
;
2222 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
2225 hr
= IMFStreamDescriptor_GetItem(sd
, guid
, value
);
2226 IMFStreamDescriptor_Release(sd
);
2231 static HRESULT WINAPI
src_reader_SetNativeMediaType(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2232 IMFMediaType
*media_type
, DWORD
*stream_flags
)
2234 FIXME("%p, %#lx, %p, %p.\n", iface
, stream_index
, media_type
, stream_flags
);
2239 static HRESULT WINAPI
src_reader_AddTransformForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2240 IUnknown
*transform
)
2242 FIXME("%p, %#lx, %p.\n", iface
, stream_index
, transform
);
2247 static HRESULT WINAPI
src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
)
2249 FIXME("%p, %#lx.\n", iface
, stream_index
);
2254 static HRESULT WINAPI
src_reader_GetTransformForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2255 DWORD transform_index
, GUID
*category
, IMFTransform
**transform
)
2257 FIXME("%p, %#lx, %#lx, %p, %p.\n", iface
, stream_index
, transform_index
, category
, transform
);
2262 static const IMFSourceReaderExVtbl srcreader_vtbl
=
2264 src_reader_QueryInterface
,
2267 src_reader_GetStreamSelection
,
2268 src_reader_SetStreamSelection
,
2269 src_reader_GetNativeMediaType
,
2270 src_reader_GetCurrentMediaType
,
2271 src_reader_SetCurrentMediaType
,
2272 src_reader_SetCurrentPosition
,
2273 src_reader_ReadSample
,
2275 src_reader_GetServiceForStream
,
2276 src_reader_GetPresentationAttribute
,
2277 src_reader_SetNativeMediaType
,
2278 src_reader_AddTransformForStream
,
2279 src_reader_RemoveAllTransformsForStream
,
2280 src_reader_GetTransformForStream
,
2283 static DWORD
reader_get_first_stream_index(IMFPresentationDescriptor
*descriptor
, const GUID
*major
)
2290 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
2291 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2293 for (i
= 0; i
< count
; ++i
)
2295 IMFMediaTypeHandler
*handler
;
2296 IMFStreamDescriptor
*sd
;
2298 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
, &selected
, &sd
)))
2300 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2301 IMFStreamDescriptor_Release(sd
);
2304 hr
= IMFMediaTypeHandler_GetMajorType(handler
, &guid
);
2305 IMFMediaTypeHandler_Release(handler
);
2308 WARN("Failed to get stream major type, hr %#lx.\n", hr
);
2312 if (IsEqualGUID(&guid
, major
))
2320 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2323 static HRESULT
create_source_reader_from_source(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2324 BOOL shutdown_on_release
, REFIID riid
, void **out
)
2326 struct source_reader
*object
;
2330 object
= calloc(1, sizeof(*object
));
2332 return E_OUTOFMEMORY
;
2334 object
->IMFSourceReaderEx_iface
.lpVtbl
= &srcreader_vtbl
;
2335 object
->source_events_callback
.lpVtbl
= &source_events_callback_vtbl
;
2336 object
->stream_events_callback
.lpVtbl
= &stream_events_callback_vtbl
;
2337 object
->async_commands_callback
.lpVtbl
= &async_commands_callback_vtbl
;
2338 object
->public_refcount
= 1;
2339 object
->refcount
= 1;
2340 list_init(&object
->responses
);
2341 if (shutdown_on_release
)
2342 object
->flags
|= SOURCE_READER_SHUTDOWN_ON_RELEASE
;
2343 object
->source
= source
;
2344 IMFMediaSource_AddRef(object
->source
);
2345 InitializeCriticalSection(&object
->cs
);
2346 InitializeConditionVariable(&object
->sample_event
);
2347 InitializeConditionVariable(&object
->state_event
);
2348 InitializeConditionVariable(&object
->stop_event
);
2350 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(object
->source
, &object
->descriptor
)))
2353 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(object
->descriptor
, &object
->stream_count
)))
2356 if (!(object
->streams
= calloc(object
->stream_count
, sizeof(*object
->streams
))))
2362 /* Set initial current media types. */
2363 for (i
= 0; i
< object
->stream_count
; ++i
)
2365 IMFMediaTypeHandler
*handler
;
2366 IMFStreamDescriptor
*sd
;
2367 IMFMediaType
*src_type
;
2370 if (FAILED(hr
= MFCreateMediaType(&object
->streams
[i
].current
)))
2373 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(object
->descriptor
, i
, &selected
, &sd
)))
2376 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &object
->streams
[i
].id
)))
2377 WARN("Failed to get stream identifier, hr %#lx.\n", hr
);
2379 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2380 IMFStreamDescriptor_Release(sd
);
2384 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, 0, &src_type
);
2385 IMFMediaTypeHandler_Release(handler
);
2389 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)object
->streams
[i
].current
);
2390 IMFMediaType_Release(src_type
);
2394 object
->streams
[i
].reader
= object
;
2395 object
->streams
[i
].index
= i
;
2401 /* At least one major type has to be set. */
2402 object
->first_audio_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Audio
);
2403 object
->first_video_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Video
);
2405 if (object
->first_audio_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
&&
2406 object
->first_video_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
)
2408 hr
= MF_E_ATTRIBUTENOTFOUND
;
2411 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(object
->source
, &object
->source_events_callback
,
2412 (IUnknown
*)object
->source
)))
2419 object
->attributes
= attributes
;
2420 IMFAttributes_AddRef(object
->attributes
);
2422 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_ASYNC_CALLBACK
, &IID_IMFSourceReaderCallback
,
2423 (void **)&object
->async_callback
);
2424 if (object
->async_callback
)
2425 TRACE("Using async callback %p.\n", object
->async_callback
);
2427 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_D3D_MANAGER
, &IID_IUnknown
, (void **)&object
->device_manager
);
2428 if (object
->device_manager
)
2430 IUnknown
*unk
= NULL
;
2432 if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IMFDXGIDeviceManager
, (void **)&unk
)))
2433 object
->flags
|= SOURCE_READER_DXGI_DEVICE_MANAGER
;
2434 else if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IDirect3DDeviceManager9
, (void **)&unk
)))
2435 object
->flags
|= SOURCE_READER_D3D9_DEVICE_MANAGER
;
2437 if (!(object
->flags
& (SOURCE_READER_HAS_DEVICE_MANAGER
)))
2439 WARN("Unknown device manager.\n");
2440 IUnknown_Release(object
->device_manager
);
2441 object
->device_manager
= NULL
;
2445 IUnknown_Release(unk
);
2449 if (FAILED(hr
= MFLockSharedWorkQueue(L
"", 0, NULL
, &object
->queue
)))
2450 WARN("Failed to acquired shared queue, hr %#lx.\n", hr
);
2453 hr
= IMFSourceReaderEx_QueryInterface(&object
->IMFSourceReaderEx_iface
, riid
, out
);
2456 IMFSourceReaderEx_Release(&object
->IMFSourceReaderEx_iface
);
2460 static HRESULT
create_source_reader_from_stream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2461 REFIID riid
, void **out
)
2463 IPropertyStore
*props
= NULL
;
2464 IMFSourceResolver
*resolver
;
2465 MF_OBJECT_TYPE obj_type
;
2466 IMFMediaSource
*source
;
2469 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2473 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2476 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, stream
, NULL
, MF_RESOLUTION_MEDIASOURCE
2477 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE
, props
, &obj_type
, (IUnknown
**)&source
);
2478 IMFSourceResolver_Release(resolver
);
2480 IPropertyStore_Release(props
);
2484 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2485 IMFMediaSource_Release(source
);
2489 static HRESULT
create_source_reader_from_url(const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2491 IPropertyStore
*props
= NULL
;
2492 IMFSourceResolver
*resolver
;
2493 IUnknown
*object
= NULL
;
2494 MF_OBJECT_TYPE obj_type
;
2495 IMFMediaSource
*source
;
2498 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2502 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2505 hr
= IMFSourceResolver_CreateObjectFromURL(resolver
, url
, MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
,
2511 case MF_OBJECT_BYTESTREAM
:
2512 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, (IMFByteStream
*)object
, NULL
,
2513 MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
, (IUnknown
**)&source
);
2515 case MF_OBJECT_MEDIASOURCE
:
2516 source
= (IMFMediaSource
*)object
;
2517 IMFMediaSource_AddRef(source
);
2520 WARN("Unknown object type %d.\n", obj_type
);
2523 IUnknown_Release(object
);
2526 IMFSourceResolver_Release(resolver
);
2528 IPropertyStore_Release(props
);
2532 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2533 IMFMediaSource_Release(source
);
2537 static HRESULT
create_source_reader_from_object(IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2539 IMFMediaSource
*source
= NULL
;
2540 IMFByteStream
*stream
= NULL
;
2543 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSource
, (void **)&source
);
2545 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2549 UINT32 disconnect
= 0;
2552 IMFAttributes_GetUINT32(attributes
, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN
, &disconnect
);
2553 hr
= create_source_reader_from_source(source
, attributes
, !disconnect
, riid
, out
);
2556 hr
= create_source_reader_from_stream(stream
, attributes
, riid
, out
);
2559 IMFMediaSource_Release(source
);
2561 IMFByteStream_Release(stream
);
2566 /***********************************************************************
2567 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2569 HRESULT WINAPI
MFCreateSourceReaderFromByteStream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2570 IMFSourceReader
**reader
)
2572 TRACE("%p, %p, %p.\n", stream
, attributes
, reader
);
2574 return create_source_reader_from_object((IUnknown
*)stream
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2577 /***********************************************************************
2578 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2580 HRESULT WINAPI
MFCreateSourceReaderFromMediaSource(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2581 IMFSourceReader
**reader
)
2583 TRACE("%p, %p, %p.\n", source
, attributes
, reader
);
2585 return create_source_reader_from_object((IUnknown
*)source
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2588 /***********************************************************************
2589 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2591 HRESULT WINAPI
MFCreateSourceReaderFromURL(const WCHAR
*url
, IMFAttributes
*attributes
, IMFSourceReader
**reader
)
2593 TRACE("%s, %p, %p.\n", debugstr_w(url
), attributes
, reader
);
2595 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2598 static HRESULT WINAPI
readwrite_factory_QueryInterface(IMFReadWriteClassFactory
*iface
, REFIID riid
, void **out
)
2600 if (IsEqualIID(riid
, &IID_IMFReadWriteClassFactory
) ||
2601 IsEqualIID(riid
, &IID_IUnknown
))
2604 IMFReadWriteClassFactory_AddRef(iface
);
2608 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2610 return E_NOINTERFACE
;
2613 static ULONG WINAPI
readwrite_factory_AddRef(IMFReadWriteClassFactory
*iface
)
2618 static ULONG WINAPI
readwrite_factory_Release(IMFReadWriteClassFactory
*iface
)
2623 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2624 const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2626 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid
), debugstr_w(url
), attributes
, debugstr_guid(riid
), out
);
2628 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2630 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, out
);
2632 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2634 return create_sink_writer_from_url(url
, NULL
, attributes
, riid
, out
);
2637 FIXME("Unsupported %s.\n", debugstr_guid(clsid
));
2642 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2643 IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2647 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid
), unk
, attributes
, debugstr_guid(riid
), out
);
2649 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2651 return create_source_reader_from_object(unk
, attributes
, riid
, out
);
2653 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2655 IMFByteStream
*stream
= NULL
;
2656 IMFMediaSink
*sink
= NULL
;
2658 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2660 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSink
, (void **)&sink
);
2663 hr
= create_sink_writer_from_url(NULL
, stream
, attributes
, riid
, out
);
2665 hr
= create_sink_writer_from_sink(sink
, attributes
, riid
, out
);
2668 IMFMediaSink_Release(sink
);
2670 IMFByteStream_Release(stream
);
2676 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2682 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl
=
2684 readwrite_factory_QueryInterface
,
2685 readwrite_factory_AddRef
,
2686 readwrite_factory_Release
,
2687 readwrite_factory_CreateInstanceFromURL
,
2688 readwrite_factory_CreateInstanceFromObject
,
2691 static IMFReadWriteClassFactory readwrite_factory
= { &readwrite_factory_vtbl
};
2693 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **out
)
2695 TRACE("%s, %p.\n", debugstr_guid(riid
), out
);
2697 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2698 IsEqualGUID(riid
, &IID_IUnknown
))
2700 IClassFactory_AddRef(iface
);
2705 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2707 return E_NOINTERFACE
;
2710 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2715 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2720 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **out
)
2722 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), out
);
2727 return CLASS_E_NOAGGREGATION
;
2729 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory
, riid
, out
);
2732 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2734 FIXME("%d.\n", dolock
);
2738 static const IClassFactoryVtbl classfactoryvtbl
=
2740 classfactory_QueryInterface
,
2741 classfactory_AddRef
,
2742 classfactory_Release
,
2743 classfactory_CreateInstance
,
2744 classfactory_LockServer
,
2747 static IClassFactory classfactory
= { &classfactoryvtbl
};
2749 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
2751 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
2753 if (IsEqualGUID(clsid
, &CLSID_MFReadWriteClassFactory
))
2754 return IClassFactory_QueryInterface(&classfactory
, riid
, out
);
2756 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2758 return CLASS_E_CLASSNOTAVAILABLE
;