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 transform_entry
77 IMFTransform
*transform
;
78 unsigned int min_buffer_size
;
86 IMFMediaStream
*stream
;
87 IMFMediaType
*current
;
88 struct list transforms
;
89 IMFVideoSampleAllocatorEx
*allocator
;
90 IMFTransform
*transform_service
;
93 enum media_stream_state state
;
95 unsigned int requests
;
96 unsigned int responses
;
97 LONGLONG last_sample_ts
;
98 struct source_reader
*reader
;
101 enum source_reader_async_op
103 SOURCE_READER_ASYNC_READ
,
104 SOURCE_READER_ASYNC_SEEK
,
105 SOURCE_READER_ASYNC_FLUSH
,
106 SOURCE_READER_ASYNC_SAMPLE_READY
,
109 struct source_reader_async_command
111 IUnknown IUnknown_iface
;
113 enum source_reader_async_op op
;
119 unsigned int stream_index
;
124 PROPVARIANT position
;
128 unsigned int stream_index
;
132 unsigned int stream_index
;
136 unsigned int stream_index
;
141 enum source_reader_flags
143 SOURCE_READER_FLUSHING
= 0x1,
144 SOURCE_READER_SEEKING
= 0x2,
145 SOURCE_READER_SHUTDOWN_ON_RELEASE
= 0x4,
146 SOURCE_READER_D3D9_DEVICE_MANAGER
= 0x8,
147 SOURCE_READER_DXGI_DEVICE_MANAGER
= 0x10,
148 SOURCE_READER_HAS_DEVICE_MANAGER
= SOURCE_READER_D3D9_DEVICE_MANAGER
| SOURCE_READER_DXGI_DEVICE_MANAGER
,
153 IMFSourceReaderEx IMFSourceReaderEx_iface
;
154 IMFAsyncCallback source_events_callback
;
155 IMFAsyncCallback stream_events_callback
;
156 IMFAsyncCallback async_commands_callback
;
158 LONG public_refcount
;
159 IMFMediaSource
*source
;
160 IMFPresentationDescriptor
*descriptor
;
161 IMFSourceReaderCallback
*async_callback
;
162 IMFAttributes
*attributes
;
163 IUnknown
*device_manager
;
164 unsigned int first_audio_stream_index
;
165 unsigned int first_video_stream_index
;
169 enum media_source_state source_state
;
170 struct media_stream
*streams
;
171 struct list responses
;
173 CONDITION_VARIABLE sample_event
;
174 CONDITION_VARIABLE state_event
;
175 CONDITION_VARIABLE stop_event
;
178 static inline struct source_reader
*impl_from_IMFSourceReaderEx(IMFSourceReaderEx
*iface
)
180 return CONTAINING_RECORD(iface
, struct source_reader
, IMFSourceReaderEx_iface
);
183 static struct source_reader
*impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
185 return CONTAINING_RECORD(iface
, struct source_reader
, source_events_callback
);
188 static struct source_reader
*impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
190 return CONTAINING_RECORD(iface
, struct source_reader
, stream_events_callback
);
193 static struct source_reader
*impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
195 return CONTAINING_RECORD(iface
, struct source_reader
, async_commands_callback
);
198 static struct source_reader_async_command
*impl_from_async_command_IUnknown(IUnknown
*iface
)
200 return CONTAINING_RECORD(iface
, struct source_reader_async_command
, IUnknown_iface
);
203 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
);
205 static ULONG
source_reader_addref(struct source_reader
*reader
)
207 return InterlockedIncrement(&reader
->refcount
);
210 static void transform_entry_destroy(struct transform_entry
*entry
)
212 IMFTransform_Release(entry
->transform
);
216 static void media_stream_destroy(struct media_stream
*stream
)
218 struct transform_entry
*entry
, *next
;
220 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &stream
->transforms
, struct transform_entry
, entry
)
222 list_remove(&entry
->entry
);
223 transform_entry_destroy(entry
);
227 IMFMediaStream_Release(stream
->stream
);
229 IMFMediaType_Release(stream
->current
);
230 if (stream
->allocator
)
231 IMFVideoSampleAllocatorEx_Release(stream
->allocator
);
234 static ULONG
source_reader_release(struct source_reader
*reader
)
236 ULONG refcount
= InterlockedDecrement(&reader
->refcount
);
241 if (reader
->device_manager
)
242 IUnknown_Release(reader
->device_manager
);
243 if (reader
->async_callback
)
244 IMFSourceReaderCallback_Release(reader
->async_callback
);
245 if (reader
->descriptor
)
246 IMFPresentationDescriptor_Release(reader
->descriptor
);
247 if (reader
->attributes
)
248 IMFAttributes_Release(reader
->attributes
);
249 IMFMediaSource_Release(reader
->source
);
251 for (i
= 0; i
< reader
->stream_count
; ++i
)
253 struct media_stream
*stream
= &reader
->streams
[i
];
254 media_stream_destroy(stream
);
256 source_reader_release_responses(reader
, NULL
);
257 free(reader
->streams
);
258 MFUnlockWorkQueue(reader
->queue
);
259 DeleteCriticalSection(&reader
->cs
);
266 static HRESULT WINAPI
source_reader_async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
268 if (IsEqualIID(riid
, &IID_IUnknown
))
271 IUnknown_AddRef(iface
);
275 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
277 return E_NOINTERFACE
;
280 static ULONG WINAPI
source_reader_async_command_AddRef(IUnknown
*iface
)
282 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
283 return InterlockedIncrement(&command
->refcount
);
286 static ULONG WINAPI
source_reader_async_command_Release(IUnknown
*iface
)
288 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
289 ULONG refcount
= InterlockedIncrement(&command
->refcount
);
293 if (command
->op
== SOURCE_READER_ASYNC_SEEK
)
294 PropVariantClear(&command
->u
.seek
.position
);
301 static const IUnknownVtbl source_reader_async_command_vtbl
=
303 source_reader_async_command_QueryInterface
,
304 source_reader_async_command_AddRef
,
305 source_reader_async_command_Release
,
308 static HRESULT
source_reader_create_async_op(enum source_reader_async_op op
, struct source_reader_async_command
**ret
)
310 struct source_reader_async_command
*command
;
312 if (!(command
= calloc(1, sizeof(*command
))))
313 return E_OUTOFMEMORY
;
315 command
->IUnknown_iface
.lpVtbl
= &source_reader_async_command_vtbl
;
323 static HRESULT
media_event_get_object(IMFMediaEvent
*event
, REFIID riid
, void **obj
)
328 PropVariantInit(&value
);
329 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
331 WARN("Failed to get event value, hr %#lx.\n", hr
);
335 if (value
.vt
!= VT_UNKNOWN
|| !value
.punkVal
)
337 WARN("Unexpected value type %d.\n", value
.vt
);
338 PropVariantClear(&value
);
342 hr
= IUnknown_QueryInterface(value
.punkVal
, riid
, obj
);
343 PropVariantClear(&value
);
346 WARN("Unexpected object type.\n");
353 static HRESULT
media_stream_get_id(IMFMediaStream
*stream
, DWORD
*id
)
355 IMFStreamDescriptor
*sd
;
358 if (SUCCEEDED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
360 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, id
);
361 IMFStreamDescriptor_Release(sd
);
367 static HRESULT WINAPI
source_reader_callback_QueryInterface(IMFAsyncCallback
*iface
,
368 REFIID riid
, void **obj
)
370 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
372 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
373 IsEqualIID(riid
, &IID_IUnknown
))
376 IMFAsyncCallback_AddRef(iface
);
380 WARN("Unsupported %s.\n", debugstr_guid(riid
));
382 return E_NOINTERFACE
;
385 static ULONG WINAPI
source_reader_source_events_callback_AddRef(IMFAsyncCallback
*iface
)
387 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
388 return source_reader_addref(reader
);
391 static ULONG WINAPI
source_reader_source_events_callback_Release(IMFAsyncCallback
*iface
)
393 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
394 return source_reader_release(reader
);
397 static HRESULT WINAPI
source_reader_callback_GetParameters(IMFAsyncCallback
*iface
,
398 DWORD
*flags
, DWORD
*queue
)
403 static void source_reader_response_ready(struct source_reader
*reader
, struct stream_response
*response
)
405 struct source_reader_async_command
*command
;
406 struct media_stream
*stream
= &reader
->streams
[response
->stream_index
];
409 if (!stream
->requests
)
412 if (reader
->async_callback
)
414 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY
, &command
)))
416 command
->u
.sample
.stream_index
= stream
->index
;
417 if (FAILED(hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
)))
418 WARN("Failed to submit async result, hr %#lx.\n", hr
);
419 IUnknown_Release(&command
->IUnknown_iface
);
423 WakeAllConditionVariable(&reader
->sample_event
);
428 static void source_reader_copy_sample_buffer(IMFSample
*src
, IMFSample
*dst
)
430 IMFMediaBuffer
*buffer
;
435 IMFSample_CopyAllItems(src
, (IMFAttributes
*)dst
);
437 IMFSample_SetSampleDuration(dst
, 0);
438 IMFSample_SetSampleTime(dst
, 0);
439 IMFSample_SetSampleFlags(dst
, 0);
441 if (SUCCEEDED(IMFSample_GetSampleDuration(src
, &time
)))
442 IMFSample_SetSampleDuration(dst
, time
);
444 if (SUCCEEDED(IMFSample_GetSampleTime(src
, &time
)))
445 IMFSample_SetSampleTime(dst
, time
);
447 if (SUCCEEDED(IMFSample_GetSampleFlags(src
, &flags
)))
448 IMFSample_SetSampleFlags(dst
, flags
);
450 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src
, NULL
)))
452 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst
, 0, &buffer
)))
454 if (FAILED(hr
= IMFSample_CopyToBuffer(src
, buffer
)))
455 WARN("Failed to copy a buffer, hr %#lx.\n", hr
);
456 IMFMediaBuffer_Release(buffer
);
461 static HRESULT
source_reader_queue_response(struct source_reader
*reader
, struct media_stream
*stream
, HRESULT status
,
462 DWORD stream_flags
, LONGLONG timestamp
, IMFSample
*sample
)
464 struct stream_response
*response
;
466 if (!(response
= calloc(1, sizeof(*response
))))
467 return E_OUTOFMEMORY
;
469 response
->status
= status
;
470 response
->stream_index
= stream
->index
;
471 response
->stream_flags
= stream_flags
;
472 response
->timestamp
= timestamp
;
473 response
->sample
= sample
;
474 if (response
->sample
)
475 IMFSample_AddRef(response
->sample
);
477 list_add_tail(&reader
->responses
, &response
->entry
);
480 source_reader_response_ready(reader
, response
);
482 stream
->last_sample_ts
= timestamp
;
487 static HRESULT
source_reader_queue_sample(struct source_reader
*reader
, struct media_stream
*stream
,
488 UINT flags
, IMFSample
*sample
)
490 LONGLONG timestamp
= 0;
492 if (FAILED(IMFSample_GetSampleTime(sample
, ×tamp
)))
493 WARN("Sample time wasn't set.\n");
495 return source_reader_queue_response(reader
, stream
, S_OK
, flags
, timestamp
, sample
);
498 static HRESULT
source_reader_request_sample(struct source_reader
*reader
, struct media_stream
*stream
)
502 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
504 if (FAILED(hr
= IMFMediaStream_RequestSample(stream
->stream
, NULL
)))
505 WARN("Sample request failed, hr %#lx.\n", hr
);
508 stream
->flags
|= STREAM_FLAG_SAMPLE_REQUESTED
;
515 static HRESULT
source_reader_new_stream_handler(struct source_reader
*reader
, IMFMediaEvent
*event
)
517 IMFMediaStream
*stream
;
522 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFMediaStream
, (void **)&stream
)))
524 WARN("Failed to get stream object, hr %#lx.\n", hr
);
528 TRACE("Got new stream %p.\n", stream
);
530 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
532 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
533 IMFMediaStream_Release(stream
);
537 EnterCriticalSection(&reader
->cs
);
539 for (i
= 0; i
< reader
->stream_count
; ++i
)
541 if (id
== reader
->streams
[i
].id
)
543 if (!reader
->streams
[i
].stream
)
545 reader
->streams
[i
].stream
= stream
;
546 IMFMediaStream_AddRef(reader
->streams
[i
].stream
);
547 if (FAILED(hr
= IMFMediaStream_BeginGetEvent(stream
, &reader
->stream_events_callback
,
548 (IUnknown
*)stream
)))
550 WARN("Failed to subscribe to stream events, hr %#lx.\n", hr
);
553 if (reader
->streams
[i
].requests
)
554 if (FAILED(source_reader_request_sample(reader
, &reader
->streams
[i
])))
555 WakeAllConditionVariable(&reader
->sample_event
);
561 if (i
== reader
->stream_count
)
562 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id
);
564 LeaveCriticalSection(&reader
->cs
);
566 IMFMediaStream_Release(stream
);
571 static HRESULT
source_reader_source_state_handler(struct source_reader
*reader
, MediaEventType event_type
)
573 EnterCriticalSection(&reader
->cs
);
577 case MESourceStarted
:
578 reader
->source_state
= SOURCE_STATE_STARTED
;
579 reader
->flags
&= ~SOURCE_READER_SEEKING
;
581 case MESourceStopped
:
582 reader
->source_state
= SOURCE_STATE_STOPPED
;
583 reader
->flags
&= ~SOURCE_READER_SEEKING
;
586 reader
->flags
&= ~SOURCE_READER_SEEKING
;
589 WARN("Unhandled event %ld.\n", event_type
);
592 LeaveCriticalSection(&reader
->cs
);
594 WakeAllConditionVariable(&reader
->state_event
);
595 if (event_type
== MESourceStopped
)
596 WakeAllConditionVariable(&reader
->stop_event
);
601 static HRESULT WINAPI
source_reader_source_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
603 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
604 MediaEventType event_type
;
605 IMFMediaSource
*source
;
606 IMFMediaEvent
*event
;
609 TRACE("%p, %p.\n", iface
, result
);
611 source
= (IMFMediaSource
*)IMFAsyncResult_GetStateNoAddRef(result
);
613 if (FAILED(hr
= IMFMediaSource_EndGetEvent(source
, result
, &event
)))
616 IMFMediaEvent_GetType(event
, &event_type
);
618 TRACE("Got event %lu.\n", event_type
);
623 hr
= source_reader_new_stream_handler(reader
, event
);
625 case MESourceStarted
:
627 case MESourceStopped
:
629 hr
= source_reader_source_state_handler(reader
, event_type
);
631 case MEBufferingStarted
:
632 case MEBufferingStopped
:
636 case MESourceCharacteristicsChanged
:
637 case MESourceMetadataChanged
:
638 case MEContentProtectionMetadata
:
639 case MEDeviceThermalStateChanged
:
640 if (reader
->async_callback
)
641 IMFSourceReaderCallback_OnEvent(reader
->async_callback
, MF_SOURCE_READER_MEDIASOURCE
, event
);
648 WARN("Failed while handling %ld event, hr %#lx.\n", event_type
, hr
);
650 IMFMediaEvent_Release(event
);
652 if (event_type
!= MESourceStopped
)
653 IMFMediaSource_BeginGetEvent(source
, iface
, (IUnknown
*)source
);
658 static const IMFAsyncCallbackVtbl source_events_callback_vtbl
=
660 source_reader_callback_QueryInterface
,
661 source_reader_source_events_callback_AddRef
,
662 source_reader_source_events_callback_Release
,
663 source_reader_callback_GetParameters
,
664 source_reader_source_events_callback_Invoke
,
667 static ULONG WINAPI
source_reader_stream_events_callback_AddRef(IMFAsyncCallback
*iface
)
669 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
670 return source_reader_addref(reader
);
673 static ULONG WINAPI
source_reader_stream_events_callback_Release(IMFAsyncCallback
*iface
)
675 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
676 return source_reader_release(reader
);
679 static HRESULT
source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO
*info
, IMFSample
**out
)
681 IMFMediaBuffer
*buffer
;
686 if (FAILED(hr
= MFCreateSample(&sample
)))
688 if (SUCCEEDED(hr
= MFCreateAlignedMemoryBuffer(info
->cbSize
, info
->cbAlignment
, &buffer
)))
690 if (SUCCEEDED(hr
= IMFSample_AddBuffer(sample
, buffer
)))
693 IMFSample_AddRef(sample
);
695 IMFMediaBuffer_Release(buffer
);
698 IMFSample_Release(sample
);
702 static void media_type_try_copy_attr(IMFMediaType
*dst
, IMFMediaType
*src
, const GUID
*attr
, HRESULT
*hr
)
706 PropVariantInit(&value
);
707 if (SUCCEEDED(*hr
) && FAILED(IMFMediaType_GetItem(dst
, attr
, NULL
))
708 && SUCCEEDED(IMFMediaType_GetItem(src
, attr
, &value
)))
709 *hr
= IMFMediaType_SetItem(dst
, attr
, &value
);
710 PropVariantClear(&value
);
713 /* update a media type with additional attributes reported by upstream element */
714 /* also present in mf/topology_loader.c pipeline */
715 static HRESULT
update_media_type_from_upstream(IMFMediaType
*media_type
, IMFMediaType
*upstream_type
)
719 /* propagate common video attributes */
720 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FRAME_SIZE
, &hr
);
721 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FRAME_RATE
, &hr
);
722 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_DEFAULT_STRIDE
, &hr
);
723 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_ROTATION
, &hr
);
724 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FIXED_SIZE_SAMPLES
, &hr
);
725 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_PIXEL_ASPECT_RATIO
, &hr
);
726 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, &hr
);
727 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
, &hr
);
729 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_CHROMA_SITING
, &hr
);
730 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_INTERLACE_MODE
, &hr
);
731 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_TRANSFER_FUNCTION
, &hr
);
732 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_PRIMARIES
, &hr
);
733 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_YUV_MATRIX
, &hr
);
734 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_LIGHTING
, &hr
);
735 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_NOMINAL_RANGE
, &hr
);
737 /* propagate common audio attributes */
738 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_NUM_CHANNELS
, &hr
);
739 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &hr
);
740 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_BITS_PER_SAMPLE
, &hr
);
741 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_SAMPLES_PER_SECOND
, &hr
);
742 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
, &hr
);
743 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_CHANNEL_MASK
, &hr
);
744 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_SAMPLES_PER_BLOCK
, &hr
);
745 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE
, &hr
);
750 static HRESULT
source_reader_pull_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
751 struct transform_entry
*entry
);
752 static HRESULT
source_reader_push_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
753 struct transform_entry
*entry
, IMFSample
*sample
)
759 if (FAILED(hr
= source_reader_pull_transform_samples(reader
, stream
, entry
))
760 && hr
!= MF_E_TRANSFORM_NEED_MORE_INPUT
)
762 if (SUCCEEDED(hr
= IMFTransform_ProcessInput(entry
->transform
, 0, sample
, 0)))
763 return source_reader_pull_transform_samples(reader
, stream
, entry
);
765 while (hr
== MF_E_NOTACCEPTING
);
770 static HRESULT
source_reader_pull_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
771 struct transform_entry
*entry
)
773 MFT_OUTPUT_STREAM_INFO stream_info
= {0};
774 struct transform_entry
*next
= NULL
;
779 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
780 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
782 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(entry
->transform
, 0, &stream_info
)))
784 stream_info
.cbSize
= max(stream_info
.cbSize
, entry
->min_buffer_size
);
786 while (SUCCEEDED(hr
))
788 MFT_OUTPUT_DATA_BUFFER out_buffer
= {0};
789 IMFMediaType
*output_type
, *media_type
;
791 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
))
792 && FAILED(hr
= source_reader_allocate_stream_sample(&stream_info
, &out_buffer
.pSample
)))
795 if (SUCCEEDED(hr
= IMFTransform_ProcessOutput(entry
->transform
, 0, 1, &out_buffer
, &status
)))
797 if ((entry
->pending_flags
& MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED
)
798 && SUCCEEDED(hr
= IMFTransform_GetOutputCurrentType(entry
->transform
, 0, &output_type
)))
801 hr
= IMFMediaType_CopyAllItems(output_type
, (IMFAttributes
*)stream
->current
);
802 else if (SUCCEEDED(hr
= IMFTransform_SetInputType(next
->transform
, 0, output_type
, 0)))
804 /* check if transform output type is still valid or if we need to reset it as well */
805 if (FAILED(hr
= IMFTransform_GetOutputCurrentType(next
->transform
, 0, &media_type
))
806 && SUCCEEDED(hr
= IMFTransform_GetOutputAvailableType(next
->transform
, 0, 0, &output_type
)))
808 next
->pending_flags
|= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED
;
809 hr
= IMFTransform_SetOutputType(entry
->transform
, 0, media_type
, 0);
810 IMFMediaType_Release(media_type
);
813 IMFMediaType_Release(output_type
);
817 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
819 hr
= source_reader_push_transform_samples(reader
, stream
, next
, out_buffer
.pSample
);
821 hr
= source_reader_queue_sample(reader
, stream
, entry
->pending_flags
, out_buffer
.pSample
);
823 entry
->pending_flags
= 0;
826 if (hr
== MF_E_TRANSFORM_STREAM_CHANGE
&& SUCCEEDED(hr
= IMFTransform_GetOutputAvailableType(entry
->transform
, 0, 0, &output_type
)))
828 hr
= IMFTransform_SetOutputType(entry
->transform
, 0, output_type
, 0);
829 IMFMediaType_Release(output_type
);
833 hr
= IMFTransform_GetOutputStreamInfo(entry
->transform
, 0, &stream_info
);
834 stream_info
.cbSize
= max(stream_info
.cbSize
, entry
->min_buffer_size
);
835 entry
->pending_flags
|= MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED
;
839 if (out_buffer
.pSample
)
840 IMFSample_Release(out_buffer
.pSample
);
841 if (out_buffer
.pEvents
)
842 IMFCollection_Release(out_buffer
.pEvents
);
848 static HRESULT
source_reader_drain_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
849 struct transform_entry
*entry
)
851 struct transform_entry
*next
= NULL
;
855 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
856 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
858 if (FAILED(hr
= IMFTransform_ProcessMessage(entry
->transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
859 WARN("Failed to drain transform %p, hr %#lx\n", entry
->transform
, hr
);
860 if (FAILED(hr
= source_reader_pull_transform_samples(reader
, stream
, entry
))
861 && hr
!= MF_E_TRANSFORM_NEED_MORE_INPUT
)
862 WARN("Failed to pull pending samples, hr %#lx.\n", hr
);
864 return next
? source_reader_drain_transform_samples(reader
, stream
, next
) : S_OK
;
867 static HRESULT
source_reader_flush_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
868 struct transform_entry
*entry
)
870 struct transform_entry
*next
= NULL
;
874 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
875 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
877 if (FAILED(hr
= IMFTransform_ProcessMessage(entry
->transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0)))
878 WARN("Failed to flush transform %p, hr %#lx\n", entry
->transform
, hr
);
880 return next
? source_reader_flush_transform_samples(reader
, stream
, next
) : S_OK
;
883 static HRESULT
source_reader_process_sample(struct source_reader
*reader
, struct media_stream
*stream
,
886 struct transform_entry
*entry
;
890 if (!(ptr
= list_head(&stream
->transforms
)))
891 return source_reader_queue_sample(reader
, stream
, 0, sample
);
892 entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
894 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
895 if (SUCCEEDED(hr
= source_reader_push_transform_samples(reader
, stream
, entry
, sample
))
896 || hr
== MF_E_TRANSFORM_NEED_MORE_INPUT
)
897 hr
= stream
->requests
? source_reader_request_sample(reader
, stream
) : S_OK
;
899 WARN("Transform failed to process output, hr %#lx.\n", hr
);
904 static HRESULT
source_reader_media_sample_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
905 IMFMediaEvent
*event
)
912 TRACE("Got new sample for stream %p.\n", stream
);
914 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFSample
, (void **)&sample
)))
916 WARN("Failed to get sample object, hr %#lx.\n", hr
);
920 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
922 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
923 IMFSample_Release(sample
);
927 EnterCriticalSection(&reader
->cs
);
929 for (i
= 0; i
< reader
->stream_count
; ++i
)
931 if (id
== reader
->streams
[i
].id
)
933 /* FIXME: propagate processing errors? */
934 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
935 hr
= source_reader_process_sample(reader
, &reader
->streams
[i
], sample
);
940 if (i
== reader
->stream_count
)
941 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id
);
943 LeaveCriticalSection(&reader
->cs
);
945 IMFSample_Release(sample
);
950 static HRESULT
source_reader_media_stream_state_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
951 IMFMediaEvent
*event
)
953 MediaEventType event_type
;
960 IMFMediaEvent_GetType(event
, &event_type
);
962 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
964 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
968 EnterCriticalSection(&reader
->cs
);
970 for (i
= 0; i
< reader
->stream_count
; ++i
)
972 struct media_stream
*stream
= &reader
->streams
[i
];
974 if (id
== stream
->id
)
982 stream
->state
= STREAM_STATE_EOS
;
983 stream
->flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
985 if ((ptr
= list_head(&stream
->transforms
)))
987 struct transform_entry
*entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
988 if (FAILED(hr
= source_reader_drain_transform_samples(reader
, stream
, entry
)))
989 WARN("Failed to drain pending samples, hr %#lx.\n", hr
);
992 while (stream
->requests
)
993 source_reader_queue_response(reader
, stream
, S_OK
, MF_SOURCE_READERF_ENDOFSTREAM
, 0, NULL
);
998 case MEStreamStarted
:
999 stream
->state
= STREAM_STATE_READY
;
1001 case MEStreamStopped
:
1002 stream
->flags
|= STREAM_FLAG_STOPPED
;
1005 value
.vt
= VT_EMPTY
;
1006 hr
= SUCCEEDED(IMFMediaEvent_GetValue(event
, &value
)) && value
.vt
== VT_I8
? S_OK
: E_UNEXPECTED
;
1007 timestamp
= SUCCEEDED(hr
) ? value
.hVal
.QuadPart
: 0;
1008 PropVariantClear(&value
);
1010 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_STREAMTICK
, timestamp
, NULL
);
1021 LeaveCriticalSection(&reader
->cs
);
1023 if (event_type
== MEStreamStopped
)
1024 WakeAllConditionVariable(&reader
->stop_event
);
1029 static HRESULT WINAPI
source_reader_stream_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1031 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
1032 MediaEventType event_type
;
1033 IMFMediaStream
*stream
;
1034 IMFMediaEvent
*event
;
1037 TRACE("%p, %p.\n", iface
, result
);
1039 stream
= (IMFMediaStream
*)IMFAsyncResult_GetStateNoAddRef(result
);
1041 if (FAILED(hr
= IMFMediaStream_EndGetEvent(stream
, result
, &event
)))
1044 IMFMediaEvent_GetType(event
, &event_type
);
1046 TRACE("Got event %lu.\n", event_type
);
1051 hr
= source_reader_media_sample_handler(reader
, stream
, event
);
1053 case MEStreamSeeked
:
1054 case MEStreamStarted
:
1055 case MEStreamStopped
:
1058 hr
= source_reader_media_stream_state_handler(reader
, stream
, event
);
1065 WARN("Failed while handling %ld event, hr %#lx.\n", event_type
, hr
);
1067 IMFMediaEvent_Release(event
);
1069 if (event_type
!= MEStreamStopped
)
1070 IMFMediaStream_BeginGetEvent(stream
, iface
, (IUnknown
*)stream
);
1075 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl
=
1077 source_reader_callback_QueryInterface
,
1078 source_reader_stream_events_callback_AddRef
,
1079 source_reader_stream_events_callback_Release
,
1080 source_reader_callback_GetParameters
,
1081 source_reader_stream_events_callback_Invoke
,
1084 static ULONG WINAPI
source_reader_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
1086 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1087 return source_reader_addref(reader
);
1090 static ULONG WINAPI
source_reader_async_commands_callback_Release(IMFAsyncCallback
*iface
)
1092 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1093 return source_reader_release(reader
);
1096 static struct stream_response
* media_stream_detach_response(struct source_reader
*reader
, struct stream_response
*response
)
1098 struct media_stream
*stream
;
1100 list_remove(&response
->entry
);
1102 if (response
->stream_index
< reader
->stream_count
)
1104 stream
= &reader
->streams
[response
->stream_index
];
1105 if (stream
->responses
)
1106 --stream
->responses
;
1112 static struct stream_response
*media_stream_pop_response(struct source_reader
*reader
, struct media_stream
*stream
)
1114 struct stream_response
*response
;
1118 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1120 if (stream
&& response
->stream_index
!= stream
->index
)
1123 if (!stream
) stream
= &reader
->streams
[response
->stream_index
];
1125 if (response
->sample
&& stream
->allocator
)
1127 /* Return allocation error to the caller, while keeping original response sample in for later. */
1128 if (SUCCEEDED(hr
= IMFVideoSampleAllocatorEx_AllocateSample(stream
->allocator
, &sample
)))
1130 source_reader_copy_sample_buffer(response
->sample
, sample
);
1131 IMFSample_Release(response
->sample
);
1132 response
->sample
= sample
;
1136 if (!(response
= calloc(1, sizeof(*response
))))
1139 response
->status
= hr
;
1140 response
->stream_flags
= MF_SOURCE_READERF_ERROR
;
1145 return media_stream_detach_response(reader
, response
);
1151 static void source_reader_release_response(struct stream_response
*response
)
1153 if (response
->sample
)
1154 IMFSample_Release(response
->sample
);
1158 static HRESULT
source_reader_get_stream_selection(const struct source_reader
*reader
, DWORD index
, BOOL
*selected
)
1160 IMFStreamDescriptor
*sd
;
1162 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, selected
, &sd
)))
1163 return MF_E_INVALIDSTREAMNUMBER
;
1164 IMFStreamDescriptor_Release(sd
);
1169 static HRESULT
source_reader_start_source(struct source_reader
*reader
)
1171 BOOL selected
, selection_changed
= FALSE
;
1172 PROPVARIANT position
;
1176 for (i
= 0; i
< reader
->stream_count
; ++i
)
1178 source_reader_get_stream_selection(reader
, i
, &selected
);
1180 reader
->streams
[i
].flags
|= STREAM_FLAG_SELECTED
;
1182 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SELECTED
;
1185 if (reader
->source_state
== SOURCE_STATE_STARTED
)
1187 for (i
= 0; i
< reader
->stream_count
; ++i
)
1189 selection_changed
= !!(reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
) ^
1190 !!(reader
->streams
[i
].flags
& STREAM_FLAG_PRESENTED
);
1191 if (selection_changed
)
1196 position
.hVal
.QuadPart
= 0;
1197 if (reader
->source_state
!= SOURCE_STATE_STARTED
|| selection_changed
)
1199 position
.vt
= reader
->source_state
== SOURCE_STATE_STARTED
? VT_EMPTY
: VT_I8
;
1201 /* Update cached stream selection if descriptor was accepted. */
1202 if (SUCCEEDED(hr
= IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &GUID_NULL
, &position
)))
1204 for (i
= 0; i
< reader
->stream_count
; ++i
)
1206 if (reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
)
1207 reader
->streams
[i
].flags
|= STREAM_FLAG_PRESENTED
;
1215 static BOOL
source_reader_got_response_for_stream(struct source_reader
*reader
, struct media_stream
*stream
)
1217 struct stream_response
*response
;
1219 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1221 if (response
->stream_index
== stream
->index
)
1228 static BOOL
source_reader_get_read_result(struct source_reader
*reader
, struct media_stream
*stream
, DWORD flags
,
1229 HRESULT
*status
, DWORD
*stream_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1231 struct stream_response
*response
= NULL
;
1232 BOOL request_sample
= FALSE
;
1234 if ((response
= media_stream_pop_response(reader
, stream
)))
1236 *status
= response
->status
;
1237 *stream_index
= stream
->index
;
1238 *stream_flags
= response
->stream_flags
;
1239 *timestamp
= response
->timestamp
;
1240 *sample
= response
->sample
;
1242 IMFSample_AddRef(*sample
);
1244 source_reader_release_response(response
);
1249 *stream_index
= stream
->index
;
1253 if (stream
->state
== STREAM_STATE_EOS
)
1255 *stream_flags
= MF_SOURCE_READERF_ENDOFSTREAM
;
1259 request_sample
= !(flags
& MF_SOURCE_READER_CONTROLF_DRAIN
);
1264 return !request_sample
;
1267 static HRESULT
source_reader_get_next_selected_stream(struct source_reader
*reader
, DWORD
*stream_index
)
1269 unsigned int i
, first_selected
= ~0u;
1270 BOOL selected
, stream_drained
;
1271 LONGLONG min_ts
= MAXLONGLONG
;
1273 for (i
= 0; i
< reader
->stream_count
; ++i
)
1275 stream_drained
= reader
->streams
[i
].state
== STREAM_STATE_EOS
&& !reader
->streams
[i
].responses
;
1276 selected
= SUCCEEDED(source_reader_get_stream_selection(reader
, i
, &selected
)) && selected
;
1280 if (first_selected
== ~0u)
1283 /* Pick the stream whose last sample had the lowest timestamp. */
1284 if (!stream_drained
&& reader
->streams
[i
].last_sample_ts
< min_ts
)
1286 min_ts
= reader
->streams
[i
].last_sample_ts
;
1292 /* If all selected streams reached EOS, use first selected. */
1293 if (first_selected
!= ~0u)
1295 if (min_ts
== MAXLONGLONG
)
1296 *stream_index
= first_selected
;
1299 return first_selected
== ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED
: S_OK
;
1302 static HRESULT
source_reader_get_stream_read_index(struct source_reader
*reader
, unsigned int index
, DWORD
*stream_index
)
1309 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1310 *stream_index
= reader
->first_video_stream_index
;
1312 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1313 *stream_index
= reader
->first_audio_stream_index
;
1315 case MF_SOURCE_READER_ANY_STREAM
:
1316 return source_reader_get_next_selected_stream(reader
, stream_index
);
1318 *stream_index
= index
;
1321 /* Can't read from deselected streams. */
1322 if (SUCCEEDED(hr
= source_reader_get_stream_selection(reader
, *stream_index
, &selected
)) && !selected
)
1323 hr
= MF_E_INVALIDREQUEST
;
1328 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
)
1330 struct stream_response
*ptr
, *next
;
1332 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &reader
->responses
, struct stream_response
, entry
)
1334 if (stream
&& stream
->index
!= ptr
->stream_index
&&
1335 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_VIDEO_STREAM
&&
1336 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_AUDIO_STREAM
&&
1337 ptr
->stream_index
!= MF_SOURCE_READER_ANY_STREAM
)
1341 media_stream_detach_response(reader
, ptr
);
1342 source_reader_release_response(ptr
);
1346 static void source_reader_flush_stream(struct source_reader
*reader
, DWORD stream_index
)
1348 struct media_stream
*stream
= &reader
->streams
[stream_index
];
1352 source_reader_release_responses(reader
, stream
);
1354 if ((ptr
= list_head(&stream
->transforms
)))
1356 struct transform_entry
*entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
1357 if (FAILED(hr
= source_reader_flush_transform_samples(reader
, stream
, entry
)))
1358 WARN("Failed to drain pending samples, hr %#lx.\n", hr
);
1361 stream
->requests
= 0;
1364 static HRESULT
source_reader_flush(struct source_reader
*reader
, unsigned int index
)
1366 unsigned int stream_index
;
1369 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1371 for (stream_index
= 0; stream_index
< reader
->stream_count
; ++stream_index
)
1372 source_reader_flush_stream(reader
, stream_index
);
1378 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1379 stream_index
= reader
->first_video_stream_index
;
1381 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1382 stream_index
= reader
->first_audio_stream_index
;
1385 stream_index
= index
;
1388 if (stream_index
< reader
->stream_count
)
1389 source_reader_flush_stream(reader
, stream_index
);
1391 hr
= MF_E_INVALIDSTREAMNUMBER
;
1397 static HRESULT WINAPI
source_reader_async_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1399 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1400 struct media_stream
*stream
, stub_stream
= { .requests
= 1 };
1401 struct source_reader_async_command
*command
;
1402 struct stream_response
*response
;
1403 DWORD stream_index
, stream_flags
;
1404 BOOL report_sample
= FALSE
;
1405 IMFSample
*sample
= NULL
;
1406 LONGLONG timestamp
= 0;
1410 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
1413 command
= impl_from_async_command_IUnknown(state
);
1415 switch (command
->op
)
1417 case SOURCE_READER_ASYNC_READ
:
1418 EnterCriticalSection(&reader
->cs
);
1420 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1422 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, command
->u
.read
.stream_index
, &stream_index
)))
1424 stream
= &reader
->streams
[stream_index
];
1426 if (!(report_sample
= source_reader_get_read_result(reader
, stream
, command
->u
.read
.flags
, &status
,
1427 &stream_index
, &stream_flags
, ×tamp
, &sample
)))
1430 source_reader_request_sample(reader
, stream
);
1431 /* FIXME: set error stream/reader state on request failure */
1436 stub_stream
.index
= command
->u
.read
.stream_index
;
1437 source_reader_queue_response(reader
, &stub_stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
1441 LeaveCriticalSection(&reader
->cs
);
1444 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, status
, stream_index
, stream_flags
,
1448 IMFSample_Release(sample
);
1452 case SOURCE_READER_ASYNC_SEEK
:
1454 EnterCriticalSection(&reader
->cs
);
1455 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &command
->u
.seek
.format
,
1456 &command
->u
.seek
.position
)))
1458 reader
->flags
|= SOURCE_READER_SEEKING
;
1460 LeaveCriticalSection(&reader
->cs
);
1464 case SOURCE_READER_ASYNC_SAMPLE_READY
:
1466 EnterCriticalSection(&reader
->cs
);
1467 response
= media_stream_pop_response(reader
, NULL
);
1468 LeaveCriticalSection(&reader
->cs
);
1472 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, response
->status
, response
->stream_index
,
1473 response
->stream_flags
, response
->timestamp
, response
->sample
);
1474 source_reader_release_response(response
);
1478 case SOURCE_READER_ASYNC_FLUSH
:
1479 EnterCriticalSection(&reader
->cs
);
1480 source_reader_flush(reader
, command
->u
.flush
.stream_index
);
1481 reader
->flags
&= ~SOURCE_READER_FLUSHING
;
1482 LeaveCriticalSection(&reader
->cs
);
1484 IMFSourceReaderCallback_OnFlush(reader
->async_callback
, command
->u
.flush
.stream_index
);
1490 IUnknown_Release(state
);
1495 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl
=
1497 source_reader_callback_QueryInterface
,
1498 source_reader_async_commands_callback_AddRef
,
1499 source_reader_async_commands_callback_Release
,
1500 source_reader_callback_GetParameters
,
1501 source_reader_async_commands_callback_Invoke
,
1504 static HRESULT WINAPI
src_reader_QueryInterface(IMFSourceReaderEx
*iface
, REFIID riid
, void **out
)
1506 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1508 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1510 if (IsEqualGUID(riid
, &IID_IUnknown
)
1511 || IsEqualGUID(riid
, &IID_IMFSourceReader
)
1512 || IsEqualGUID(riid
, &IID_IMFSourceReaderEx
))
1514 *out
= &reader
->IMFSourceReaderEx_iface
;
1518 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1520 return E_NOINTERFACE
;
1523 IUnknown_AddRef((IUnknown
*)*out
);
1527 static ULONG WINAPI
src_reader_AddRef(IMFSourceReaderEx
*iface
)
1529 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1530 ULONG refcount
= InterlockedIncrement(&reader
->public_refcount
);
1532 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1537 static BOOL
source_reader_is_source_stopped(const struct source_reader
*reader
)
1541 if (reader
->source_state
!= SOURCE_STATE_STOPPED
)
1544 for (i
= 0; i
< reader
->stream_count
; ++i
)
1546 if (reader
->streams
[i
].stream
&& !(reader
->streams
[i
].flags
& STREAM_FLAG_STOPPED
))
1553 static ULONG WINAPI
src_reader_Release(IMFSourceReaderEx
*iface
)
1555 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1556 ULONG refcount
= InterlockedDecrement(&reader
->public_refcount
);
1559 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1563 if (reader
->flags
& SOURCE_READER_SHUTDOWN_ON_RELEASE
)
1564 IMFMediaSource_Shutdown(reader
->source
);
1565 else if (SUCCEEDED(IMFMediaSource_Stop(reader
->source
)))
1567 EnterCriticalSection(&reader
->cs
);
1569 while (!source_reader_is_source_stopped(reader
))
1571 SleepConditionVariableCS(&reader
->stop_event
, &reader
->cs
, INFINITE
);
1574 LeaveCriticalSection(&reader
->cs
);
1577 for (i
= 0; i
< reader
->stream_count
; ++i
)
1579 struct media_stream
*stream
= &reader
->streams
[i
];
1580 IMFVideoSampleAllocatorCallback
*callback
;
1582 if (!stream
->allocator
)
1585 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream
->allocator
, &IID_IMFVideoSampleAllocatorCallback
,
1586 (void **)&callback
)))
1588 IMFVideoSampleAllocatorCallback_SetCallback(callback
, NULL
);
1589 IMFVideoSampleAllocatorCallback_Release(callback
);
1593 source_reader_release(reader
);
1599 static HRESULT WINAPI
src_reader_GetStreamSelection(IMFSourceReaderEx
*iface
, DWORD index
, BOOL
*selected
)
1601 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1603 TRACE("%p, %#lx, %p.\n", iface
, index
, selected
);
1607 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1608 index
= reader
->first_video_stream_index
;
1610 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1611 index
= reader
->first_audio_stream_index
;
1617 return source_reader_get_stream_selection(reader
, index
, selected
);
1620 static HRESULT WINAPI
src_reader_SetStreamSelection(IMFSourceReaderEx
*iface
, DWORD index
, BOOL selection
)
1622 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1624 BOOL selection_changed
= FALSE
, selected
;
1627 TRACE("%p, %#lx, %d.\n", iface
, index
, selection
);
1629 selection
= !!selection
;
1631 EnterCriticalSection(&reader
->cs
);
1633 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1635 for (i
= 0; i
< reader
->stream_count
; ++i
)
1637 if (!selection_changed
)
1639 source_reader_get_stream_selection(reader
, i
, &selected
);
1640 selection_changed
= !!(selected
^ selection
);
1644 IMFPresentationDescriptor_SelectStream(reader
->descriptor
, i
);
1646 IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, i
);
1653 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1654 index
= reader
->first_video_stream_index
;
1656 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1657 index
= reader
->first_audio_stream_index
;
1663 source_reader_get_stream_selection(reader
, index
, &selected
);
1664 selection_changed
= !!(selected
^ selection
);
1667 hr
= IMFPresentationDescriptor_SelectStream(reader
->descriptor
, index
);
1669 hr
= IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, index
);
1672 if (selection_changed
)
1674 for (i
= 0; i
< reader
->stream_count
; ++i
)
1676 reader
->streams
[i
].last_sample_ts
= 0;
1680 LeaveCriticalSection(&reader
->cs
);
1682 return SUCCEEDED(hr
) ? S_OK
: MF_E_INVALIDSTREAMNUMBER
;
1685 static HRESULT
source_reader_get_native_media_type(struct source_reader
*reader
, DWORD index
, DWORD type_index
,
1686 IMFMediaType
**type
)
1688 IMFMediaTypeHandler
*handler
;
1689 IMFStreamDescriptor
*sd
;
1690 IMFMediaType
*src_type
;
1696 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1697 index
= reader
->first_video_stream_index
;
1699 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1700 index
= reader
->first_audio_stream_index
;
1706 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1707 return MF_E_INVALIDSTREAMNUMBER
;
1709 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
1710 IMFStreamDescriptor_Release(sd
);
1714 if (type_index
== MF_SOURCE_READER_CURRENT_TYPE_INDEX
)
1715 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &src_type
);
1717 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, type_index
, &src_type
);
1718 IMFMediaTypeHandler_Release(handler
);
1722 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
1723 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)*type
);
1724 IMFMediaType_Release(src_type
);
1730 static HRESULT WINAPI
src_reader_GetNativeMediaType(IMFSourceReaderEx
*iface
, DWORD index
, DWORD type_index
,
1731 IMFMediaType
**type
)
1733 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1735 TRACE("%p, %#lx, %#lx, %p.\n", iface
, index
, type_index
, type
);
1737 return source_reader_get_native_media_type(reader
, index
, type_index
, type
);
1740 static HRESULT WINAPI
src_reader_GetCurrentMediaType(IMFSourceReaderEx
*iface
, DWORD index
, IMFMediaType
**type
)
1742 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1745 TRACE("%p, %#lx, %p.\n", iface
, index
, type
);
1749 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1750 index
= reader
->first_video_stream_index
;
1752 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1753 index
= reader
->first_audio_stream_index
;
1759 if (index
>= reader
->stream_count
)
1760 return MF_E_INVALIDSTREAMNUMBER
;
1762 if (FAILED(hr
= MFCreateMediaType(type
)))
1765 EnterCriticalSection(&reader
->cs
);
1767 hr
= IMFMediaType_CopyAllItems(reader
->streams
[index
].current
, (IMFAttributes
*)*type
);
1769 LeaveCriticalSection(&reader
->cs
);
1774 static HRESULT
source_reader_get_source_type_handler(struct source_reader
*reader
, DWORD index
,
1775 IMFMediaTypeHandler
**handler
)
1777 IMFStreamDescriptor
*sd
;
1781 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1784 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, handler
);
1785 IMFStreamDescriptor_Release(sd
);
1790 static HRESULT
source_reader_set_compatible_media_type(struct source_reader
*reader
, DWORD index
, IMFMediaType
*type
)
1792 struct media_stream
*stream
= &reader
->streams
[index
];
1793 struct transform_entry
*entry
, *next
;
1794 IMFMediaTypeHandler
*type_handler
;
1795 IMFMediaType
*native_type
;
1796 BOOL type_set
= FALSE
;
1801 if (FAILED(hr
= IMFMediaType_IsEqual(type
, stream
->current
, &flags
)))
1804 if (!(flags
& MF_MEDIATYPE_EQUAL_MAJOR_TYPES
))
1805 return MF_E_INVALIDMEDIATYPE
;
1807 /* No need for a decoder or type change. */
1808 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_DATA
)
1811 if (stream
->transform_service
)
1813 IMFTransform_Release(stream
->transform_service
);
1814 stream
->transform_service
= NULL
;
1816 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &stream
->transforms
, struct transform_entry
, entry
)
1818 list_remove(&entry
->entry
);
1819 transform_entry_destroy(entry
);
1822 if (FAILED(hr
= source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1825 while (!type_set
&& IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler
, i
++, &native_type
) == S_OK
)
1827 static const DWORD compare_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_DATA
;
1829 if (SUCCEEDED(IMFMediaType_IsEqual(native_type
, type
, &flags
)) && (flags
& compare_flags
) == compare_flags
)
1831 if ((type_set
= SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, native_type
))))
1832 IMFMediaType_CopyAllItems(native_type
, (IMFAttributes
*)stream
->current
);
1835 IMFMediaType_Release(native_type
);
1838 IMFMediaTypeHandler_Release(type_handler
);
1840 return type_set
? S_OK
: S_FALSE
;
1843 static HRESULT
source_reader_create_sample_allocator_attributes(const struct source_reader
*reader
,
1844 IMFAttributes
**attributes
)
1846 UINT32 shared
= 0, shared_without_mutex
= 0;
1849 if (FAILED(hr
= MFCreateAttributes(attributes
, 1)))
1852 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED
, &shared
);
1853 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, &shared_without_mutex
);
1855 if (shared_without_mutex
)
1856 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, TRUE
);
1858 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED
, TRUE
);
1863 static HRESULT
source_reader_setup_sample_allocator(struct source_reader
*reader
, unsigned int index
)
1865 struct media_stream
*stream
= &reader
->streams
[index
];
1866 IMFAttributes
*attributes
= NULL
;
1870 IMFMediaType_GetMajorType(stream
->current
, &major
);
1871 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
1874 if (!(reader
->flags
& SOURCE_READER_HAS_DEVICE_MANAGER
))
1877 if (!stream
->allocator
)
1879 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&stream
->allocator
)))
1881 WARN("Failed to create sample allocator, hr %#lx.\n", hr
);
1886 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream
->allocator
);
1887 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(stream
->allocator
, reader
->device_manager
)))
1889 WARN("Failed to set device manager, hr %#lx.\n", hr
);
1893 if (FAILED(hr
= source_reader_create_sample_allocator_attributes(reader
, &attributes
)))
1894 WARN("Failed to create allocator attributes, hr %#lx.\n", hr
);
1896 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream
->allocator
, 2, 8,
1897 attributes
, stream
->current
)))
1899 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr
);
1903 IMFAttributes_Release(attributes
);
1908 static BOOL
source_reader_allow_video_processor(struct source_reader
*reader
, BOOL
*advanced
)
1913 if (!reader
->attributes
)
1916 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING
, &value
)))
1918 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING
, &value
)))
1919 return value
|| *advanced
;
1924 static HRESULT
source_reader_create_transform(struct source_reader
*reader
, BOOL decoder
, BOOL allow_processor
,
1925 IMFMediaType
*input_type
, IMFMediaType
*output_type
, struct transform_entry
**out
)
1927 MFT_REGISTER_TYPE_INFO in_type
, out_type
;
1928 struct transform_entry
*entry
;
1929 IMFActivate
**activates
;
1931 IMFTransform
*transform
;
1935 if (FAILED(hr
= IMFMediaType_GetMajorType(input_type
, &in_type
.guidMajorType
))
1936 || FAILED(hr
= IMFMediaType_GetGUID(input_type
, &MF_MT_SUBTYPE
, &in_type
.guidSubtype
)))
1938 if (FAILED(hr
= IMFMediaType_GetMajorType(output_type
, &out_type
.guidMajorType
))
1939 || FAILED(hr
= IMFMediaType_GetGUID(output_type
, &MF_MT_SUBTYPE
, &out_type
.guidSubtype
)))
1942 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
))
1943 category
= decoder
? MFT_CATEGORY_VIDEO_DECODER
: MFT_CATEGORY_VIDEO_PROCESSOR
;
1944 else if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1945 category
= decoder
? MFT_CATEGORY_AUDIO_DECODER
: MFT_CATEGORY_AUDIO_EFFECT
;
1947 return MF_E_TOPO_CODEC_NOT_FOUND
;
1949 if (!(entry
= calloc(1, sizeof(*entry
))))
1950 return E_OUTOFMEMORY
;
1951 list_init(&entry
->entry
);
1952 entry
->category
= category
;
1954 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
)
1955 && SUCCEEDED(IMFMediaType_GetUINT32(output_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &entry
->min_buffer_size
)))
1957 UINT32 bytes_per_second
;
1959 if (SUCCEEDED(IMFMediaType_GetUINT32(output_type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
, &bytes_per_second
)))
1960 entry
->min_buffer_size
= max(entry
->min_buffer_size
, bytes_per_second
);
1964 if (SUCCEEDED(hr
= MFTEnumEx(category
, 0, &in_type
, allow_processor
? NULL
: &out_type
, &activates
, &count
)))
1969 return MF_E_TOPO_CODEC_NOT_FOUND
;
1972 for (i
= 0; i
< count
; i
++)
1974 IMFMediaType
*media_type
;
1976 if (FAILED(IMFActivate_ActivateObject(activates
[i
], &IID_IMFTransform
, (void **)&transform
)))
1978 if (SUCCEEDED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0))
1979 && SUCCEEDED(hr
= IMFTransform_GetInputCurrentType(transform
, 0, &media_type
)))
1981 if (SUCCEEDED(hr
= update_media_type_from_upstream(output_type
, media_type
))
1982 && FAILED(hr
= IMFTransform_SetOutputType(transform
, 0, output_type
, 0)) && allow_processor
1983 && SUCCEEDED(hr
= IMFTransform_GetOutputAvailableType(transform
, 0, 0, &media_type
)))
1985 struct transform_entry
*converter
;
1987 if (SUCCEEDED(hr
= IMFTransform_SetOutputType(transform
, 0, media_type
, 0))
1988 && SUCCEEDED(hr
= update_media_type_from_upstream(output_type
, media_type
))
1989 && SUCCEEDED(hr
= source_reader_create_transform(reader
, FALSE
, FALSE
, media_type
, output_type
, &converter
)))
1990 list_add_tail(&entry
->entry
, &converter
->entry
);
1992 IMFMediaType_Release(media_type
);
1997 entry
->transform
= transform
;
2003 IMFTransform_Release(transform
);
2006 for (i
= 0; i
< count
; ++i
)
2007 IMFActivate_Release(activates
[i
]);
2008 CoTaskMemFree(activates
);
2016 static HRESULT
source_reader_create_decoder_for_stream(struct source_reader
*reader
, DWORD index
, IMFMediaType
*output_type
)
2018 BOOL enable_advanced
, allow_processor
;
2019 struct media_stream
*stream
= &reader
->streams
[index
];
2020 IMFMediaType
*input_type
;
2024 allow_processor
= source_reader_allow_video_processor(reader
, &enable_advanced
);
2026 while (SUCCEEDED(hr
= source_reader_get_native_media_type(reader
, index
, i
++, &input_type
)))
2028 struct transform_entry
*entry
;
2030 /* first, try to append a single processor, then try again with a decoder and a processor */
2031 if ((allow_processor
&& SUCCEEDED(hr
= source_reader_create_transform(reader
, FALSE
, FALSE
, input_type
, output_type
, &entry
)))
2032 || SUCCEEDED(hr
= source_reader_create_transform(reader
, TRUE
, allow_processor
, input_type
, output_type
, &entry
)))
2034 struct list
*ptr
= list_head(&entry
->entry
);
2035 struct transform_entry
*service
= ptr
? LIST_ENTRY(ptr
, struct transform_entry
, entry
) : entry
;
2036 IMFMediaTypeHandler
*type_handler
;
2038 if (enable_advanced
)
2040 /* when advanced video processing is enabled, converters are exposed as stream transform service */
2041 stream
->transform_service
= service
->transform
;
2042 IMFTransform_AddRef(stream
->transform_service
);
2046 /* when advanced video processing is disabled, only decoders are exposed as stream transform service */
2047 if (IsEqualGUID(&entry
->category
, &MFT_CATEGORY_AUDIO_DECODER
)
2048 || IsEqualGUID(&entry
->category
, &MFT_CATEGORY_VIDEO_DECODER
))
2050 stream
->transform_service
= entry
->transform
;
2051 IMFTransform_AddRef(stream
->transform_service
);
2053 /* converters are hidden from the stream transforms */
2054 if (service
!= entry
)
2055 service
->hidden
= TRUE
;
2059 /* converters are hidden from the stream transforms */
2060 entry
->hidden
= TRUE
;
2064 /* move any additional transforms that have been created */
2065 list_move_head(&stream
->transforms
, &entry
->entry
);
2066 list_add_head(&stream
->transforms
, &entry
->entry
);
2068 if (SUCCEEDED(source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
2070 if (FAILED(hr
= IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, input_type
)))
2071 WARN("Failed to set current input media type, hr %#lx\n", hr
);
2072 IMFMediaTypeHandler_Release(type_handler
);
2075 if (FAILED(hr
= IMFTransform_GetOutputCurrentType(service
->transform
, 0, &output_type
)))
2076 WARN("Failed to get decoder output media type, hr %#lx\n", hr
);
2079 IMFMediaType_CopyAllItems(output_type
, (IMFAttributes
*)stream
->current
);
2080 IMFMediaType_Release(output_type
);
2083 IMFMediaType_Release(input_type
);
2087 IMFMediaType_Release(input_type
);
2090 return MF_E_TOPO_CODEC_NOT_FOUND
;
2093 static HRESULT WINAPI
src_reader_SetCurrentMediaType(IMFSourceReaderEx
*iface
, DWORD index
, DWORD
*reserved
,
2096 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2099 TRACE("%p, %#lx, %p, %p.\n", iface
, index
, reserved
, type
);
2103 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2104 index
= reader
->first_video_stream_index
;
2106 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2107 index
= reader
->first_audio_stream_index
;
2113 if (index
>= reader
->stream_count
)
2114 return MF_E_INVALIDSTREAMNUMBER
;
2116 /* FIXME: setting the output type while streaming should trigger a flush */
2118 EnterCriticalSection(&reader
->cs
);
2120 hr
= source_reader_set_compatible_media_type(reader
, index
, type
);
2122 hr
= source_reader_create_decoder_for_stream(reader
, index
, type
);
2124 hr
= source_reader_setup_sample_allocator(reader
, index
);
2126 LeaveCriticalSection(&reader
->cs
);
2131 static HRESULT WINAPI
src_reader_SetCurrentPosition(IMFSourceReaderEx
*iface
, REFGUID format
, REFPROPVARIANT position
)
2133 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2134 struct source_reader_async_command
*command
;
2139 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), position
);
2141 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2144 if (!(flags
& MFMEDIASOURCE_CAN_SEEK
))
2145 return MF_E_INVALIDREQUEST
;
2147 EnterCriticalSection(&reader
->cs
);
2149 /* Check if we got pending requests. */
2150 for (i
= 0; i
< reader
->stream_count
; ++i
)
2152 if (reader
->streams
[i
].requests
)
2154 hr
= MF_E_INVALIDREQUEST
;
2161 for (i
= 0; i
< reader
->stream_count
; ++i
)
2163 reader
->streams
[i
].last_sample_ts
= 0;
2166 if (reader
->async_callback
)
2168 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK
, &command
)))
2170 command
->u
.seek
.format
= *format
;
2171 PropVariantCopy(&command
->u
.seek
.position
, position
);
2173 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2174 IUnknown_Release(&command
->IUnknown_iface
);
2179 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, format
, position
)))
2181 reader
->flags
|= SOURCE_READER_SEEKING
;
2182 while (reader
->flags
& SOURCE_READER_SEEKING
)
2184 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2190 LeaveCriticalSection(&reader
->cs
);
2195 static HRESULT
source_reader_read_sample(struct source_reader
*reader
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
2196 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2198 struct media_stream
*stream
;
2199 DWORD actual_index_tmp
;
2200 LONGLONG timestamp_tmp
;
2204 if (!stream_flags
|| !sample
)
2210 timestamp
= ×tamp_tmp
;
2213 actual_index
= &actual_index_tmp
;
2215 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
2217 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, index
, &stream_index
)))
2219 *actual_index
= stream_index
;
2221 stream
= &reader
->streams
[stream_index
];
2223 if (!source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
2226 while (!source_reader_got_response_for_stream(reader
, stream
) && stream
->state
!= STREAM_STATE_EOS
)
2229 if (FAILED(hr
= source_reader_request_sample(reader
, stream
)))
2230 WARN("Failed to request a sample, hr %#lx.\n", hr
);
2231 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
2233 *stream_flags
= MF_SOURCE_READERF_ERROR
;
2237 SleepConditionVariableCS(&reader
->sample_event
, &reader
->cs
, INFINITE
);
2240 source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
2246 *actual_index
= index
;
2247 *stream_flags
= MF_SOURCE_READERF_ERROR
;
2252 TRACE("Stream %lu, got sample %p, flags %#lx.\n", *actual_index
, *sample
, *stream_flags
);
2257 static HRESULT
source_reader_read_sample_async(struct source_reader
*reader
, unsigned int index
, unsigned int flags
,
2258 DWORD
*actual_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2260 struct source_reader_async_command
*command
;
2263 if (actual_index
|| stream_flags
|| timestamp
|| sample
)
2264 return E_INVALIDARG
;
2266 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2267 hr
= MF_E_NOTACCEPTING
;
2270 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_READ
, &command
)))
2272 command
->u
.read
.stream_index
= index
;
2273 command
->u
.read
.flags
= flags
;
2275 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2276 IUnknown_Release(&command
->IUnknown_iface
);
2283 static HRESULT WINAPI
src_reader_ReadSample(IMFSourceReaderEx
*iface
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
2284 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2286 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2289 TRACE("%p, %#lx, %#lx, %p, %p, %p, %p\n", iface
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2291 EnterCriticalSection(&reader
->cs
);
2293 while (reader
->flags
& SOURCE_READER_SEEKING
)
2295 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2298 if (reader
->async_callback
)
2299 hr
= source_reader_read_sample_async(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2301 hr
= source_reader_read_sample(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2303 LeaveCriticalSection(&reader
->cs
);
2308 static HRESULT
source_reader_flush_async(struct source_reader
*reader
, unsigned int index
)
2310 struct source_reader_async_command
*command
;
2311 unsigned int stream_index
;
2314 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2315 return MF_E_INVALIDREQUEST
;
2319 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2320 stream_index
= reader
->first_video_stream_index
;
2322 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2323 stream_index
= reader
->first_audio_stream_index
;
2326 stream_index
= index
;
2329 reader
->flags
|= SOURCE_READER_FLUSHING
;
2331 if (stream_index
!= MF_SOURCE_READER_ALL_STREAMS
&& stream_index
>= reader
->stream_count
)
2332 return MF_E_INVALIDSTREAMNUMBER
;
2334 if (FAILED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH
, &command
)))
2337 command
->u
.flush
.stream_index
= stream_index
;
2339 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2340 IUnknown_Release(&command
->IUnknown_iface
);
2345 static HRESULT WINAPI
src_reader_Flush(IMFSourceReaderEx
*iface
, DWORD index
)
2347 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2350 TRACE("%p, %#lx.\n", iface
, index
);
2352 EnterCriticalSection(&reader
->cs
);
2354 if (reader
->async_callback
)
2355 hr
= source_reader_flush_async(reader
, index
);
2357 hr
= source_reader_flush(reader
, index
);
2359 LeaveCriticalSection(&reader
->cs
);
2364 static HRESULT WINAPI
src_reader_GetServiceForStream(IMFSourceReaderEx
*iface
, DWORD index
, REFGUID service
,
2365 REFIID riid
, void **object
)
2367 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2368 struct media_stream
*stream
= &reader
->streams
[index
];
2369 IUnknown
*obj
= NULL
;
2372 TRACE("%p, %#lx, %s, %s, %p\n", iface
, index
, debugstr_guid(service
), debugstr_guid(riid
), object
);
2374 EnterCriticalSection(&reader
->cs
);
2378 case MF_SOURCE_READER_MEDIASOURCE
:
2379 obj
= (IUnknown
*)reader
->source
;
2382 if (index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2383 index
= reader
->first_video_stream_index
;
2384 else if (index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2385 index
= reader
->first_audio_stream_index
;
2387 if (index
>= reader
->stream_count
)
2388 hr
= MF_E_INVALIDSTREAMNUMBER
;
2389 else if (!(obj
= (IUnknown
*)stream
->transform_service
))
2395 IUnknown_AddRef(obj
);
2397 LeaveCriticalSection(&reader
->cs
);
2401 if (IsEqualGUID(service
, &GUID_NULL
))
2403 hr
= IUnknown_QueryInterface(obj
, riid
, object
);
2409 hr
= IUnknown_QueryInterface(obj
, &IID_IMFGetService
, (void **)&gs
);
2412 hr
= IMFGetService_GetService(gs
, service
, riid
, object
);
2413 IMFGetService_Release(gs
);
2419 IUnknown_Release(obj
);
2424 static HRESULT WINAPI
src_reader_GetPresentationAttribute(IMFSourceReaderEx
*iface
, DWORD index
,
2425 REFGUID guid
, PROPVARIANT
*value
)
2427 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2428 IMFStreamDescriptor
*sd
;
2432 TRACE("%p, %#lx, %s, %p.\n", iface
, index
, debugstr_guid(guid
), value
);
2436 case MF_SOURCE_READER_MEDIASOURCE
:
2437 if (IsEqualGUID(guid
, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS
))
2441 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2445 value
->ulVal
= flags
;
2450 return IMFPresentationDescriptor_GetItem(reader
->descriptor
, guid
, value
);
2453 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2454 index
= reader
->first_video_stream_index
;
2456 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2457 index
= reader
->first_audio_stream_index
;
2463 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
2466 hr
= IMFStreamDescriptor_GetItem(sd
, guid
, value
);
2467 IMFStreamDescriptor_Release(sd
);
2472 static HRESULT WINAPI
src_reader_SetNativeMediaType(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2473 IMFMediaType
*media_type
, DWORD
*stream_flags
)
2475 FIXME("%p, %#lx, %p, %p.\n", iface
, stream_index
, media_type
, stream_flags
);
2480 static HRESULT WINAPI
src_reader_AddTransformForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2481 IUnknown
*transform
)
2483 FIXME("%p, %#lx, %p.\n", iface
, stream_index
, transform
);
2488 static HRESULT WINAPI
src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
)
2490 FIXME("%p, %#lx.\n", iface
, stream_index
);
2495 static struct transform_entry
*get_transform_at_index(struct media_stream
*stream
, UINT index
)
2497 struct transform_entry
*entry
;
2499 LIST_FOR_EACH_ENTRY(entry
, &stream
->transforms
, struct transform_entry
, entry
)
2500 if (!entry
->hidden
&& !index
--)
2506 static HRESULT WINAPI
src_reader_GetTransformForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2507 DWORD transform_index
, GUID
*category
, IMFTransform
**transform
)
2509 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2510 struct transform_entry
*entry
;
2513 TRACE("%p, %#lx, %#lx, %p, %p.\n", iface
, stream_index
, transform_index
, category
, transform
);
2515 EnterCriticalSection(&reader
->cs
);
2517 if (stream_index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2518 stream_index
= reader
->first_video_stream_index
;
2519 else if (stream_index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2520 stream_index
= reader
->first_audio_stream_index
;
2522 if (stream_index
>= reader
->stream_count
)
2523 hr
= MF_E_INVALIDSTREAMNUMBER
;
2524 else if (!(entry
= get_transform_at_index(&reader
->streams
[stream_index
], transform_index
)))
2525 hr
= MF_E_INVALIDINDEX
;
2528 *category
= entry
->category
;
2529 *transform
= entry
->transform
;
2530 IMFTransform_AddRef(*transform
);
2534 LeaveCriticalSection(&reader
->cs
);
2539 static const IMFSourceReaderExVtbl srcreader_vtbl
=
2541 src_reader_QueryInterface
,
2544 src_reader_GetStreamSelection
,
2545 src_reader_SetStreamSelection
,
2546 src_reader_GetNativeMediaType
,
2547 src_reader_GetCurrentMediaType
,
2548 src_reader_SetCurrentMediaType
,
2549 src_reader_SetCurrentPosition
,
2550 src_reader_ReadSample
,
2552 src_reader_GetServiceForStream
,
2553 src_reader_GetPresentationAttribute
,
2554 src_reader_SetNativeMediaType
,
2555 src_reader_AddTransformForStream
,
2556 src_reader_RemoveAllTransformsForStream
,
2557 src_reader_GetTransformForStream
,
2560 static DWORD
reader_get_first_stream_index(IMFPresentationDescriptor
*descriptor
, const GUID
*major
)
2567 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
2568 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2570 for (i
= 0; i
< count
; ++i
)
2572 IMFMediaTypeHandler
*handler
;
2573 IMFStreamDescriptor
*sd
;
2575 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
, &selected
, &sd
)))
2577 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2578 IMFStreamDescriptor_Release(sd
);
2581 hr
= IMFMediaTypeHandler_GetMajorType(handler
, &guid
);
2582 IMFMediaTypeHandler_Release(handler
);
2585 WARN("Failed to get stream major type, hr %#lx.\n", hr
);
2589 if (IsEqualGUID(&guid
, major
))
2597 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2600 static HRESULT
create_source_reader_from_source(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2601 BOOL shutdown_on_release
, REFIID riid
, void **out
)
2603 struct source_reader
*object
;
2607 object
= calloc(1, sizeof(*object
));
2609 return E_OUTOFMEMORY
;
2611 object
->IMFSourceReaderEx_iface
.lpVtbl
= &srcreader_vtbl
;
2612 object
->source_events_callback
.lpVtbl
= &source_events_callback_vtbl
;
2613 object
->stream_events_callback
.lpVtbl
= &stream_events_callback_vtbl
;
2614 object
->async_commands_callback
.lpVtbl
= &async_commands_callback_vtbl
;
2615 object
->public_refcount
= 1;
2616 object
->refcount
= 1;
2617 list_init(&object
->responses
);
2618 if (shutdown_on_release
)
2619 object
->flags
|= SOURCE_READER_SHUTDOWN_ON_RELEASE
;
2620 object
->source
= source
;
2621 IMFMediaSource_AddRef(object
->source
);
2622 InitializeCriticalSection(&object
->cs
);
2623 InitializeConditionVariable(&object
->sample_event
);
2624 InitializeConditionVariable(&object
->state_event
);
2625 InitializeConditionVariable(&object
->stop_event
);
2627 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(object
->source
, &object
->descriptor
)))
2630 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(object
->descriptor
, &object
->stream_count
)))
2633 if (!(object
->streams
= calloc(object
->stream_count
, sizeof(*object
->streams
))))
2639 /* Set initial current media types. */
2640 for (i
= 0; i
< object
->stream_count
; ++i
)
2642 IMFMediaTypeHandler
*handler
;
2643 IMFStreamDescriptor
*sd
;
2644 IMFMediaType
*src_type
;
2647 list_init(&object
->streams
[i
].transforms
);
2649 if (FAILED(hr
= MFCreateMediaType(&object
->streams
[i
].current
)))
2652 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(object
->descriptor
, i
, &selected
, &sd
)))
2655 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &object
->streams
[i
].id
)))
2656 WARN("Failed to get stream identifier, hr %#lx.\n", hr
);
2658 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2659 IMFStreamDescriptor_Release(sd
);
2663 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, 0, &src_type
);
2664 IMFMediaTypeHandler_Release(handler
);
2668 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)object
->streams
[i
].current
);
2669 IMFMediaType_Release(src_type
);
2673 object
->streams
[i
].reader
= object
;
2674 object
->streams
[i
].index
= i
;
2680 /* At least one major type has to be set. */
2681 object
->first_audio_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Audio
);
2682 object
->first_video_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Video
);
2684 if (object
->first_audio_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
&&
2685 object
->first_video_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
)
2687 hr
= MF_E_ATTRIBUTENOTFOUND
;
2690 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(object
->source
, &object
->source_events_callback
,
2691 (IUnknown
*)object
->source
)))
2698 object
->attributes
= attributes
;
2699 IMFAttributes_AddRef(object
->attributes
);
2701 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_ASYNC_CALLBACK
, &IID_IMFSourceReaderCallback
,
2702 (void **)&object
->async_callback
);
2703 if (object
->async_callback
)
2704 TRACE("Using async callback %p.\n", object
->async_callback
);
2706 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_D3D_MANAGER
, &IID_IUnknown
, (void **)&object
->device_manager
);
2707 if (object
->device_manager
)
2709 IUnknown
*unk
= NULL
;
2711 if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IMFDXGIDeviceManager
, (void **)&unk
)))
2712 object
->flags
|= SOURCE_READER_DXGI_DEVICE_MANAGER
;
2713 else if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IDirect3DDeviceManager9
, (void **)&unk
)))
2714 object
->flags
|= SOURCE_READER_D3D9_DEVICE_MANAGER
;
2716 if (!(object
->flags
& (SOURCE_READER_HAS_DEVICE_MANAGER
)))
2718 WARN("Unknown device manager.\n");
2719 IUnknown_Release(object
->device_manager
);
2720 object
->device_manager
= NULL
;
2724 IUnknown_Release(unk
);
2728 if (FAILED(hr
= MFLockSharedWorkQueue(L
"", 0, NULL
, &object
->queue
)))
2729 WARN("Failed to acquired shared queue, hr %#lx.\n", hr
);
2732 hr
= IMFSourceReaderEx_QueryInterface(&object
->IMFSourceReaderEx_iface
, riid
, out
);
2735 IMFSourceReaderEx_Release(&object
->IMFSourceReaderEx_iface
);
2739 static HRESULT
create_source_reader_from_stream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2740 REFIID riid
, void **out
)
2742 IPropertyStore
*props
= NULL
;
2743 IMFSourceResolver
*resolver
;
2744 MF_OBJECT_TYPE obj_type
;
2745 IMFMediaSource
*source
;
2748 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2752 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2755 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, stream
, NULL
, MF_RESOLUTION_MEDIASOURCE
2756 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE
, props
, &obj_type
, (IUnknown
**)&source
);
2757 IMFSourceResolver_Release(resolver
);
2759 IPropertyStore_Release(props
);
2763 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2764 IMFMediaSource_Release(source
);
2768 static HRESULT
create_source_reader_from_url(const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2770 IPropertyStore
*props
= NULL
;
2771 IMFSourceResolver
*resolver
;
2772 IUnknown
*object
= NULL
;
2773 MF_OBJECT_TYPE obj_type
;
2774 IMFMediaSource
*source
;
2777 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2781 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2784 hr
= IMFSourceResolver_CreateObjectFromURL(resolver
, url
, MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
,
2790 case MF_OBJECT_BYTESTREAM
:
2791 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, (IMFByteStream
*)object
, NULL
,
2792 MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
, (IUnknown
**)&source
);
2794 case MF_OBJECT_MEDIASOURCE
:
2795 source
= (IMFMediaSource
*)object
;
2796 IMFMediaSource_AddRef(source
);
2799 WARN("Unknown object type %d.\n", obj_type
);
2802 IUnknown_Release(object
);
2805 IMFSourceResolver_Release(resolver
);
2807 IPropertyStore_Release(props
);
2811 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2812 IMFMediaSource_Release(source
);
2816 static HRESULT
create_source_reader_from_object(IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2818 IMFMediaSource
*source
= NULL
;
2819 IMFByteStream
*stream
= NULL
;
2822 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSource
, (void **)&source
);
2824 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2828 UINT32 disconnect
= 0;
2831 IMFAttributes_GetUINT32(attributes
, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN
, &disconnect
);
2832 hr
= create_source_reader_from_source(source
, attributes
, !disconnect
, riid
, out
);
2835 hr
= create_source_reader_from_stream(stream
, attributes
, riid
, out
);
2838 IMFMediaSource_Release(source
);
2840 IMFByteStream_Release(stream
);
2845 /***********************************************************************
2846 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2848 HRESULT WINAPI
MFCreateSourceReaderFromByteStream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2849 IMFSourceReader
**reader
)
2851 TRACE("%p, %p, %p.\n", stream
, attributes
, reader
);
2853 return create_source_reader_from_object((IUnknown
*)stream
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2856 /***********************************************************************
2857 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2859 HRESULT WINAPI
MFCreateSourceReaderFromMediaSource(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2860 IMFSourceReader
**reader
)
2862 TRACE("%p, %p, %p.\n", source
, attributes
, reader
);
2864 return create_source_reader_from_object((IUnknown
*)source
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2867 /***********************************************************************
2868 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2870 HRESULT WINAPI
MFCreateSourceReaderFromURL(const WCHAR
*url
, IMFAttributes
*attributes
, IMFSourceReader
**reader
)
2872 TRACE("%s, %p, %p.\n", debugstr_w(url
), attributes
, reader
);
2874 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2877 static HRESULT WINAPI
readwrite_factory_QueryInterface(IMFReadWriteClassFactory
*iface
, REFIID riid
, void **out
)
2879 if (IsEqualIID(riid
, &IID_IMFReadWriteClassFactory
) ||
2880 IsEqualIID(riid
, &IID_IUnknown
))
2883 IMFReadWriteClassFactory_AddRef(iface
);
2887 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2889 return E_NOINTERFACE
;
2892 static ULONG WINAPI
readwrite_factory_AddRef(IMFReadWriteClassFactory
*iface
)
2897 static ULONG WINAPI
readwrite_factory_Release(IMFReadWriteClassFactory
*iface
)
2902 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2903 const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2905 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid
), debugstr_w(url
), attributes
, debugstr_guid(riid
), out
);
2907 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2909 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, out
);
2911 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2913 return create_sink_writer_from_url(url
, NULL
, attributes
, riid
, out
);
2916 FIXME("Unsupported %s.\n", debugstr_guid(clsid
));
2921 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2922 IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2926 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid
), unk
, attributes
, debugstr_guid(riid
), out
);
2928 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2930 return create_source_reader_from_object(unk
, attributes
, riid
, out
);
2932 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2934 IMFByteStream
*stream
= NULL
;
2935 IMFMediaSink
*sink
= NULL
;
2937 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2939 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSink
, (void **)&sink
);
2942 hr
= create_sink_writer_from_url(NULL
, stream
, attributes
, riid
, out
);
2944 hr
= create_sink_writer_from_sink(sink
, attributes
, riid
, out
);
2947 IMFMediaSink_Release(sink
);
2949 IMFByteStream_Release(stream
);
2955 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2961 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl
=
2963 readwrite_factory_QueryInterface
,
2964 readwrite_factory_AddRef
,
2965 readwrite_factory_Release
,
2966 readwrite_factory_CreateInstanceFromURL
,
2967 readwrite_factory_CreateInstanceFromObject
,
2970 static IMFReadWriteClassFactory readwrite_factory
= { &readwrite_factory_vtbl
};
2972 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **out
)
2974 TRACE("%s, %p.\n", debugstr_guid(riid
), out
);
2976 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2977 IsEqualGUID(riid
, &IID_IUnknown
))
2979 IClassFactory_AddRef(iface
);
2984 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2986 return E_NOINTERFACE
;
2989 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2994 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2999 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **out
)
3001 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), out
);
3006 return CLASS_E_NOAGGREGATION
;
3008 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory
, riid
, out
);
3011 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
3013 FIXME("%d.\n", dolock
);
3017 static const IClassFactoryVtbl classfactoryvtbl
=
3019 classfactory_QueryInterface
,
3020 classfactory_AddRef
,
3021 classfactory_Release
,
3022 classfactory_CreateInstance
,
3023 classfactory_LockServer
,
3026 static IClassFactory classfactory
= { &classfactoryvtbl
};
3028 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
3030 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
3032 if (IsEqualGUID(clsid
, &CLSID_MFReadWriteClassFactory
))
3033 return IClassFactory_QueryInterface(&classfactory
, riid
, out
);
3035 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
3037 return CLASS_E_CLASSNOTAVAILABLE
;