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 DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32
, D3DFMT_A8B8G8R8
);
46 struct stream_response
56 enum media_stream_state
58 STREAM_STATE_READY
= 0,
62 enum media_source_state
64 SOURCE_STATE_STOPPED
= 0,
68 enum media_stream_flags
70 STREAM_FLAG_SAMPLE_REQUESTED
= 0x1, /* Protects from making multiple sample requests. */
71 STREAM_FLAG_SELECTED
= 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
72 STREAM_FLAG_PRESENTED
= 0x4, /* Set if stream was selected last time Start() was called. */
73 STREAM_FLAG_STOPPED
= 0x8, /* Received MEStreamStopped */
76 struct transform_entry
79 IMFTransform
*transform
;
80 unsigned int min_buffer_size
;
84 BOOL attributes_initialized
;
89 IMFMediaStream
*stream
;
90 IMFMediaType
*current
;
91 struct list transforms
;
92 IMFVideoSampleAllocatorEx
*allocator
;
93 IMFTransform
*transform_service
;
96 enum media_stream_state state
;
98 unsigned int requests
;
99 unsigned int responses
;
100 LONGLONG last_sample_ts
;
101 struct source_reader
*reader
;
104 enum source_reader_async_op
106 SOURCE_READER_ASYNC_READ
,
107 SOURCE_READER_ASYNC_SEEK
,
108 SOURCE_READER_ASYNC_FLUSH
,
109 SOURCE_READER_ASYNC_SAMPLE_READY
,
112 struct source_reader_async_command
114 IUnknown IUnknown_iface
;
116 enum source_reader_async_op op
;
122 unsigned int stream_index
;
127 PROPVARIANT position
;
131 unsigned int stream_index
;
135 unsigned int stream_index
;
139 unsigned int stream_index
;
144 enum source_reader_flags
146 SOURCE_READER_FLUSHING
= 0x1,
147 SOURCE_READER_SEEKING
= 0x2,
148 SOURCE_READER_SHUTDOWN_ON_RELEASE
= 0x4,
149 SOURCE_READER_D3D9_DEVICE_MANAGER
= 0x8,
150 SOURCE_READER_DXGI_DEVICE_MANAGER
= 0x10,
151 SOURCE_READER_HAS_DEVICE_MANAGER
= SOURCE_READER_D3D9_DEVICE_MANAGER
| SOURCE_READER_DXGI_DEVICE_MANAGER
,
156 IMFSourceReaderEx IMFSourceReaderEx_iface
;
157 IMFAsyncCallback source_events_callback
;
158 IMFAsyncCallback stream_events_callback
;
159 IMFAsyncCallback async_commands_callback
;
161 LONG public_refcount
;
162 IMFMediaSource
*source
;
163 IMFPresentationDescriptor
*descriptor
;
164 IMFSourceReaderCallback
*async_callback
;
165 IMFAttributes
*attributes
;
166 IUnknown
*device_manager
;
167 unsigned int first_audio_stream_index
;
168 unsigned int first_video_stream_index
;
172 enum media_source_state source_state
;
173 struct media_stream
*streams
;
174 struct list responses
;
176 CONDITION_VARIABLE sample_event
;
177 CONDITION_VARIABLE state_event
;
178 CONDITION_VARIABLE stop_event
;
181 static inline struct source_reader
*impl_from_IMFSourceReaderEx(IMFSourceReaderEx
*iface
)
183 return CONTAINING_RECORD(iface
, struct source_reader
, IMFSourceReaderEx_iface
);
186 static struct source_reader
*impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
188 return CONTAINING_RECORD(iface
, struct source_reader
, source_events_callback
);
191 static struct source_reader
*impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
193 return CONTAINING_RECORD(iface
, struct source_reader
, stream_events_callback
);
196 static struct source_reader
*impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
198 return CONTAINING_RECORD(iface
, struct source_reader
, async_commands_callback
);
201 static struct source_reader_async_command
*impl_from_async_command_IUnknown(IUnknown
*iface
)
203 return CONTAINING_RECORD(iface
, struct source_reader_async_command
, IUnknown_iface
);
206 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
);
208 static ULONG
source_reader_addref(struct source_reader
*reader
)
210 return InterlockedIncrement(&reader
->refcount
);
213 static void transform_entry_destroy(struct transform_entry
*entry
)
215 IMFTransform_Release(entry
->transform
);
219 static void media_stream_destroy(struct media_stream
*stream
)
221 struct transform_entry
*entry
, *next
;
223 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &stream
->transforms
, struct transform_entry
, entry
)
225 list_remove(&entry
->entry
);
226 transform_entry_destroy(entry
);
229 if (stream
->transform_service
)
230 IMFTransform_Release(stream
->transform_service
);
232 IMFMediaStream_Release(stream
->stream
);
234 IMFMediaType_Release(stream
->current
);
235 if (stream
->allocator
)
236 IMFVideoSampleAllocatorEx_Release(stream
->allocator
);
239 static ULONG
source_reader_release(struct source_reader
*reader
)
241 ULONG refcount
= InterlockedDecrement(&reader
->refcount
);
246 if (reader
->device_manager
)
247 IUnknown_Release(reader
->device_manager
);
248 if (reader
->async_callback
)
249 IMFSourceReaderCallback_Release(reader
->async_callback
);
250 if (reader
->descriptor
)
251 IMFPresentationDescriptor_Release(reader
->descriptor
);
252 if (reader
->attributes
)
253 IMFAttributes_Release(reader
->attributes
);
254 IMFMediaSource_Release(reader
->source
);
256 for (i
= 0; i
< reader
->stream_count
; ++i
)
258 struct media_stream
*stream
= &reader
->streams
[i
];
259 media_stream_destroy(stream
);
261 source_reader_release_responses(reader
, NULL
);
262 free(reader
->streams
);
263 DeleteCriticalSection(&reader
->cs
);
270 static HRESULT WINAPI
source_reader_async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
272 if (IsEqualIID(riid
, &IID_IUnknown
))
275 IUnknown_AddRef(iface
);
279 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
281 return E_NOINTERFACE
;
284 static ULONG WINAPI
source_reader_async_command_AddRef(IUnknown
*iface
)
286 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
287 return InterlockedIncrement(&command
->refcount
);
290 static ULONG WINAPI
source_reader_async_command_Release(IUnknown
*iface
)
292 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
293 ULONG refcount
= InterlockedIncrement(&command
->refcount
);
297 if (command
->op
== SOURCE_READER_ASYNC_SEEK
)
298 PropVariantClear(&command
->u
.seek
.position
);
305 static const IUnknownVtbl source_reader_async_command_vtbl
=
307 source_reader_async_command_QueryInterface
,
308 source_reader_async_command_AddRef
,
309 source_reader_async_command_Release
,
312 static HRESULT
source_reader_create_async_op(enum source_reader_async_op op
, struct source_reader_async_command
**ret
)
314 struct source_reader_async_command
*command
;
316 if (!(command
= calloc(1, sizeof(*command
))))
317 return E_OUTOFMEMORY
;
319 command
->IUnknown_iface
.lpVtbl
= &source_reader_async_command_vtbl
;
327 static HRESULT
media_event_get_object(IMFMediaEvent
*event
, REFIID riid
, void **obj
)
332 PropVariantInit(&value
);
333 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
335 WARN("Failed to get event value, hr %#lx.\n", hr
);
339 if (value
.vt
!= VT_UNKNOWN
|| !value
.punkVal
)
341 WARN("Unexpected value type %d.\n", value
.vt
);
342 PropVariantClear(&value
);
346 hr
= IUnknown_QueryInterface(value
.punkVal
, riid
, obj
);
347 PropVariantClear(&value
);
350 WARN("Unexpected object type.\n");
357 static HRESULT
media_stream_get_id(IMFMediaStream
*stream
, DWORD
*id
)
359 IMFStreamDescriptor
*sd
;
362 if (SUCCEEDED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
364 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, id
);
365 IMFStreamDescriptor_Release(sd
);
371 static HRESULT WINAPI
source_reader_callback_QueryInterface(IMFAsyncCallback
*iface
,
372 REFIID riid
, void **obj
)
374 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
376 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
377 IsEqualIID(riid
, &IID_IUnknown
))
380 IMFAsyncCallback_AddRef(iface
);
384 WARN("Unsupported %s.\n", debugstr_guid(riid
));
386 return E_NOINTERFACE
;
389 static ULONG WINAPI
source_reader_source_events_callback_AddRef(IMFAsyncCallback
*iface
)
391 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
392 return source_reader_addref(reader
);
395 static ULONG WINAPI
source_reader_source_events_callback_Release(IMFAsyncCallback
*iface
)
397 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
398 return source_reader_release(reader
);
401 static HRESULT WINAPI
source_reader_callback_GetParameters(IMFAsyncCallback
*iface
,
402 DWORD
*flags
, DWORD
*queue
)
407 static void source_reader_response_ready(struct source_reader
*reader
, struct stream_response
*response
)
409 struct source_reader_async_command
*command
;
410 struct media_stream
*stream
= &reader
->streams
[response
->stream_index
];
413 if (!stream
->requests
)
416 if (reader
->async_callback
)
418 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY
, &command
)))
420 command
->u
.sample
.stream_index
= stream
->index
;
421 if (FAILED(hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
)))
422 WARN("Failed to submit async result, hr %#lx.\n", hr
);
423 IUnknown_Release(&command
->IUnknown_iface
);
427 WakeAllConditionVariable(&reader
->sample_event
);
432 static void source_reader_copy_sample_buffer(IMFSample
*src
, IMFSample
*dst
)
434 IMFMediaBuffer
*buffer
;
439 IMFSample_CopyAllItems(src
, (IMFAttributes
*)dst
);
441 IMFSample_SetSampleDuration(dst
, 0);
442 IMFSample_SetSampleTime(dst
, 0);
443 IMFSample_SetSampleFlags(dst
, 0);
445 if (SUCCEEDED(IMFSample_GetSampleDuration(src
, &time
)))
446 IMFSample_SetSampleDuration(dst
, time
);
448 if (SUCCEEDED(IMFSample_GetSampleTime(src
, &time
)))
449 IMFSample_SetSampleTime(dst
, time
);
451 if (SUCCEEDED(IMFSample_GetSampleFlags(src
, &flags
)))
452 IMFSample_SetSampleFlags(dst
, flags
);
454 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src
, NULL
)))
456 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst
, 0, &buffer
)))
458 if (FAILED(hr
= IMFSample_CopyToBuffer(src
, buffer
)))
459 WARN("Failed to copy a buffer, hr %#lx.\n", hr
);
460 IMFMediaBuffer_Release(buffer
);
465 static HRESULT
source_reader_queue_response(struct source_reader
*reader
, struct media_stream
*stream
, HRESULT status
,
466 DWORD stream_flags
, LONGLONG timestamp
, IMFSample
*sample
)
468 struct stream_response
*response
;
470 if (!(response
= calloc(1, sizeof(*response
))))
471 return E_OUTOFMEMORY
;
473 response
->status
= status
;
474 response
->stream_index
= stream
->index
;
475 response
->stream_flags
= stream_flags
;
476 response
->timestamp
= timestamp
;
477 response
->sample
= sample
;
478 if (response
->sample
)
479 IMFSample_AddRef(response
->sample
);
481 list_add_tail(&reader
->responses
, &response
->entry
);
484 source_reader_response_ready(reader
, response
);
486 stream
->last_sample_ts
= timestamp
;
491 static HRESULT
source_reader_queue_sample(struct source_reader
*reader
, struct media_stream
*stream
,
492 UINT flags
, IMFSample
*sample
)
494 LONGLONG timestamp
= 0;
496 if (FAILED(IMFSample_GetSampleTime(sample
, ×tamp
)))
497 WARN("Sample time wasn't set.\n");
499 return source_reader_queue_response(reader
, stream
, S_OK
, flags
, timestamp
, sample
);
502 static HRESULT
source_reader_request_sample(struct source_reader
*reader
, struct media_stream
*stream
)
506 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
508 if (FAILED(hr
= IMFMediaStream_RequestSample(stream
->stream
, NULL
)))
509 WARN("Sample request failed, hr %#lx.\n", hr
);
512 stream
->flags
|= STREAM_FLAG_SAMPLE_REQUESTED
;
519 static HRESULT
source_reader_new_stream_handler(struct source_reader
*reader
, IMFMediaEvent
*event
)
521 IMFMediaStream
*stream
;
526 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFMediaStream
, (void **)&stream
)))
528 WARN("Failed to get stream object, hr %#lx.\n", hr
);
532 TRACE("Got new stream %p.\n", stream
);
534 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
536 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
537 IMFMediaStream_Release(stream
);
541 EnterCriticalSection(&reader
->cs
);
543 for (i
= 0; i
< reader
->stream_count
; ++i
)
545 if (id
== reader
->streams
[i
].id
)
547 if (!reader
->streams
[i
].stream
)
549 reader
->streams
[i
].stream
= stream
;
550 IMFMediaStream_AddRef(reader
->streams
[i
].stream
);
551 if (FAILED(hr
= IMFMediaStream_BeginGetEvent(stream
, &reader
->stream_events_callback
,
552 (IUnknown
*)stream
)))
554 WARN("Failed to subscribe to stream events, hr %#lx.\n", hr
);
557 if (reader
->streams
[i
].requests
)
558 if (FAILED(source_reader_request_sample(reader
, &reader
->streams
[i
])))
559 WakeAllConditionVariable(&reader
->sample_event
);
565 if (i
== reader
->stream_count
)
566 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id
);
568 LeaveCriticalSection(&reader
->cs
);
570 IMFMediaStream_Release(stream
);
575 static HRESULT
source_reader_source_state_handler(struct source_reader
*reader
, MediaEventType event_type
)
577 EnterCriticalSection(&reader
->cs
);
581 case MESourceStarted
:
582 reader
->source_state
= SOURCE_STATE_STARTED
;
583 reader
->flags
&= ~SOURCE_READER_SEEKING
;
585 case MESourceStopped
:
586 reader
->source_state
= SOURCE_STATE_STOPPED
;
587 reader
->flags
&= ~SOURCE_READER_SEEKING
;
590 reader
->flags
&= ~SOURCE_READER_SEEKING
;
593 WARN("Unhandled event %ld.\n", event_type
);
596 LeaveCriticalSection(&reader
->cs
);
598 WakeAllConditionVariable(&reader
->state_event
);
599 if (event_type
== MESourceStopped
)
600 WakeAllConditionVariable(&reader
->stop_event
);
605 static HRESULT WINAPI
source_reader_source_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
607 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
608 MediaEventType event_type
;
609 IMFMediaSource
*source
;
610 IMFMediaEvent
*event
;
613 TRACE("%p, %p.\n", iface
, result
);
615 source
= (IMFMediaSource
*)IMFAsyncResult_GetStateNoAddRef(result
);
617 if (FAILED(hr
= IMFMediaSource_EndGetEvent(source
, result
, &event
)))
620 IMFMediaEvent_GetType(event
, &event_type
);
622 TRACE("Got event %lu.\n", event_type
);
627 hr
= source_reader_new_stream_handler(reader
, event
);
629 case MESourceStarted
:
631 case MESourceStopped
:
633 hr
= source_reader_source_state_handler(reader
, event_type
);
635 case MEBufferingStarted
:
636 case MEBufferingStopped
:
640 case MESourceCharacteristicsChanged
:
641 case MESourceMetadataChanged
:
642 case MEContentProtectionMetadata
:
643 case MEDeviceThermalStateChanged
:
644 if (reader
->async_callback
)
645 IMFSourceReaderCallback_OnEvent(reader
->async_callback
, MF_SOURCE_READER_MEDIASOURCE
, event
);
652 WARN("Failed while handling %ld event, hr %#lx.\n", event_type
, hr
);
654 IMFMediaEvent_Release(event
);
656 if (event_type
!= MESourceStopped
)
657 IMFMediaSource_BeginGetEvent(source
, iface
, (IUnknown
*)source
);
662 static const IMFAsyncCallbackVtbl source_events_callback_vtbl
=
664 source_reader_callback_QueryInterface
,
665 source_reader_source_events_callback_AddRef
,
666 source_reader_source_events_callback_Release
,
667 source_reader_callback_GetParameters
,
668 source_reader_source_events_callback_Invoke
,
671 static ULONG WINAPI
source_reader_stream_events_callback_AddRef(IMFAsyncCallback
*iface
)
673 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
674 return source_reader_addref(reader
);
677 static ULONG WINAPI
source_reader_stream_events_callback_Release(IMFAsyncCallback
*iface
)
679 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
680 return source_reader_release(reader
);
683 static HRESULT
source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO
*info
, IMFSample
**out
)
685 IMFMediaBuffer
*buffer
;
690 if (FAILED(hr
= MFCreateSample(&sample
)))
692 if (SUCCEEDED(hr
= MFCreateAlignedMemoryBuffer(info
->cbSize
, info
->cbAlignment
, &buffer
)))
694 if (SUCCEEDED(hr
= IMFSample_AddBuffer(sample
, buffer
)))
697 IMFSample_AddRef(sample
);
699 IMFMediaBuffer_Release(buffer
);
702 IMFSample_Release(sample
);
706 static void media_type_try_copy_attr(IMFMediaType
*dst
, IMFMediaType
*src
, const GUID
*attr
, HRESULT
*hr
)
710 PropVariantInit(&value
);
711 if (SUCCEEDED(*hr
) && FAILED(IMFMediaType_GetItem(dst
, attr
, NULL
))
712 && SUCCEEDED(IMFMediaType_GetItem(src
, attr
, &value
)))
713 *hr
= IMFMediaType_SetItem(dst
, attr
, &value
);
714 PropVariantClear(&value
);
717 /* update a media type with additional attributes reported by upstream element */
718 /* also present in mf/topology_loader.c pipeline */
719 static HRESULT
update_media_type_from_upstream(IMFMediaType
*media_type
, IMFMediaType
*upstream_type
)
723 /* propagate common video attributes */
724 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FRAME_SIZE
, &hr
);
725 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FRAME_RATE
, &hr
);
726 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_DEFAULT_STRIDE
, &hr
);
727 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_ROTATION
, &hr
);
728 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FIXED_SIZE_SAMPLES
, &hr
);
729 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_PIXEL_ASPECT_RATIO
, &hr
);
730 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, &hr
);
731 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
, &hr
);
733 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_CHROMA_SITING
, &hr
);
734 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_INTERLACE_MODE
, &hr
);
735 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_TRANSFER_FUNCTION
, &hr
);
736 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_PRIMARIES
, &hr
);
737 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_YUV_MATRIX
, &hr
);
738 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_LIGHTING
, &hr
);
739 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_NOMINAL_RANGE
, &hr
);
741 /* propagate common audio attributes */
742 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_NUM_CHANNELS
, &hr
);
743 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &hr
);
744 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_BITS_PER_SAMPLE
, &hr
);
745 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_SAMPLES_PER_SECOND
, &hr
);
746 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
, &hr
);
747 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_CHANNEL_MASK
, &hr
);
748 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_SAMPLES_PER_BLOCK
, &hr
);
749 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE
, &hr
);
754 static HRESULT
source_reader_pull_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
755 struct transform_entry
*entry
);
756 static HRESULT
source_reader_push_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
757 struct transform_entry
*entry
, IMFSample
*sample
)
763 if (FAILED(hr
= source_reader_pull_transform_samples(reader
, stream
, entry
))
764 && hr
!= MF_E_TRANSFORM_NEED_MORE_INPUT
)
766 if (SUCCEEDED(hr
= IMFTransform_ProcessInput(entry
->transform
, 0, sample
, 0)))
767 return source_reader_pull_transform_samples(reader
, stream
, entry
);
769 while (hr
== MF_E_NOTACCEPTING
);
774 /* update the transform output type while keeping subtype which matches the desired type */
775 static HRESULT
set_matching_transform_output_type(IMFTransform
*transform
, IMFMediaType
*old_output_type
)
777 IMFMediaType
*new_output_type
;
778 GUID subtype
, desired
;
782 IMFMediaType_GetGUID(old_output_type
, &MF_MT_SUBTYPE
, &desired
);
784 /* find an available output type matching the desired subtype */
785 while (SUCCEEDED(hr
= IMFTransform_GetOutputAvailableType(transform
, 0, i
++, &new_output_type
)))
787 IMFMediaType_GetGUID(new_output_type
, &MF_MT_SUBTYPE
, &subtype
);
788 if (IsEqualGUID(&subtype
, &desired
) && SUCCEEDED(hr
= IMFTransform_SetOutputType(transform
, 0, new_output_type
, 0)))
790 IMFMediaType_Release(new_output_type
);
793 IMFMediaType_Release(new_output_type
);
799 /* update the transform output type while keeping subtype which matches the old output type */
800 static HRESULT
transform_entry_update_output_type(struct transform_entry
*entry
, IMFMediaType
*old_output_type
)
804 if (SUCCEEDED(hr
= set_matching_transform_output_type(entry
->transform
, old_output_type
)))
805 entry
->pending_flags
|= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED
;
810 /* update the transform input type while keeping an output type which matches the current output subtype */
811 static HRESULT
transform_entry_update_input_type(struct transform_entry
*entry
, IMFMediaType
*input_type
)
813 IMFMediaType
*old_output_type
, *new_output_type
;
816 if (FAILED(hr
= IMFTransform_GetOutputCurrentType(entry
->transform
, 0, &old_output_type
)))
818 if (FAILED(hr
= IMFTransform_SetInputType(entry
->transform
, 0, input_type
, 0)))
821 /* check if transform output type is still valid or if we need to update it as well */
822 if (FAILED(hr
= IMFTransform_GetOutputCurrentType(entry
->transform
, 0, &new_output_type
)))
823 hr
= transform_entry_update_output_type(entry
, old_output_type
);
825 IMFMediaType_Release(new_output_type
);
827 IMFMediaType_Release(old_output_type
);
831 static void transform_entry_initialize_attributes(struct source_reader
*reader
, struct transform_entry
*entry
)
833 IMFAttributes
*attributes
;
835 if (SUCCEEDED(IMFTransform_GetAttributes(entry
->transform
, &attributes
)))
837 if (FAILED(IMFAttributes_GetItem(attributes
, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT
, NULL
)))
838 IMFAttributes_SetUINT32(attributes
, &MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT
, 6);
840 IMFAttributes_Release(attributes
);
843 if (SUCCEEDED(IMFTransform_GetOutputStreamAttributes(entry
->transform
, 0, &attributes
)))
845 UINT32 shared
, shared_without_mutex
, bind_flags
;
847 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED
, &shared
)))
848 IMFAttributes_SetUINT32(attributes
, &MF_SA_D3D11_SHARED
, shared
);
849 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, &shared_without_mutex
)))
850 IMFAttributes_SetUINT32(attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, shared_without_mutex
);
851 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SOURCE_READER_D3D11_BIND_FLAGS
, &bind_flags
)))
852 IMFAttributes_SetUINT32(attributes
, &MF_SA_D3D11_BINDFLAGS
, bind_flags
);
853 else if ((reader
->flags
& SOURCE_READER_DXGI_DEVICE_MANAGER
) && FAILED(IMFAttributes_GetItem(attributes
, &MF_SA_D3D11_BINDFLAGS
, NULL
)))
854 IMFAttributes_SetUINT32(attributes
, &MF_SA_D3D11_BINDFLAGS
, 1024);
856 IMFAttributes_Release(attributes
);
860 static HRESULT
source_reader_pull_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
861 struct transform_entry
*entry
)
863 MFT_OUTPUT_STREAM_INFO stream_info
= {0};
864 struct transform_entry
*next
= NULL
;
869 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
870 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
872 if (!entry
->attributes_initialized
)
874 transform_entry_initialize_attributes(reader
, entry
);
875 entry
->attributes_initialized
= TRUE
;
878 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(entry
->transform
, 0, &stream_info
)))
880 stream_info
.cbSize
= max(stream_info
.cbSize
, entry
->min_buffer_size
);
882 while (SUCCEEDED(hr
))
884 MFT_OUTPUT_DATA_BUFFER out_buffer
= {0};
885 IMFMediaType
*media_type
;
887 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
))
888 && FAILED(hr
= source_reader_allocate_stream_sample(&stream_info
, &out_buffer
.pSample
)))
891 if (SUCCEEDED(hr
= IMFTransform_ProcessOutput(entry
->transform
, 0, 1, &out_buffer
, &status
)))
893 /* propagate upstream type to the transform input type */
894 if ((entry
->pending_flags
& MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED
)
895 && SUCCEEDED(hr
= IMFTransform_GetOutputCurrentType(entry
->transform
, 0, &media_type
)))
898 hr
= IMFMediaType_CopyAllItems(media_type
, (IMFAttributes
*)stream
->current
);
900 hr
= transform_entry_update_input_type(next
, media_type
);
901 IMFMediaType_Release(media_type
);
905 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
907 hr
= source_reader_push_transform_samples(reader
, stream
, next
, out_buffer
.pSample
);
909 hr
= source_reader_queue_sample(reader
, stream
, entry
->pending_flags
, out_buffer
.pSample
);
911 entry
->pending_flags
= 0;
914 if (hr
== MF_E_TRANSFORM_STREAM_CHANGE
&& SUCCEEDED(hr
= IMFTransform_GetOutputCurrentType(entry
->transform
, 0, &media_type
)))
916 hr
= transform_entry_update_output_type(entry
, media_type
);
917 IMFMediaType_Release(media_type
);
921 hr
= IMFTransform_GetOutputStreamInfo(entry
->transform
, 0, &stream_info
);
922 stream_info
.cbSize
= max(stream_info
.cbSize
, entry
->min_buffer_size
);
926 if (out_buffer
.pSample
)
927 IMFSample_Release(out_buffer
.pSample
);
928 if (out_buffer
.pEvents
)
929 IMFCollection_Release(out_buffer
.pEvents
);
935 static HRESULT
source_reader_drain_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
936 struct transform_entry
*entry
)
938 struct transform_entry
*next
= NULL
;
942 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
943 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
945 if (FAILED(hr
= IMFTransform_ProcessMessage(entry
->transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
946 WARN("Failed to drain transform %p, hr %#lx\n", entry
->transform
, hr
);
947 if (FAILED(hr
= source_reader_pull_transform_samples(reader
, stream
, entry
))
948 && hr
!= MF_E_TRANSFORM_NEED_MORE_INPUT
)
949 WARN("Failed to pull pending samples, hr %#lx.\n", hr
);
951 return next
? source_reader_drain_transform_samples(reader
, stream
, next
) : S_OK
;
954 static HRESULT
source_reader_flush_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
955 struct transform_entry
*entry
)
957 struct transform_entry
*next
= NULL
;
961 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
962 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
964 if (FAILED(hr
= IMFTransform_ProcessMessage(entry
->transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0)))
965 WARN("Failed to flush transform %p, hr %#lx\n", entry
->transform
, hr
);
967 return next
? source_reader_flush_transform_samples(reader
, stream
, next
) : S_OK
;
970 static HRESULT
source_reader_notify_transform(struct source_reader
*reader
, struct media_stream
*stream
,
971 struct transform_entry
*entry
, UINT message
)
973 struct transform_entry
*next
= NULL
;
977 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
978 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
980 if (FAILED(hr
= IMFTransform_ProcessMessage(entry
->transform
, message
, 0)))
981 WARN("Failed to notify transform %p message %#x, hr %#lx\n", entry
->transform
, message
, hr
);
983 return next
? source_reader_notify_transform(reader
, stream
, next
, message
) : S_OK
;
986 static HRESULT
source_reader_process_sample(struct source_reader
*reader
, struct media_stream
*stream
,
989 struct transform_entry
*entry
;
993 if (!(ptr
= list_head(&stream
->transforms
)))
994 return source_reader_queue_sample(reader
, stream
, 0, sample
);
995 entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
997 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
998 if (SUCCEEDED(hr
= source_reader_push_transform_samples(reader
, stream
, entry
, sample
))
999 || hr
== MF_E_TRANSFORM_NEED_MORE_INPUT
)
1000 hr
= stream
->requests
? source_reader_request_sample(reader
, stream
) : S_OK
;
1002 WARN("Transform failed to process output, hr %#lx.\n", hr
);
1007 static HRESULT
source_reader_media_sample_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
1008 IMFMediaEvent
*event
)
1015 TRACE("Got new sample for stream %p.\n", stream
);
1017 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFSample
, (void **)&sample
)))
1019 WARN("Failed to get sample object, hr %#lx.\n", hr
);
1023 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
1025 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
1026 IMFSample_Release(sample
);
1030 EnterCriticalSection(&reader
->cs
);
1032 for (i
= 0; i
< reader
->stream_count
; ++i
)
1034 if (id
== reader
->streams
[i
].id
)
1036 /* FIXME: propagate processing errors? */
1037 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
1038 hr
= source_reader_process_sample(reader
, &reader
->streams
[i
], sample
);
1043 if (i
== reader
->stream_count
)
1044 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id
);
1046 LeaveCriticalSection(&reader
->cs
);
1048 IMFSample_Release(sample
);
1053 static HRESULT
source_reader_media_stream_state_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
1054 IMFMediaEvent
*event
)
1056 MediaEventType event_type
;
1064 IMFMediaEvent_GetType(event
, &event_type
);
1066 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
1068 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
1072 EnterCriticalSection(&reader
->cs
);
1074 for (i
= 0; i
< reader
->stream_count
; ++i
)
1076 struct media_stream
*stream
= &reader
->streams
[i
];
1078 if (id
== stream
->id
)
1083 stream
->state
= STREAM_STATE_EOS
;
1084 stream
->flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
1086 if ((ptr
= list_head(&stream
->transforms
)))
1088 struct transform_entry
*entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
1089 if (FAILED(hr
= source_reader_drain_transform_samples(reader
, stream
, entry
)))
1090 WARN("Failed to drain pending samples, hr %#lx.\n", hr
);
1093 while (stream
->requests
)
1094 source_reader_queue_response(reader
, stream
, S_OK
, MF_SOURCE_READERF_ENDOFSTREAM
, 0, NULL
);
1097 case MEStreamSeeked
:
1098 case MEStreamStarted
:
1099 stream
->state
= STREAM_STATE_READY
;
1101 if ((ptr
= list_head(&stream
->transforms
)))
1103 struct transform_entry
*entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
1104 if (FAILED(hr
= source_reader_notify_transform(reader
, stream
, entry
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
)))
1105 WARN("Failed to notify transforms of stream start, hr %#lx.\n", hr
);
1108 case MEStreamStopped
:
1109 stream
->flags
|= STREAM_FLAG_STOPPED
;
1112 value
.vt
= VT_EMPTY
;
1113 hr
= SUCCEEDED(IMFMediaEvent_GetValue(event
, &value
)) && value
.vt
== VT_I8
? S_OK
: E_UNEXPECTED
;
1114 timestamp
= SUCCEEDED(hr
) ? value
.hVal
.QuadPart
: 0;
1115 PropVariantClear(&value
);
1117 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_STREAMTICK
, timestamp
, NULL
);
1128 LeaveCriticalSection(&reader
->cs
);
1130 if (event_type
== MEStreamStopped
)
1131 WakeAllConditionVariable(&reader
->stop_event
);
1136 static HRESULT WINAPI
source_reader_stream_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1138 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
1139 MediaEventType event_type
;
1140 IMFMediaStream
*stream
;
1141 IMFMediaEvent
*event
;
1144 TRACE("%p, %p.\n", iface
, result
);
1146 stream
= (IMFMediaStream
*)IMFAsyncResult_GetStateNoAddRef(result
);
1148 if (FAILED(hr
= IMFMediaStream_EndGetEvent(stream
, result
, &event
)))
1151 IMFMediaEvent_GetType(event
, &event_type
);
1153 TRACE("Got event %lu.\n", event_type
);
1158 hr
= source_reader_media_sample_handler(reader
, stream
, event
);
1160 case MEStreamSeeked
:
1161 case MEStreamStarted
:
1162 case MEStreamStopped
:
1165 hr
= source_reader_media_stream_state_handler(reader
, stream
, event
);
1172 WARN("Failed while handling %ld event, hr %#lx.\n", event_type
, hr
);
1174 IMFMediaEvent_Release(event
);
1176 if (event_type
!= MEStreamStopped
)
1177 IMFMediaStream_BeginGetEvent(stream
, iface
, (IUnknown
*)stream
);
1182 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl
=
1184 source_reader_callback_QueryInterface
,
1185 source_reader_stream_events_callback_AddRef
,
1186 source_reader_stream_events_callback_Release
,
1187 source_reader_callback_GetParameters
,
1188 source_reader_stream_events_callback_Invoke
,
1191 static ULONG WINAPI
source_reader_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
1193 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1194 return source_reader_addref(reader
);
1197 static ULONG WINAPI
source_reader_async_commands_callback_Release(IMFAsyncCallback
*iface
)
1199 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1200 return source_reader_release(reader
);
1203 static struct stream_response
* media_stream_detach_response(struct source_reader
*reader
, struct stream_response
*response
)
1205 struct media_stream
*stream
;
1207 list_remove(&response
->entry
);
1209 if (response
->stream_index
< reader
->stream_count
)
1211 stream
= &reader
->streams
[response
->stream_index
];
1212 if (stream
->responses
)
1213 --stream
->responses
;
1219 static struct stream_response
*media_stream_pop_response(struct source_reader
*reader
, struct media_stream
*stream
)
1221 struct stream_response
*response
;
1225 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1227 if (stream
&& response
->stream_index
!= stream
->index
)
1230 if (!stream
) stream
= &reader
->streams
[response
->stream_index
];
1232 if (response
->sample
&& stream
->allocator
)
1234 /* Return allocation error to the caller, while keeping original response sample in for later. */
1235 if (SUCCEEDED(hr
= IMFVideoSampleAllocatorEx_AllocateSample(stream
->allocator
, &sample
)))
1237 source_reader_copy_sample_buffer(response
->sample
, sample
);
1238 IMFSample_Release(response
->sample
);
1239 response
->sample
= sample
;
1243 if (!(response
= calloc(1, sizeof(*response
))))
1246 response
->status
= hr
;
1247 response
->stream_flags
= MF_SOURCE_READERF_ERROR
;
1252 return media_stream_detach_response(reader
, response
);
1258 static void source_reader_release_response(struct stream_response
*response
)
1260 if (response
->sample
)
1261 IMFSample_Release(response
->sample
);
1265 static HRESULT
source_reader_get_stream_selection(const struct source_reader
*reader
, DWORD index
, BOOL
*selected
)
1267 IMFStreamDescriptor
*sd
;
1269 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, selected
, &sd
)))
1270 return MF_E_INVALIDSTREAMNUMBER
;
1271 IMFStreamDescriptor_Release(sd
);
1276 static HRESULT
source_reader_start_source(struct source_reader
*reader
)
1278 BOOL selected
, selection_changed
= FALSE
;
1279 PROPVARIANT position
;
1283 for (i
= 0; i
< reader
->stream_count
; ++i
)
1285 source_reader_get_stream_selection(reader
, i
, &selected
);
1287 reader
->streams
[i
].flags
|= STREAM_FLAG_SELECTED
;
1289 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SELECTED
;
1292 if (reader
->source_state
== SOURCE_STATE_STARTED
)
1294 for (i
= 0; i
< reader
->stream_count
; ++i
)
1296 selection_changed
= !!(reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
) ^
1297 !!(reader
->streams
[i
].flags
& STREAM_FLAG_PRESENTED
);
1298 if (selection_changed
)
1303 position
.hVal
.QuadPart
= 0;
1304 if (reader
->source_state
!= SOURCE_STATE_STARTED
|| selection_changed
)
1306 position
.vt
= reader
->source_state
== SOURCE_STATE_STARTED
? VT_EMPTY
: VT_I8
;
1308 /* Update cached stream selection if descriptor was accepted. */
1309 if (SUCCEEDED(hr
= IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &GUID_NULL
, &position
)))
1311 for (i
= 0; i
< reader
->stream_count
; ++i
)
1313 if (reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
)
1314 reader
->streams
[i
].flags
|= STREAM_FLAG_PRESENTED
;
1322 static BOOL
source_reader_got_response_for_stream(struct source_reader
*reader
, struct media_stream
*stream
)
1324 struct stream_response
*response
;
1326 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1328 if (response
->stream_index
== stream
->index
)
1335 static BOOL
source_reader_get_read_result(struct source_reader
*reader
, struct media_stream
*stream
, DWORD flags
,
1336 HRESULT
*status
, DWORD
*stream_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1338 struct stream_response
*response
= NULL
;
1339 BOOL request_sample
= FALSE
;
1341 if ((response
= media_stream_pop_response(reader
, stream
)))
1343 *status
= response
->status
;
1344 *stream_index
= stream
->index
;
1345 *stream_flags
= response
->stream_flags
;
1346 *timestamp
= response
->timestamp
;
1347 *sample
= response
->sample
;
1349 IMFSample_AddRef(*sample
);
1351 source_reader_release_response(response
);
1356 *stream_index
= stream
->index
;
1360 if (stream
->state
== STREAM_STATE_EOS
)
1362 *stream_flags
= MF_SOURCE_READERF_ENDOFSTREAM
;
1366 request_sample
= !(flags
& MF_SOURCE_READER_CONTROLF_DRAIN
);
1371 return !request_sample
;
1374 static HRESULT
source_reader_get_next_selected_stream(struct source_reader
*reader
, DWORD
*stream_index
)
1376 unsigned int i
, first_selected
= ~0u;
1377 BOOL selected
, stream_drained
;
1378 LONGLONG min_ts
= MAXLONGLONG
;
1380 for (i
= 0; i
< reader
->stream_count
; ++i
)
1382 stream_drained
= reader
->streams
[i
].state
== STREAM_STATE_EOS
&& !reader
->streams
[i
].responses
;
1383 selected
= SUCCEEDED(source_reader_get_stream_selection(reader
, i
, &selected
)) && selected
;
1387 if (first_selected
== ~0u)
1390 /* Pick the stream whose last sample had the lowest timestamp. */
1391 if (!stream_drained
&& reader
->streams
[i
].last_sample_ts
< min_ts
)
1393 min_ts
= reader
->streams
[i
].last_sample_ts
;
1399 /* If all selected streams reached EOS, use first selected. */
1400 if (first_selected
!= ~0u)
1402 if (min_ts
== MAXLONGLONG
)
1403 *stream_index
= first_selected
;
1406 return first_selected
== ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED
: S_OK
;
1409 static HRESULT
source_reader_get_stream_read_index(struct source_reader
*reader
, unsigned int index
, DWORD
*stream_index
)
1416 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1417 *stream_index
= reader
->first_video_stream_index
;
1419 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1420 *stream_index
= reader
->first_audio_stream_index
;
1422 case MF_SOURCE_READER_ANY_STREAM
:
1423 return source_reader_get_next_selected_stream(reader
, stream_index
);
1425 *stream_index
= index
;
1428 /* Can't read from deselected streams. */
1429 if (SUCCEEDED(hr
= source_reader_get_stream_selection(reader
, *stream_index
, &selected
)) && !selected
)
1430 hr
= MF_E_INVALIDREQUEST
;
1435 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
)
1437 struct stream_response
*ptr
, *next
;
1439 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &reader
->responses
, struct stream_response
, entry
)
1441 if (stream
&& stream
->index
!= ptr
->stream_index
&&
1442 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_VIDEO_STREAM
&&
1443 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_AUDIO_STREAM
&&
1444 ptr
->stream_index
!= MF_SOURCE_READER_ANY_STREAM
)
1448 media_stream_detach_response(reader
, ptr
);
1449 source_reader_release_response(ptr
);
1453 static void source_reader_flush_stream(struct source_reader
*reader
, DWORD stream_index
)
1455 struct media_stream
*stream
= &reader
->streams
[stream_index
];
1459 source_reader_release_responses(reader
, stream
);
1461 if ((ptr
= list_head(&stream
->transforms
)))
1463 struct transform_entry
*entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
1464 if (FAILED(hr
= source_reader_flush_transform_samples(reader
, stream
, entry
)))
1465 WARN("Failed to drain pending samples, hr %#lx.\n", hr
);
1468 stream
->requests
= 0;
1471 static HRESULT
source_reader_flush(struct source_reader
*reader
, unsigned int index
)
1473 unsigned int stream_index
;
1476 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1478 for (stream_index
= 0; stream_index
< reader
->stream_count
; ++stream_index
)
1479 source_reader_flush_stream(reader
, stream_index
);
1485 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1486 stream_index
= reader
->first_video_stream_index
;
1488 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1489 stream_index
= reader
->first_audio_stream_index
;
1492 stream_index
= index
;
1495 if (stream_index
< reader
->stream_count
)
1496 source_reader_flush_stream(reader
, stream_index
);
1498 hr
= MF_E_INVALIDSTREAMNUMBER
;
1504 static HRESULT WINAPI
source_reader_async_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1506 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1507 struct media_stream
*stream
, stub_stream
= { .requests
= 1 };
1508 struct source_reader_async_command
*command
;
1509 struct stream_response
*response
;
1510 DWORD stream_index
, stream_flags
;
1511 BOOL report_sample
= FALSE
;
1512 IMFSample
*sample
= NULL
;
1513 LONGLONG timestamp
= 0;
1517 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
1520 command
= impl_from_async_command_IUnknown(state
);
1522 switch (command
->op
)
1524 case SOURCE_READER_ASYNC_READ
:
1525 EnterCriticalSection(&reader
->cs
);
1527 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1529 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, command
->u
.read
.stream_index
, &stream_index
)))
1531 stream
= &reader
->streams
[stream_index
];
1533 if (!(report_sample
= source_reader_get_read_result(reader
, stream
, command
->u
.read
.flags
, &status
,
1534 &stream_index
, &stream_flags
, ×tamp
, &sample
)))
1537 source_reader_request_sample(reader
, stream
);
1538 /* FIXME: set error stream/reader state on request failure */
1543 stub_stream
.index
= command
->u
.read
.stream_index
;
1544 source_reader_queue_response(reader
, &stub_stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
1548 LeaveCriticalSection(&reader
->cs
);
1551 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, status
, stream_index
, stream_flags
,
1555 IMFSample_Release(sample
);
1559 case SOURCE_READER_ASYNC_SEEK
:
1561 EnterCriticalSection(&reader
->cs
);
1562 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &command
->u
.seek
.format
,
1563 &command
->u
.seek
.position
)))
1565 reader
->flags
|= SOURCE_READER_SEEKING
;
1567 LeaveCriticalSection(&reader
->cs
);
1571 case SOURCE_READER_ASYNC_SAMPLE_READY
:
1573 EnterCriticalSection(&reader
->cs
);
1574 response
= media_stream_pop_response(reader
, NULL
);
1575 LeaveCriticalSection(&reader
->cs
);
1579 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, response
->status
, response
->stream_index
,
1580 response
->stream_flags
, response
->timestamp
, response
->sample
);
1581 source_reader_release_response(response
);
1585 case SOURCE_READER_ASYNC_FLUSH
:
1586 EnterCriticalSection(&reader
->cs
);
1587 source_reader_flush(reader
, command
->u
.flush
.stream_index
);
1588 reader
->flags
&= ~SOURCE_READER_FLUSHING
;
1589 LeaveCriticalSection(&reader
->cs
);
1591 IMFSourceReaderCallback_OnFlush(reader
->async_callback
, command
->u
.flush
.stream_index
);
1597 IUnknown_Release(state
);
1602 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl
=
1604 source_reader_callback_QueryInterface
,
1605 source_reader_async_commands_callback_AddRef
,
1606 source_reader_async_commands_callback_Release
,
1607 source_reader_callback_GetParameters
,
1608 source_reader_async_commands_callback_Invoke
,
1611 static HRESULT WINAPI
src_reader_QueryInterface(IMFSourceReaderEx
*iface
, REFIID riid
, void **out
)
1613 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1615 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1617 if (IsEqualGUID(riid
, &IID_IUnknown
)
1618 || IsEqualGUID(riid
, &IID_IMFSourceReader
)
1619 || IsEqualGUID(riid
, &IID_IMFSourceReaderEx
))
1621 *out
= &reader
->IMFSourceReaderEx_iface
;
1625 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1627 return E_NOINTERFACE
;
1630 IUnknown_AddRef((IUnknown
*)*out
);
1634 static ULONG WINAPI
src_reader_AddRef(IMFSourceReaderEx
*iface
)
1636 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1637 ULONG refcount
= InterlockedIncrement(&reader
->public_refcount
);
1639 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1644 static BOOL
source_reader_is_source_stopped(const struct source_reader
*reader
)
1648 if (reader
->source_state
!= SOURCE_STATE_STOPPED
)
1651 for (i
= 0; i
< reader
->stream_count
; ++i
)
1653 if (reader
->streams
[i
].stream
&& !(reader
->streams
[i
].flags
& STREAM_FLAG_STOPPED
))
1660 static ULONG WINAPI
src_reader_Release(IMFSourceReaderEx
*iface
)
1662 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1663 ULONG refcount
= InterlockedDecrement(&reader
->public_refcount
);
1666 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1670 if (reader
->flags
& SOURCE_READER_SHUTDOWN_ON_RELEASE
)
1671 IMFMediaSource_Shutdown(reader
->source
);
1672 else if (SUCCEEDED(IMFMediaSource_Stop(reader
->source
)))
1674 EnterCriticalSection(&reader
->cs
);
1676 while (!source_reader_is_source_stopped(reader
))
1678 SleepConditionVariableCS(&reader
->stop_event
, &reader
->cs
, INFINITE
);
1681 LeaveCriticalSection(&reader
->cs
);
1684 for (i
= 0; i
< reader
->stream_count
; ++i
)
1686 struct media_stream
*stream
= &reader
->streams
[i
];
1687 IMFVideoSampleAllocatorCallback
*callback
;
1689 if (!stream
->allocator
)
1692 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream
->allocator
, &IID_IMFVideoSampleAllocatorCallback
,
1693 (void **)&callback
)))
1695 IMFVideoSampleAllocatorCallback_SetCallback(callback
, NULL
);
1696 IMFVideoSampleAllocatorCallback_Release(callback
);
1700 MFUnlockWorkQueue(reader
->queue
);
1701 source_reader_release(reader
);
1707 static HRESULT WINAPI
src_reader_GetStreamSelection(IMFSourceReaderEx
*iface
, DWORD index
, BOOL
*selected
)
1709 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1711 TRACE("%p, %#lx, %p.\n", iface
, index
, selected
);
1715 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1716 index
= reader
->first_video_stream_index
;
1718 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1719 index
= reader
->first_audio_stream_index
;
1725 return source_reader_get_stream_selection(reader
, index
, selected
);
1728 static HRESULT WINAPI
src_reader_SetStreamSelection(IMFSourceReaderEx
*iface
, DWORD index
, BOOL selection
)
1730 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1732 BOOL selection_changed
= FALSE
, selected
;
1735 TRACE("%p, %#lx, %d.\n", iface
, index
, selection
);
1737 selection
= !!selection
;
1739 EnterCriticalSection(&reader
->cs
);
1741 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1743 for (i
= 0; i
< reader
->stream_count
; ++i
)
1745 if (!selection_changed
)
1747 source_reader_get_stream_selection(reader
, i
, &selected
);
1748 selection_changed
= !!(selected
^ selection
);
1752 IMFPresentationDescriptor_SelectStream(reader
->descriptor
, i
);
1754 IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, i
);
1761 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1762 index
= reader
->first_video_stream_index
;
1764 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1765 index
= reader
->first_audio_stream_index
;
1771 source_reader_get_stream_selection(reader
, index
, &selected
);
1772 selection_changed
= !!(selected
^ selection
);
1775 hr
= IMFPresentationDescriptor_SelectStream(reader
->descriptor
, index
);
1777 hr
= IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, index
);
1780 if (selection_changed
)
1782 for (i
= 0; i
< reader
->stream_count
; ++i
)
1784 reader
->streams
[i
].last_sample_ts
= 0;
1788 LeaveCriticalSection(&reader
->cs
);
1790 return SUCCEEDED(hr
) ? S_OK
: MF_E_INVALIDSTREAMNUMBER
;
1793 static HRESULT
source_reader_get_native_media_type(struct source_reader
*reader
, DWORD index
, DWORD type_index
,
1794 IMFMediaType
**type
)
1796 IMFMediaTypeHandler
*handler
;
1797 IMFStreamDescriptor
*sd
;
1798 IMFMediaType
*src_type
;
1804 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1805 index
= reader
->first_video_stream_index
;
1807 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1808 index
= reader
->first_audio_stream_index
;
1814 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1815 return MF_E_INVALIDSTREAMNUMBER
;
1817 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
1818 IMFStreamDescriptor_Release(sd
);
1822 if (type_index
== MF_SOURCE_READER_CURRENT_TYPE_INDEX
)
1823 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &src_type
);
1825 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, type_index
, &src_type
);
1826 IMFMediaTypeHandler_Release(handler
);
1830 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
1831 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)*type
);
1832 IMFMediaType_Release(src_type
);
1838 static HRESULT WINAPI
src_reader_GetNativeMediaType(IMFSourceReaderEx
*iface
, DWORD index
, DWORD type_index
,
1839 IMFMediaType
**type
)
1841 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1843 TRACE("%p, %#lx, %#lx, %p.\n", iface
, index
, type_index
, type
);
1845 return source_reader_get_native_media_type(reader
, index
, type_index
, type
);
1848 static HRESULT WINAPI
src_reader_GetCurrentMediaType(IMFSourceReaderEx
*iface
, DWORD index
, IMFMediaType
**type
)
1850 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1853 TRACE("%p, %#lx, %p.\n", iface
, index
, type
);
1857 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1858 index
= reader
->first_video_stream_index
;
1860 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1861 index
= reader
->first_audio_stream_index
;
1867 if (index
>= reader
->stream_count
)
1868 return MF_E_INVALIDSTREAMNUMBER
;
1870 if (FAILED(hr
= MFCreateMediaType(type
)))
1873 EnterCriticalSection(&reader
->cs
);
1875 hr
= IMFMediaType_CopyAllItems(reader
->streams
[index
].current
, (IMFAttributes
*)*type
);
1877 LeaveCriticalSection(&reader
->cs
);
1882 static HRESULT
source_reader_get_source_type_handler(struct source_reader
*reader
, DWORD index
,
1883 IMFMediaTypeHandler
**handler
)
1885 IMFStreamDescriptor
*sd
;
1889 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1892 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, handler
);
1893 IMFStreamDescriptor_Release(sd
);
1898 static HRESULT
source_reader_set_compatible_media_type(struct source_reader
*reader
, DWORD index
, IMFMediaType
*type
)
1900 struct media_stream
*stream
= &reader
->streams
[index
];
1901 struct transform_entry
*entry
, *next
;
1902 IMFMediaTypeHandler
*type_handler
;
1903 IMFMediaType
*native_type
;
1904 BOOL type_set
= FALSE
;
1909 if (FAILED(hr
= IMFMediaType_IsEqual(type
, stream
->current
, &flags
)))
1912 if (!(flags
& MF_MEDIATYPE_EQUAL_MAJOR_TYPES
))
1913 return MF_E_INVALIDMEDIATYPE
;
1915 /* No need for a decoder or type change. */
1916 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_DATA
)
1919 if (stream
->transform_service
)
1921 IMFTransform_Release(stream
->transform_service
);
1922 stream
->transform_service
= NULL
;
1924 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &stream
->transforms
, struct transform_entry
, entry
)
1926 list_remove(&entry
->entry
);
1927 transform_entry_destroy(entry
);
1930 if (FAILED(hr
= source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1933 while (!type_set
&& IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler
, i
++, &native_type
) == S_OK
)
1935 static const DWORD compare_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_DATA
;
1937 if (SUCCEEDED(IMFMediaType_IsEqual(native_type
, type
, &flags
)) && (flags
& compare_flags
) == compare_flags
)
1939 if ((type_set
= SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, native_type
))))
1940 IMFMediaType_CopyAllItems(native_type
, (IMFAttributes
*)stream
->current
);
1943 IMFMediaType_Release(native_type
);
1946 IMFMediaTypeHandler_Release(type_handler
);
1948 return type_set
? S_OK
: S_FALSE
;
1951 static HRESULT
source_reader_create_sample_allocator_attributes(const struct source_reader
*reader
,
1952 IMFAttributes
**attributes
)
1954 UINT32 shared
= 0, shared_without_mutex
= 0;
1957 if (FAILED(hr
= MFCreateAttributes(attributes
, 1)))
1960 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED
, &shared
);
1961 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, &shared_without_mutex
);
1963 if (shared_without_mutex
)
1964 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, TRUE
);
1966 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED
, TRUE
);
1971 static HRESULT
source_reader_setup_sample_allocator(struct source_reader
*reader
, unsigned int index
)
1973 struct media_stream
*stream
= &reader
->streams
[index
];
1974 IMFAttributes
*attributes
= NULL
;
1978 IMFMediaType_GetMajorType(stream
->current
, &major
);
1979 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
1982 if (!(reader
->flags
& SOURCE_READER_HAS_DEVICE_MANAGER
))
1985 if (!stream
->allocator
)
1987 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&stream
->allocator
)))
1989 WARN("Failed to create sample allocator, hr %#lx.\n", hr
);
1994 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream
->allocator
);
1995 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(stream
->allocator
, reader
->device_manager
)))
1997 WARN("Failed to set device manager, hr %#lx.\n", hr
);
2001 if (FAILED(hr
= source_reader_create_sample_allocator_attributes(reader
, &attributes
)))
2002 WARN("Failed to create allocator attributes, hr %#lx.\n", hr
);
2004 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream
->allocator
, 2, 8,
2005 attributes
, stream
->current
)))
2007 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr
);
2011 IMFAttributes_Release(attributes
);
2016 static BOOL
source_reader_allow_video_processor(struct source_reader
*reader
, BOOL
*advanced
)
2021 if (!reader
->attributes
)
2024 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING
, &value
)))
2026 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING
, &value
)))
2027 return value
|| *advanced
;
2032 static HRESULT
source_reader_create_transform(struct source_reader
*reader
, BOOL decoder
, BOOL allow_processor
,
2033 IMFMediaType
*input_type
, IMFMediaType
*output_type
, struct transform_entry
**out
)
2035 MFT_REGISTER_TYPE_INFO in_type
, out_type
;
2036 struct transform_entry
*entry
;
2037 IMFActivate
**activates
;
2039 IMFTransform
*transform
;
2043 if (FAILED(hr
= IMFMediaType_GetMajorType(input_type
, &in_type
.guidMajorType
))
2044 || FAILED(hr
= IMFMediaType_GetGUID(input_type
, &MF_MT_SUBTYPE
, &in_type
.guidSubtype
)))
2046 if (FAILED(hr
= IMFMediaType_GetMajorType(output_type
, &out_type
.guidMajorType
))
2047 || FAILED(hr
= IMFMediaType_GetGUID(output_type
, &MF_MT_SUBTYPE
, &out_type
.guidSubtype
)))
2050 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
))
2051 category
= decoder
? MFT_CATEGORY_VIDEO_DECODER
: MFT_CATEGORY_VIDEO_PROCESSOR
;
2052 else if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
2053 category
= decoder
? MFT_CATEGORY_AUDIO_DECODER
: MFT_CATEGORY_AUDIO_EFFECT
;
2055 return MF_E_TOPO_CODEC_NOT_FOUND
;
2057 if (!(entry
= calloc(1, sizeof(*entry
))))
2058 return E_OUTOFMEMORY
;
2059 list_init(&entry
->entry
);
2060 entry
->category
= category
;
2062 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
)
2063 && SUCCEEDED(IMFMediaType_GetUINT32(output_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &entry
->min_buffer_size
)))
2065 UINT32 bytes_per_second
;
2067 if (SUCCEEDED(IMFMediaType_GetUINT32(output_type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
, &bytes_per_second
)))
2068 entry
->min_buffer_size
= max(entry
->min_buffer_size
, bytes_per_second
);
2071 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
) && IsEqualGUID(&out_type
.guidSubtype
, &MFVideoFormat_ABGR32
)
2072 && IsEqualGUID(&category
, &MFT_CATEGORY_VIDEO_PROCESSOR
))
2074 /* The video processor isn't registered for MFVideoFormat_ABGR32, and native even only supports that format when
2075 * D3D-enabled, we still want to instantiate a video processor in such case, so fixup the subtype for MFTEnumEx.
2077 WARN("Fixing up MFVideoFormat_ABGR32 subtype for the video processor\n");
2078 out_type
.guidSubtype
= MFVideoFormat_RGB32
;
2083 if (SUCCEEDED(hr
= MFTEnumEx(category
, 0, &in_type
, allow_processor
? NULL
: &out_type
, &activates
, &count
)))
2088 return MF_E_TOPO_CODEC_NOT_FOUND
;
2091 for (i
= 0; i
< count
; i
++)
2093 IMFAttributes
*attributes
;
2094 IMFMediaType
*media_type
;
2096 if (FAILED(hr
= IMFActivate_ActivateObject(activates
[i
], &IID_IMFTransform
, (void **)&transform
)))
2099 if (!reader
->device_manager
|| FAILED(IMFTransform_GetAttributes(transform
, &attributes
)))
2100 entry
->attributes_initialized
= TRUE
;
2103 UINT32 d3d_aware
= FALSE
;
2105 if (reader
->flags
& SOURCE_READER_DXGI_DEVICE_MANAGER
)
2107 if (SUCCEEDED(IMFAttributes_GetUINT32(attributes
, &MF_SA_D3D11_AWARE
, &d3d_aware
)) && d3d_aware
)
2108 IMFTransform_ProcessMessage(transform
, MFT_MESSAGE_SET_D3D_MANAGER
, (ULONG_PTR
)reader
->device_manager
);
2110 else if (reader
->flags
& SOURCE_READER_D3D9_DEVICE_MANAGER
)
2112 if (SUCCEEDED(IMFAttributes_GetUINT32(attributes
, &MF_SA_D3D_AWARE
, &d3d_aware
)) && d3d_aware
)
2113 IMFTransform_ProcessMessage(transform
, MFT_MESSAGE_SET_D3D_MANAGER
, (ULONG_PTR
)reader
->device_manager
);
2116 entry
->attributes_initialized
= !d3d_aware
;
2117 IMFAttributes_Release(attributes
);
2120 if (SUCCEEDED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0))
2121 && SUCCEEDED(hr
= IMFTransform_GetInputCurrentType(transform
, 0, &media_type
)))
2123 if (SUCCEEDED(hr
= update_media_type_from_upstream(output_type
, media_type
))
2124 && FAILED(hr
= IMFTransform_SetOutputType(transform
, 0, output_type
, 0))
2125 && FAILED(hr
= set_matching_transform_output_type(transform
, output_type
)) && allow_processor
2126 && SUCCEEDED(hr
= IMFTransform_GetOutputAvailableType(transform
, 0, 0, &media_type
)))
2128 struct transform_entry
*converter
;
2130 if (SUCCEEDED(hr
= IMFTransform_SetOutputType(transform
, 0, media_type
, 0))
2131 && SUCCEEDED(hr
= update_media_type_from_upstream(output_type
, media_type
))
2132 && SUCCEEDED(hr
= source_reader_create_transform(reader
, FALSE
, FALSE
, media_type
, output_type
, &converter
)))
2133 list_add_tail(&entry
->entry
, &converter
->entry
);
2135 IMFMediaType_Release(media_type
);
2140 entry
->transform
= transform
;
2146 IMFTransform_Release(transform
);
2149 for (i
= 0; i
< count
; ++i
)
2150 IMFActivate_Release(activates
[i
]);
2151 CoTaskMemFree(activates
);
2159 static HRESULT
source_reader_create_decoder_for_stream(struct source_reader
*reader
, DWORD index
, IMFMediaType
*output_type
)
2161 BOOL enable_advanced
, allow_processor
;
2162 struct media_stream
*stream
= &reader
->streams
[index
];
2163 IMFMediaType
*input_type
;
2167 allow_processor
= source_reader_allow_video_processor(reader
, &enable_advanced
);
2169 while (SUCCEEDED(hr
= source_reader_get_native_media_type(reader
, index
, i
++, &input_type
)))
2171 struct transform_entry
*entry
;
2173 /* first, try to append a single processor, then try again with a decoder and a processor */
2174 if ((allow_processor
&& SUCCEEDED(hr
= source_reader_create_transform(reader
, FALSE
, FALSE
, input_type
, output_type
, &entry
)))
2175 || SUCCEEDED(hr
= source_reader_create_transform(reader
, TRUE
, allow_processor
, input_type
, output_type
, &entry
)))
2177 struct list
*ptr
= list_head(&entry
->entry
);
2178 struct transform_entry
*service
= ptr
? LIST_ENTRY(ptr
, struct transform_entry
, entry
) : entry
;
2179 IMFMediaTypeHandler
*type_handler
;
2181 if (enable_advanced
)
2183 /* when advanced video processing is enabled, converters are exposed as stream transform service */
2184 stream
->transform_service
= service
->transform
;
2185 IMFTransform_AddRef(stream
->transform_service
);
2189 /* when advanced video processing is disabled, only decoders are exposed as stream transform service */
2190 if (IsEqualGUID(&entry
->category
, &MFT_CATEGORY_AUDIO_DECODER
)
2191 || IsEqualGUID(&entry
->category
, &MFT_CATEGORY_VIDEO_DECODER
))
2193 stream
->transform_service
= entry
->transform
;
2194 IMFTransform_AddRef(stream
->transform_service
);
2196 /* converters are hidden from the stream transforms */
2197 if (service
!= entry
)
2198 service
->hidden
= TRUE
;
2202 /* converters are hidden from the stream transforms */
2203 entry
->hidden
= TRUE
;
2207 /* move any additional transforms that have been created */
2208 list_move_head(&stream
->transforms
, &entry
->entry
);
2209 list_add_head(&stream
->transforms
, &entry
->entry
);
2211 if (SUCCEEDED(source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
2213 if (FAILED(hr
= IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, input_type
)))
2214 WARN("Failed to set current input media type, hr %#lx\n", hr
);
2215 IMFMediaTypeHandler_Release(type_handler
);
2218 if (FAILED(hr
= IMFTransform_GetOutputCurrentType(service
->transform
, 0, &output_type
)))
2219 WARN("Failed to get decoder output media type, hr %#lx\n", hr
);
2222 IMFMediaType_CopyAllItems(output_type
, (IMFAttributes
*)stream
->current
);
2223 IMFMediaType_Release(output_type
);
2226 IMFMediaType_Release(input_type
);
2230 IMFMediaType_Release(input_type
);
2233 return MF_E_TOPO_CODEC_NOT_FOUND
;
2236 static HRESULT WINAPI
src_reader_SetCurrentMediaType(IMFSourceReaderEx
*iface
, DWORD index
, DWORD
*reserved
,
2239 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2242 TRACE("%p, %#lx, %p, %p.\n", iface
, index
, reserved
, type
);
2246 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2247 index
= reader
->first_video_stream_index
;
2249 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2250 index
= reader
->first_audio_stream_index
;
2256 if (index
>= reader
->stream_count
)
2257 return MF_E_INVALIDSTREAMNUMBER
;
2259 /* FIXME: setting the output type while streaming should trigger a flush */
2261 EnterCriticalSection(&reader
->cs
);
2263 hr
= source_reader_set_compatible_media_type(reader
, index
, type
);
2265 hr
= source_reader_create_decoder_for_stream(reader
, index
, type
);
2267 hr
= source_reader_setup_sample_allocator(reader
, index
);
2269 LeaveCriticalSection(&reader
->cs
);
2274 static HRESULT WINAPI
src_reader_SetCurrentPosition(IMFSourceReaderEx
*iface
, REFGUID format
, REFPROPVARIANT position
)
2276 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2277 struct source_reader_async_command
*command
;
2282 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), position
);
2284 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2287 if (!(flags
& MFMEDIASOURCE_CAN_SEEK
))
2288 return MF_E_INVALIDREQUEST
;
2290 EnterCriticalSection(&reader
->cs
);
2292 /* Check if we got pending requests. */
2293 for (i
= 0; i
< reader
->stream_count
; ++i
)
2295 if (reader
->streams
[i
].requests
)
2297 hr
= MF_E_INVALIDREQUEST
;
2304 for (i
= 0; i
< reader
->stream_count
; ++i
)
2306 reader
->streams
[i
].last_sample_ts
= 0;
2309 if (reader
->async_callback
)
2311 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK
, &command
)))
2313 command
->u
.seek
.format
= *format
;
2314 PropVariantCopy(&command
->u
.seek
.position
, position
);
2316 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2317 IUnknown_Release(&command
->IUnknown_iface
);
2322 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, format
, position
)))
2324 reader
->flags
|= SOURCE_READER_SEEKING
;
2325 while (reader
->flags
& SOURCE_READER_SEEKING
)
2327 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2333 LeaveCriticalSection(&reader
->cs
);
2338 static HRESULT
source_reader_read_sample(struct source_reader
*reader
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
2339 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2341 struct media_stream
*stream
;
2342 DWORD actual_index_tmp
;
2343 LONGLONG timestamp_tmp
;
2347 if (!stream_flags
|| !sample
)
2353 timestamp
= ×tamp_tmp
;
2356 actual_index
= &actual_index_tmp
;
2358 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
2360 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, index
, &stream_index
)))
2362 *actual_index
= stream_index
;
2364 stream
= &reader
->streams
[stream_index
];
2366 if (!source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
2369 while (!source_reader_got_response_for_stream(reader
, stream
) && stream
->state
!= STREAM_STATE_EOS
)
2372 if (FAILED(hr
= source_reader_request_sample(reader
, stream
)))
2373 WARN("Failed to request a sample, hr %#lx.\n", hr
);
2374 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
2376 *stream_flags
= MF_SOURCE_READERF_ERROR
;
2380 SleepConditionVariableCS(&reader
->sample_event
, &reader
->cs
, INFINITE
);
2383 source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
2389 *actual_index
= index
;
2390 *stream_flags
= MF_SOURCE_READERF_ERROR
;
2395 TRACE("Stream %lu, got sample %p, flags %#lx.\n", *actual_index
, *sample
, *stream_flags
);
2400 static HRESULT
source_reader_read_sample_async(struct source_reader
*reader
, unsigned int index
, unsigned int flags
,
2401 DWORD
*actual_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2403 struct source_reader_async_command
*command
;
2406 if (actual_index
|| stream_flags
|| timestamp
|| sample
)
2407 return E_INVALIDARG
;
2409 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2410 hr
= MF_E_NOTACCEPTING
;
2413 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_READ
, &command
)))
2415 command
->u
.read
.stream_index
= index
;
2416 command
->u
.read
.flags
= flags
;
2418 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2419 IUnknown_Release(&command
->IUnknown_iface
);
2426 static HRESULT WINAPI
src_reader_ReadSample(IMFSourceReaderEx
*iface
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
2427 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2429 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2432 TRACE("%p, %#lx, %#lx, %p, %p, %p, %p\n", iface
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2434 EnterCriticalSection(&reader
->cs
);
2436 while (reader
->flags
& SOURCE_READER_SEEKING
)
2438 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2441 if (reader
->async_callback
)
2442 hr
= source_reader_read_sample_async(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2444 hr
= source_reader_read_sample(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2446 LeaveCriticalSection(&reader
->cs
);
2451 static HRESULT
source_reader_flush_async(struct source_reader
*reader
, unsigned int index
)
2453 struct source_reader_async_command
*command
;
2454 unsigned int stream_index
;
2457 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2458 return MF_E_INVALIDREQUEST
;
2462 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2463 stream_index
= reader
->first_video_stream_index
;
2465 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2466 stream_index
= reader
->first_audio_stream_index
;
2469 stream_index
= index
;
2472 reader
->flags
|= SOURCE_READER_FLUSHING
;
2474 if (stream_index
!= MF_SOURCE_READER_ALL_STREAMS
&& stream_index
>= reader
->stream_count
)
2475 return MF_E_INVALIDSTREAMNUMBER
;
2477 if (FAILED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH
, &command
)))
2480 command
->u
.flush
.stream_index
= stream_index
;
2482 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2483 IUnknown_Release(&command
->IUnknown_iface
);
2488 static HRESULT WINAPI
src_reader_Flush(IMFSourceReaderEx
*iface
, DWORD index
)
2490 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2493 TRACE("%p, %#lx.\n", iface
, index
);
2495 EnterCriticalSection(&reader
->cs
);
2497 if (reader
->async_callback
)
2498 hr
= source_reader_flush_async(reader
, index
);
2500 hr
= source_reader_flush(reader
, index
);
2502 LeaveCriticalSection(&reader
->cs
);
2507 static HRESULT WINAPI
src_reader_GetServiceForStream(IMFSourceReaderEx
*iface
, DWORD index
, REFGUID service
,
2508 REFIID riid
, void **object
)
2510 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2511 IUnknown
*obj
= NULL
;
2514 TRACE("%p, %#lx, %s, %s, %p\n", iface
, index
, debugstr_guid(service
), debugstr_guid(riid
), object
);
2516 EnterCriticalSection(&reader
->cs
);
2520 case MF_SOURCE_READER_MEDIASOURCE
:
2521 obj
= (IUnknown
*)reader
->source
;
2524 if (index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2525 index
= reader
->first_video_stream_index
;
2526 else if (index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2527 index
= reader
->first_audio_stream_index
;
2529 if (index
>= reader
->stream_count
)
2530 hr
= MF_E_INVALIDSTREAMNUMBER
;
2531 else if (!(obj
= (IUnknown
*)reader
->streams
[index
].transform_service
))
2537 IUnknown_AddRef(obj
);
2539 LeaveCriticalSection(&reader
->cs
);
2543 if (IsEqualGUID(service
, &GUID_NULL
))
2545 hr
= IUnknown_QueryInterface(obj
, riid
, object
);
2551 hr
= IUnknown_QueryInterface(obj
, &IID_IMFGetService
, (void **)&gs
);
2554 hr
= IMFGetService_GetService(gs
, service
, riid
, object
);
2555 IMFGetService_Release(gs
);
2561 IUnknown_Release(obj
);
2566 static HRESULT WINAPI
src_reader_GetPresentationAttribute(IMFSourceReaderEx
*iface
, DWORD index
,
2567 REFGUID guid
, PROPVARIANT
*value
)
2569 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2570 IMFStreamDescriptor
*sd
;
2574 TRACE("%p, %#lx, %s, %p.\n", iface
, index
, debugstr_guid(guid
), value
);
2578 case MF_SOURCE_READER_MEDIASOURCE
:
2579 if (IsEqualGUID(guid
, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS
))
2583 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2587 value
->ulVal
= flags
;
2592 return IMFPresentationDescriptor_GetItem(reader
->descriptor
, guid
, value
);
2595 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2596 index
= reader
->first_video_stream_index
;
2598 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2599 index
= reader
->first_audio_stream_index
;
2605 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
2608 hr
= IMFStreamDescriptor_GetItem(sd
, guid
, value
);
2609 IMFStreamDescriptor_Release(sd
);
2614 static HRESULT WINAPI
src_reader_SetNativeMediaType(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2615 IMFMediaType
*media_type
, DWORD
*stream_flags
)
2617 FIXME("%p, %#lx, %p, %p.\n", iface
, stream_index
, media_type
, stream_flags
);
2622 static HRESULT WINAPI
src_reader_AddTransformForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2623 IUnknown
*transform
)
2625 FIXME("%p, %#lx, %p.\n", iface
, stream_index
, transform
);
2630 static HRESULT WINAPI
src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
)
2632 FIXME("%p, %#lx.\n", iface
, stream_index
);
2637 static struct transform_entry
*get_transform_at_index(struct media_stream
*stream
, UINT index
)
2639 struct transform_entry
*entry
;
2641 LIST_FOR_EACH_ENTRY(entry
, &stream
->transforms
, struct transform_entry
, entry
)
2642 if (!entry
->hidden
&& !index
--)
2648 static HRESULT WINAPI
src_reader_GetTransformForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2649 DWORD transform_index
, GUID
*category
, IMFTransform
**transform
)
2651 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2652 struct transform_entry
*entry
;
2655 TRACE("%p, %#lx, %#lx, %p, %p.\n", iface
, stream_index
, transform_index
, category
, transform
);
2660 EnterCriticalSection(&reader
->cs
);
2662 if (stream_index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2663 stream_index
= reader
->first_video_stream_index
;
2664 else if (stream_index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2665 stream_index
= reader
->first_audio_stream_index
;
2667 if (stream_index
>= reader
->stream_count
)
2668 hr
= MF_E_INVALIDSTREAMNUMBER
;
2669 else if (!(entry
= get_transform_at_index(&reader
->streams
[stream_index
], transform_index
)))
2670 hr
= MF_E_INVALIDINDEX
;
2674 *category
= entry
->category
;
2675 *transform
= entry
->transform
;
2676 IMFTransform_AddRef(*transform
);
2680 LeaveCriticalSection(&reader
->cs
);
2685 static const IMFSourceReaderExVtbl srcreader_vtbl
=
2687 src_reader_QueryInterface
,
2690 src_reader_GetStreamSelection
,
2691 src_reader_SetStreamSelection
,
2692 src_reader_GetNativeMediaType
,
2693 src_reader_GetCurrentMediaType
,
2694 src_reader_SetCurrentMediaType
,
2695 src_reader_SetCurrentPosition
,
2696 src_reader_ReadSample
,
2698 src_reader_GetServiceForStream
,
2699 src_reader_GetPresentationAttribute
,
2700 src_reader_SetNativeMediaType
,
2701 src_reader_AddTransformForStream
,
2702 src_reader_RemoveAllTransformsForStream
,
2703 src_reader_GetTransformForStream
,
2706 static DWORD
reader_get_first_stream_index(IMFPresentationDescriptor
*descriptor
, const GUID
*major
)
2713 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
2714 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2716 for (i
= 0; i
< count
; ++i
)
2718 IMFMediaTypeHandler
*handler
;
2719 IMFStreamDescriptor
*sd
;
2721 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
, &selected
, &sd
)))
2723 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2724 IMFStreamDescriptor_Release(sd
);
2727 hr
= IMFMediaTypeHandler_GetMajorType(handler
, &guid
);
2728 IMFMediaTypeHandler_Release(handler
);
2731 WARN("Failed to get stream major type, hr %#lx.\n", hr
);
2735 if (IsEqualGUID(&guid
, major
))
2743 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2746 static HRESULT
create_source_reader_from_source(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2747 BOOL shutdown_on_release
, REFIID riid
, void **out
)
2749 struct source_reader
*object
;
2753 object
= calloc(1, sizeof(*object
));
2755 return E_OUTOFMEMORY
;
2757 object
->IMFSourceReaderEx_iface
.lpVtbl
= &srcreader_vtbl
;
2758 object
->source_events_callback
.lpVtbl
= &source_events_callback_vtbl
;
2759 object
->stream_events_callback
.lpVtbl
= &stream_events_callback_vtbl
;
2760 object
->async_commands_callback
.lpVtbl
= &async_commands_callback_vtbl
;
2761 object
->public_refcount
= 1;
2762 object
->refcount
= 1;
2763 list_init(&object
->responses
);
2764 if (shutdown_on_release
)
2765 object
->flags
|= SOURCE_READER_SHUTDOWN_ON_RELEASE
;
2766 object
->source
= source
;
2767 IMFMediaSource_AddRef(object
->source
);
2768 InitializeCriticalSection(&object
->cs
);
2769 InitializeConditionVariable(&object
->sample_event
);
2770 InitializeConditionVariable(&object
->state_event
);
2771 InitializeConditionVariable(&object
->stop_event
);
2773 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(object
->source
, &object
->descriptor
)))
2776 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(object
->descriptor
, &object
->stream_count
)))
2779 if (!(object
->streams
= calloc(object
->stream_count
, sizeof(*object
->streams
))))
2785 /* Set initial current media types. */
2786 for (i
= 0; i
< object
->stream_count
; ++i
)
2788 IMFMediaTypeHandler
*handler
;
2789 IMFStreamDescriptor
*sd
;
2790 IMFMediaType
*src_type
;
2793 list_init(&object
->streams
[i
].transforms
);
2795 if (FAILED(hr
= MFCreateMediaType(&object
->streams
[i
].current
)))
2798 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(object
->descriptor
, i
, &selected
, &sd
)))
2801 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &object
->streams
[i
].id
)))
2802 WARN("Failed to get stream identifier, hr %#lx.\n", hr
);
2804 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2805 IMFStreamDescriptor_Release(sd
);
2809 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, 0, &src_type
);
2810 IMFMediaTypeHandler_Release(handler
);
2814 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)object
->streams
[i
].current
);
2815 IMFMediaType_Release(src_type
);
2819 object
->streams
[i
].reader
= object
;
2820 object
->streams
[i
].index
= i
;
2826 /* At least one major type has to be set. */
2827 object
->first_audio_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Audio
);
2828 object
->first_video_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Video
);
2830 if (object
->first_audio_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
&&
2831 object
->first_video_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
)
2833 hr
= MF_E_ATTRIBUTENOTFOUND
;
2836 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(object
->source
, &object
->source_events_callback
,
2837 (IUnknown
*)object
->source
)))
2844 object
->attributes
= attributes
;
2845 IMFAttributes_AddRef(object
->attributes
);
2847 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_ASYNC_CALLBACK
, &IID_IMFSourceReaderCallback
,
2848 (void **)&object
->async_callback
);
2849 if (object
->async_callback
)
2850 TRACE("Using async callback %p.\n", object
->async_callback
);
2852 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_D3D_MANAGER
, &IID_IUnknown
, (void **)&object
->device_manager
);
2853 if (object
->device_manager
)
2855 IUnknown
*unk
= NULL
;
2857 if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IMFDXGIDeviceManager
, (void **)&unk
)))
2858 object
->flags
|= SOURCE_READER_DXGI_DEVICE_MANAGER
;
2859 else if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IDirect3DDeviceManager9
, (void **)&unk
)))
2860 object
->flags
|= SOURCE_READER_D3D9_DEVICE_MANAGER
;
2862 if (!(object
->flags
& (SOURCE_READER_HAS_DEVICE_MANAGER
)))
2864 WARN("Unknown device manager.\n");
2865 IUnknown_Release(object
->device_manager
);
2866 object
->device_manager
= NULL
;
2870 IUnknown_Release(unk
);
2874 if (FAILED(hr
= MFLockSharedWorkQueue(L
"", 0, NULL
, &object
->queue
)))
2875 WARN("Failed to acquired shared queue, hr %#lx.\n", hr
);
2878 hr
= IMFSourceReaderEx_QueryInterface(&object
->IMFSourceReaderEx_iface
, riid
, out
);
2881 IMFSourceReaderEx_Release(&object
->IMFSourceReaderEx_iface
);
2885 static HRESULT
create_source_reader_from_stream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2886 REFIID riid
, void **out
)
2888 IPropertyStore
*props
= NULL
;
2889 IMFSourceResolver
*resolver
;
2890 MF_OBJECT_TYPE obj_type
;
2891 IMFMediaSource
*source
;
2894 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2898 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2901 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, stream
, NULL
, MF_RESOLUTION_MEDIASOURCE
2902 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE
, props
, &obj_type
, (IUnknown
**)&source
);
2903 IMFSourceResolver_Release(resolver
);
2905 IPropertyStore_Release(props
);
2909 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2910 IMFMediaSource_Release(source
);
2914 static HRESULT
create_source_reader_from_url(const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2916 IPropertyStore
*props
= NULL
;
2917 IMFSourceResolver
*resolver
;
2918 IUnknown
*object
= NULL
;
2919 MF_OBJECT_TYPE obj_type
;
2920 IMFMediaSource
*source
;
2923 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2927 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2930 hr
= IMFSourceResolver_CreateObjectFromURL(resolver
, url
, MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
,
2936 case MF_OBJECT_BYTESTREAM
:
2937 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, (IMFByteStream
*)object
, NULL
,
2938 MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
, (IUnknown
**)&source
);
2940 case MF_OBJECT_MEDIASOURCE
:
2941 source
= (IMFMediaSource
*)object
;
2942 IMFMediaSource_AddRef(source
);
2945 WARN("Unknown object type %d.\n", obj_type
);
2948 IUnknown_Release(object
);
2951 IMFSourceResolver_Release(resolver
);
2953 IPropertyStore_Release(props
);
2957 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2958 IMFMediaSource_Release(source
);
2962 static HRESULT
create_source_reader_from_object(IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2964 IMFMediaSource
*source
= NULL
;
2965 IMFByteStream
*stream
= NULL
;
2968 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSource
, (void **)&source
);
2970 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2974 UINT32 disconnect
= 0;
2977 IMFAttributes_GetUINT32(attributes
, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN
, &disconnect
);
2978 hr
= create_source_reader_from_source(source
, attributes
, !disconnect
, riid
, out
);
2981 hr
= create_source_reader_from_stream(stream
, attributes
, riid
, out
);
2984 IMFMediaSource_Release(source
);
2986 IMFByteStream_Release(stream
);
2991 /***********************************************************************
2992 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2994 HRESULT WINAPI
MFCreateSourceReaderFromByteStream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2995 IMFSourceReader
**reader
)
2997 TRACE("%p, %p, %p.\n", stream
, attributes
, reader
);
2999 return create_source_reader_from_object((IUnknown
*)stream
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
3002 /***********************************************************************
3003 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
3005 HRESULT WINAPI
MFCreateSourceReaderFromMediaSource(IMFMediaSource
*source
, IMFAttributes
*attributes
,
3006 IMFSourceReader
**reader
)
3008 TRACE("%p, %p, %p.\n", source
, attributes
, reader
);
3010 return create_source_reader_from_object((IUnknown
*)source
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
3013 /***********************************************************************
3014 * MFCreateSourceReaderFromURL (mfreadwrite.@)
3016 HRESULT WINAPI
MFCreateSourceReaderFromURL(const WCHAR
*url
, IMFAttributes
*attributes
, IMFSourceReader
**reader
)
3018 TRACE("%s, %p, %p.\n", debugstr_w(url
), attributes
, reader
);
3020 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
3023 static HRESULT WINAPI
readwrite_factory_QueryInterface(IMFReadWriteClassFactory
*iface
, REFIID riid
, void **out
)
3025 if (IsEqualIID(riid
, &IID_IMFReadWriteClassFactory
) ||
3026 IsEqualIID(riid
, &IID_IUnknown
))
3029 IMFReadWriteClassFactory_AddRef(iface
);
3033 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
3035 return E_NOINTERFACE
;
3038 static ULONG WINAPI
readwrite_factory_AddRef(IMFReadWriteClassFactory
*iface
)
3043 static ULONG WINAPI
readwrite_factory_Release(IMFReadWriteClassFactory
*iface
)
3048 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
3049 const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
3051 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid
), debugstr_w(url
), attributes
, debugstr_guid(riid
), out
);
3053 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
3055 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, out
);
3057 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
3059 return create_sink_writer_from_url(url
, NULL
, attributes
, riid
, out
);
3062 FIXME("Unsupported %s.\n", debugstr_guid(clsid
));
3067 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
3068 IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
3072 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid
), unk
, attributes
, debugstr_guid(riid
), out
);
3074 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
3076 return create_source_reader_from_object(unk
, attributes
, riid
, out
);
3078 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
3080 IMFByteStream
*stream
= NULL
;
3081 IMFMediaSink
*sink
= NULL
;
3083 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
3085 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSink
, (void **)&sink
);
3088 hr
= create_sink_writer_from_url(NULL
, stream
, attributes
, riid
, out
);
3090 hr
= create_sink_writer_from_sink(sink
, attributes
, riid
, out
);
3093 IMFMediaSink_Release(sink
);
3095 IMFByteStream_Release(stream
);
3101 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
3107 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl
=
3109 readwrite_factory_QueryInterface
,
3110 readwrite_factory_AddRef
,
3111 readwrite_factory_Release
,
3112 readwrite_factory_CreateInstanceFromURL
,
3113 readwrite_factory_CreateInstanceFromObject
,
3116 static IMFReadWriteClassFactory readwrite_factory
= { &readwrite_factory_vtbl
};
3118 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **out
)
3120 TRACE("%s, %p.\n", debugstr_guid(riid
), out
);
3122 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
3123 IsEqualGUID(riid
, &IID_IUnknown
))
3125 IClassFactory_AddRef(iface
);
3130 WARN("interface %s not implemented\n", debugstr_guid(riid
));
3132 return E_NOINTERFACE
;
3135 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
3140 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
3145 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **out
)
3147 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), out
);
3152 return CLASS_E_NOAGGREGATION
;
3154 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory
, riid
, out
);
3157 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
3159 FIXME("%d.\n", dolock
);
3163 static const IClassFactoryVtbl classfactoryvtbl
=
3165 classfactory_QueryInterface
,
3166 classfactory_AddRef
,
3167 classfactory_Release
,
3168 classfactory_CreateInstance
,
3169 classfactory_LockServer
,
3172 static IClassFactory classfactory
= { &classfactoryvtbl
};
3174 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
3176 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
3178 if (IsEqualGUID(clsid
, &CLSID_MFReadWriteClassFactory
))
3179 return IClassFactory_QueryInterface(&classfactory
, riid
, out
);
3181 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
3183 return CLASS_E_CLASSNOTAVAILABLE
;