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
23 #define NONAMELESSUNION
35 #include "mfreadwrite.h"
37 #include "wine/debug.h"
38 #include "wine/heap.h"
39 #include "wine/list.h"
41 #include "mf_private.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
45 static HINSTANCE mfinstance
;
47 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, LPVOID reserved
)
51 case DLL_WINE_PREATTACH
:
52 return FALSE
; /* prefer native version */
53 case DLL_PROCESS_ATTACH
:
54 mfinstance
= instance
;
55 DisableThreadLibraryCalls(instance
);
62 HRESULT WINAPI
DllCanUnloadNow(void)
67 HRESULT WINAPI
DllRegisterServer(void)
69 return __wine_register_resources( mfinstance
);
72 HRESULT WINAPI
DllUnregisterServer(void)
74 return __wine_unregister_resources( mfinstance
);
77 struct stream_response
87 enum media_stream_state
89 STREAM_STATE_READY
= 0,
93 enum media_source_state
95 SOURCE_STATE_STOPPED
= 0,
99 enum media_stream_flags
101 STREAM_FLAG_SAMPLE_REQUESTED
= 0x1, /* Protects from making multiple sample requests. */
102 STREAM_FLAG_SELECTED
= 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
103 STREAM_FLAG_PRESENTED
= 0x4, /* Set if stream was selected last time Start() was called. */
104 STREAM_FLAG_REQUESTED_ONCE
= 0x8, /* Used for MF_SOURCE_READER_ANY_STREAM in synchronous mode. */
109 IMFMediaStream
*stream
;
110 IMFMediaType
*current
;
111 IMFTransform
*decoder
;
114 enum media_stream_state state
;
116 unsigned int requests
;
117 unsigned int responses
;
120 enum source_reader_async_op
122 SOURCE_READER_ASYNC_READ
,
123 SOURCE_READER_ASYNC_SEEK
,
124 SOURCE_READER_ASYNC_FLUSH
,
125 SOURCE_READER_ASYNC_SAMPLE_READY
,
128 struct source_reader_async_command
130 IUnknown IUnknown_iface
;
132 enum source_reader_async_op op
;
138 unsigned int stream_index
;
143 PROPVARIANT position
;
147 unsigned int stream_index
;
151 unsigned int stream_index
;
156 enum source_reader_flags
158 SOURCE_READER_FLUSHING
= 0x1,
159 SOURCE_READER_SEEKING
= 0x2,
160 SOURCE_READER_SHUTDOWN_ON_RELEASE
= 0x4,
165 IMFSourceReader IMFSourceReader_iface
;
166 IMFAsyncCallback source_events_callback
;
167 IMFAsyncCallback stream_events_callback
;
168 IMFAsyncCallback async_commands_callback
;
170 IMFMediaSource
*source
;
171 IMFPresentationDescriptor
*descriptor
;
172 DWORD first_audio_stream_index
;
173 DWORD first_video_stream_index
;
174 IMFSourceReaderCallback
*async_callback
;
176 enum media_source_state source_state
;
177 struct media_stream
*streams
;
179 struct list responses
;
181 CONDITION_VARIABLE sample_event
;
182 CONDITION_VARIABLE state_event
;
185 static inline struct source_reader
*impl_from_IMFSourceReader(IMFSourceReader
*iface
)
187 return CONTAINING_RECORD(iface
, struct source_reader
, IMFSourceReader_iface
);
190 static struct source_reader
*impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
192 return CONTAINING_RECORD(iface
, struct source_reader
, source_events_callback
);
195 static struct source_reader
*impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
197 return CONTAINING_RECORD(iface
, struct source_reader
, stream_events_callback
);
200 static struct source_reader
*impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
202 return CONTAINING_RECORD(iface
, struct source_reader
, async_commands_callback
);
205 static struct source_reader_async_command
*impl_from_async_command_IUnknown(IUnknown
*iface
)
207 return CONTAINING_RECORD(iface
, struct source_reader_async_command
, IUnknown_iface
);
210 static HRESULT WINAPI
source_reader_async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
212 if (IsEqualIID(riid
, &IID_IUnknown
))
215 IUnknown_AddRef(iface
);
219 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
221 return E_NOINTERFACE
;
224 static ULONG WINAPI
source_reader_async_command_AddRef(IUnknown
*iface
)
226 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
227 return InterlockedIncrement(&command
->refcount
);
230 static ULONG WINAPI
source_reader_async_command_Release(IUnknown
*iface
)
232 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
233 ULONG refcount
= InterlockedIncrement(&command
->refcount
);
237 if (command
->op
== SOURCE_READER_ASYNC_SEEK
)
238 PropVariantClear(&command
->u
.seek
.position
);
245 static const IUnknownVtbl source_reader_async_command_vtbl
=
247 source_reader_async_command_QueryInterface
,
248 source_reader_async_command_AddRef
,
249 source_reader_async_command_Release
,
252 static HRESULT
source_reader_create_async_op(enum source_reader_async_op op
, struct source_reader_async_command
**ret
)
254 struct source_reader_async_command
*command
;
256 if (!(command
= heap_alloc_zero(sizeof(*command
))))
257 return E_OUTOFMEMORY
;
259 command
->IUnknown_iface
.lpVtbl
= &source_reader_async_command_vtbl
;
267 static HRESULT
media_event_get_object(IMFMediaEvent
*event
, REFIID riid
, void **obj
)
272 PropVariantInit(&value
);
273 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
275 WARN("Failed to get event value, hr %#x.\n", hr
);
279 if (value
.vt
!= VT_UNKNOWN
|| !value
.u
.punkVal
)
281 WARN("Unexpected value type %d.\n", value
.vt
);
282 PropVariantClear(&value
);
286 hr
= IUnknown_QueryInterface(value
.u
.punkVal
, riid
, obj
);
287 PropVariantClear(&value
);
290 WARN("Unexpected object type.\n");
297 static HRESULT
media_stream_get_id(IMFMediaStream
*stream
, DWORD
*id
)
299 IMFStreamDescriptor
*sd
;
302 if (SUCCEEDED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
304 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, id
);
305 IMFStreamDescriptor_Release(sd
);
311 static HRESULT WINAPI
source_reader_callback_QueryInterface(IMFAsyncCallback
*iface
,
312 REFIID riid
, void **obj
)
314 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
316 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
317 IsEqualIID(riid
, &IID_IUnknown
))
320 IMFAsyncCallback_AddRef(iface
);
324 WARN("Unsupported %s.\n", debugstr_guid(riid
));
326 return E_NOINTERFACE
;
329 static ULONG WINAPI
source_reader_source_events_callback_AddRef(IMFAsyncCallback
*iface
)
331 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
332 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
335 static ULONG WINAPI
source_reader_source_events_callback_Release(IMFAsyncCallback
*iface
)
337 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
338 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
341 static HRESULT WINAPI
source_reader_callback_GetParameters(IMFAsyncCallback
*iface
,
342 DWORD
*flags
, DWORD
*queue
)
347 static void source_reader_queue_response(struct source_reader
*reader
, struct media_stream
*stream
, HRESULT status
,
348 DWORD stream_flags
, LONGLONG timestamp
, IMFSample
*sample
)
350 struct source_reader_async_command
*command
;
351 struct stream_response
*response
;
354 response
= heap_alloc_zero(sizeof(*response
));
355 response
->status
= status
;
356 response
->stream_index
= stream
->index
;
357 response
->stream_flags
= stream_flags
;
358 response
->timestamp
= timestamp
;
359 response
->sample
= sample
;
360 if (response
->sample
)
361 IMFSample_AddRef(response
->sample
);
363 list_add_tail(&reader
->responses
, &response
->entry
);
366 if (stream
->requests
)
368 if (reader
->async_callback
)
370 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY
, &command
)))
372 command
->u
.sample
.stream_index
= stream
->index
;
373 if (FAILED(hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &reader
->async_commands_callback
,
374 &command
->IUnknown_iface
)))
375 WARN("Failed to submit async result, hr %#x.\n", hr
);
376 IUnknown_Release(&command
->IUnknown_iface
);
380 WakeAllConditionVariable(&reader
->sample_event
);
386 static HRESULT
source_reader_request_sample(struct source_reader
*reader
, struct media_stream
*stream
)
390 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
392 if (FAILED(hr
= IMFMediaStream_RequestSample(stream
->stream
, NULL
)))
393 WARN("Sample request failed, hr %#x.\n", hr
);
396 stream
->flags
|= (STREAM_FLAG_SAMPLE_REQUESTED
| STREAM_FLAG_REQUESTED_ONCE
);
403 static HRESULT
source_reader_new_stream_handler(struct source_reader
*reader
, IMFMediaEvent
*event
)
405 IMFMediaStream
*stream
;
410 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFMediaStream
, (void **)&stream
)))
412 WARN("Failed to get stream object, hr %#x.\n", hr
);
416 TRACE("Got new stream %p.\n", stream
);
418 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
420 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
421 IMFMediaStream_Release(stream
);
425 EnterCriticalSection(&reader
->cs
);
427 for (i
= 0; i
< reader
->stream_count
; ++i
)
429 if (id
== reader
->streams
[i
].id
)
431 if (!reader
->streams
[i
].stream
)
433 reader
->streams
[i
].stream
= stream
;
434 IMFMediaStream_AddRef(reader
->streams
[i
].stream
);
435 if (FAILED(hr
= IMFMediaStream_BeginGetEvent(stream
, &reader
->stream_events_callback
,
436 (IUnknown
*)stream
)))
438 WARN("Failed to subscribe to stream events, hr %#x.\n", hr
);
441 if (reader
->streams
[i
].requests
)
442 source_reader_request_sample(reader
, &reader
->streams
[i
]);
448 if (i
== reader
->stream_count
)
449 WARN("Stream with id %#x was not present in presentation descriptor.\n", id
);
451 LeaveCriticalSection(&reader
->cs
);
453 IMFMediaStream_Release(stream
);
458 static HRESULT
source_reader_source_state_handler(struct source_reader
*reader
, MediaEventType event_type
)
460 EnterCriticalSection(&reader
->cs
);
464 case MESourceStarted
:
465 reader
->source_state
= SOURCE_STATE_STARTED
;
467 case MESourceStopped
:
468 reader
->source_state
= SOURCE_STATE_STOPPED
;
471 reader
->flags
&= ~SOURCE_READER_SEEKING
;
474 WARN("Unhandled event %d.\n", event_type
);
477 LeaveCriticalSection(&reader
->cs
);
479 WakeAllConditionVariable(&reader
->state_event
);
484 static HRESULT WINAPI
source_reader_source_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
486 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
487 MediaEventType event_type
;
488 IMFMediaSource
*source
;
489 IMFMediaEvent
*event
;
492 TRACE("%p, %p.\n", iface
, result
);
494 source
= (IMFMediaSource
*)IMFAsyncResult_GetStateNoAddRef(result
);
496 if (FAILED(hr
= IMFMediaSource_EndGetEvent(source
, result
, &event
)))
499 IMFMediaEvent_GetType(event
, &event_type
);
501 TRACE("Got event %u.\n", event_type
);
506 hr
= source_reader_new_stream_handler(reader
, event
);
508 case MESourceStarted
:
510 case MESourceStopped
:
512 hr
= source_reader_source_state_handler(reader
, event_type
);
514 case MEBufferingStarted
:
515 case MEBufferingStopped
:
519 case MESourceCharacteristicsChanged
:
520 case MESourceMetadataChanged
:
521 case MEContentProtectionMetadata
:
522 case MEDeviceThermalStateChanged
:
523 if (reader
->async_callback
)
524 IMFSourceReaderCallback_OnEvent(reader
->async_callback
, MF_SOURCE_READER_MEDIASOURCE
, event
);
531 WARN("Failed while handling %d event, hr %#x.\n", event_type
, hr
);
533 IMFMediaEvent_Release(event
);
535 IMFMediaSource_BeginGetEvent(source
, iface
, (IUnknown
*)source
);
540 static const IMFAsyncCallbackVtbl source_events_callback_vtbl
=
542 source_reader_callback_QueryInterface
,
543 source_reader_source_events_callback_AddRef
,
544 source_reader_source_events_callback_Release
,
545 source_reader_callback_GetParameters
,
546 source_reader_source_events_callback_Invoke
,
549 static ULONG WINAPI
source_reader_stream_events_callback_AddRef(IMFAsyncCallback
*iface
)
551 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
552 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
555 static ULONG WINAPI
source_reader_stream_events_callback_Release(IMFAsyncCallback
*iface
)
557 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
558 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
561 static HRESULT
source_reader_pull_stream_samples(struct source_reader
*reader
, struct media_stream
*stream
)
563 MFT_OUTPUT_STREAM_INFO stream_info
= { 0 };
564 MFT_OUTPUT_DATA_BUFFER out_buffer
;
565 IMFMediaBuffer
*buffer
;
570 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(stream
->decoder
, 0, &stream_info
)))
572 WARN("Failed to get output stream info, hr %#x.\n", hr
);
578 memset(&out_buffer
, 0, sizeof(out_buffer
));
580 if (!(stream_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
))
582 if (FAILED(hr
= MFCreateSample(&out_buffer
.pSample
)))
585 if (FAILED(hr
= MFCreateAlignedMemoryBuffer(stream_info
.cbSize
, stream_info
.cbAlignment
, &buffer
)))
587 IMFSample_Release(out_buffer
.pSample
);
591 IMFSample_AddBuffer(out_buffer
.pSample
, buffer
);
592 IMFMediaBuffer_Release(buffer
);
595 if (FAILED(hr
= IMFTransform_ProcessOutput(stream
->decoder
, 0, 1, &out_buffer
, &status
)))
597 if (out_buffer
.pSample
)
598 IMFSample_Release(out_buffer
.pSample
);
603 if (FAILED(IMFSample_GetSampleTime(out_buffer
.pSample
, ×tamp
)))
604 WARN("Sample time wasn't set.\n");
606 source_reader_queue_response(reader
, stream
, S_OK
/* FIXME */, 0, timestamp
, out_buffer
.pSample
);
607 if (out_buffer
.pSample
)
608 IMFSample_Release(out_buffer
.pSample
);
609 if (out_buffer
.pEvents
)
610 IMFCollection_Release(out_buffer
.pEvents
);
616 static HRESULT
source_reader_process_sample(struct source_reader
*reader
, struct media_stream
*stream
,
622 if (!stream
->decoder
)
625 if (FAILED(IMFSample_GetSampleTime(sample
, ×tamp
)))
626 WARN("Sample time wasn't set.\n");
628 source_reader_queue_response(reader
, stream
, S_OK
, 0, timestamp
, sample
);
632 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
634 hr
= source_reader_pull_stream_samples(reader
, stream
);
635 if (hr
== MF_E_TRANSFORM_NEED_MORE_INPUT
)
637 if (FAILED(hr
= IMFTransform_ProcessInput(stream
->decoder
, 0, sample
, 0)))
639 WARN("Transform failed to process input, hr %#x.\n", hr
);
643 if ((hr
= source_reader_pull_stream_samples(reader
, stream
)) == MF_E_TRANSFORM_NEED_MORE_INPUT
)
647 WARN("Transform failed to process output, hr %#x.\n", hr
);
652 static HRESULT
source_reader_media_sample_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
653 IMFMediaEvent
*event
)
660 TRACE("Got new sample for stream %p.\n", stream
);
662 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFSample
, (void **)&sample
)))
664 WARN("Failed to get sample object, hr %#x.\n", hr
);
668 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
670 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
671 IMFSample_Release(sample
);
675 EnterCriticalSection(&reader
->cs
);
677 for (i
= 0; i
< reader
->stream_count
; ++i
)
679 if (id
== reader
->streams
[i
].id
)
681 /* FIXME: propagate processing errors? */
683 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
684 hr
= source_reader_process_sample(reader
, &reader
->streams
[i
], sample
);
685 if (reader
->streams
[i
].requests
)
686 source_reader_request_sample(reader
, &reader
->streams
[i
]);
692 if (i
== reader
->stream_count
)
693 WARN("Stream with id %#x was not present in presentation descriptor.\n", id
);
695 LeaveCriticalSection(&reader
->cs
);
697 IMFSample_Release(sample
);
702 static HRESULT
source_reader_media_stream_state_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
703 IMFMediaEvent
*event
)
705 MediaEventType event_type
;
712 IMFMediaEvent_GetType(event
, &event_type
);
714 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
716 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
720 EnterCriticalSection(&reader
->cs
);
722 for (i
= 0; i
< reader
->stream_count
; ++i
)
724 struct media_stream
*stream
= &reader
->streams
[i
];
726 if (id
== stream
->id
)
731 stream
->state
= STREAM_STATE_EOS
;
732 stream
->flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
734 if (stream
->decoder
&& SUCCEEDED(IMFTransform_ProcessMessage(stream
->decoder
,
735 MFT_MESSAGE_COMMAND_DRAIN
, 0)))
737 if ((hr
= source_reader_pull_stream_samples(reader
, stream
)) != MF_E_TRANSFORM_NEED_MORE_INPUT
)
738 WARN("Failed to pull pending samples, hr %#x.\n", hr
);
741 while (stream
->requests
)
742 source_reader_queue_response(reader
, stream
, S_OK
, MF_SOURCE_READERF_ENDOFSTREAM
, 0, NULL
);
746 case MEStreamStarted
:
747 stream
->state
= STREAM_STATE_READY
;
751 hr
= SUCCEEDED(IMFMediaEvent_GetValue(event
, &value
)) && value
.vt
== VT_I8
? S_OK
: E_UNEXPECTED
;
752 timestamp
= SUCCEEDED(hr
) ? value
.u
.hVal
.QuadPart
: 0;
753 PropVariantClear(&value
);
755 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_STREAMTICK
, timestamp
, NULL
);
766 LeaveCriticalSection(&reader
->cs
);
771 static HRESULT WINAPI
source_reader_stream_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
773 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
774 MediaEventType event_type
;
775 IMFMediaStream
*stream
;
776 IMFMediaEvent
*event
;
779 TRACE("%p, %p.\n", iface
, result
);
781 stream
= (IMFMediaStream
*)IMFAsyncResult_GetStateNoAddRef(result
);
783 if (FAILED(hr
= IMFMediaStream_EndGetEvent(stream
, result
, &event
)))
786 IMFMediaEvent_GetType(event
, &event_type
);
788 TRACE("Got event %u.\n", event_type
);
793 hr
= source_reader_media_sample_handler(reader
, stream
, event
);
796 case MEStreamStarted
:
799 hr
= source_reader_media_stream_state_handler(reader
, stream
, event
);
806 WARN("Failed while handling %d event, hr %#x.\n", event_type
, hr
);
808 IMFMediaEvent_Release(event
);
810 IMFMediaStream_BeginGetEvent(stream
, iface
, (IUnknown
*)stream
);
815 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl
=
817 source_reader_callback_QueryInterface
,
818 source_reader_stream_events_callback_AddRef
,
819 source_reader_stream_events_callback_Release
,
820 source_reader_callback_GetParameters
,
821 source_reader_stream_events_callback_Invoke
,
824 static ULONG WINAPI
source_reader_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
826 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
827 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
830 static ULONG WINAPI
source_reader_async_commands_callback_Release(IMFAsyncCallback
*iface
)
832 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
833 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
836 static struct stream_response
* media_stream_detach_response(struct source_reader
*reader
, struct stream_response
*response
)
838 struct media_stream
*stream
;
840 list_remove(&response
->entry
);
842 if (response
->stream_index
< reader
->stream_count
)
844 stream
= &reader
->streams
[response
->stream_index
];
845 if (stream
->responses
)
852 static struct stream_response
*media_stream_pop_response(struct source_reader
*reader
, struct media_stream
*stream
)
854 struct stream_response
*response
;
859 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
861 if (response
->stream_index
== stream
->index
)
862 return media_stream_detach_response(reader
, response
);
867 if ((head
= list_head(&reader
->responses
)))
868 return media_stream_detach_response(reader
, LIST_ENTRY(head
, struct stream_response
, entry
));
874 static void source_reader_release_response(struct stream_response
*response
)
876 if (response
->sample
)
877 IMFSample_Release(response
->sample
);
881 static HRESULT
source_reader_get_stream_selection(const struct source_reader
*reader
, DWORD index
, BOOL
*selected
)
883 IMFStreamDescriptor
*sd
;
885 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, selected
, &sd
)))
886 return MF_E_INVALIDSTREAMNUMBER
;
887 IMFStreamDescriptor_Release(sd
);
892 static HRESULT
source_reader_start_source(struct source_reader
*reader
)
894 BOOL selected
, selection_changed
= FALSE
;
895 PROPVARIANT position
;
899 for (i
= 0; i
< reader
->stream_count
; ++i
)
901 source_reader_get_stream_selection(reader
, i
, &selected
);
903 reader
->streams
[i
].flags
|= STREAM_FLAG_SELECTED
;
905 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SELECTED
;
908 if (reader
->source_state
== SOURCE_STATE_STARTED
)
910 for (i
= 0; i
< reader
->stream_count
; ++i
)
912 selection_changed
= !!(reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
) ^
913 !!(reader
->streams
[i
].flags
& STREAM_FLAG_PRESENTED
);
914 if (selection_changed
)
919 position
.u
.hVal
.QuadPart
= 0;
920 if (reader
->source_state
!= SOURCE_STATE_STARTED
|| selection_changed
)
922 position
.vt
= reader
->source_state
== SOURCE_STATE_STARTED
? VT_EMPTY
: VT_I8
;
924 /* Update cached stream selection if descriptor was accepted. */
925 if (SUCCEEDED(hr
= IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &GUID_NULL
, &position
)))
927 for (i
= 0; i
< reader
->stream_count
; ++i
)
929 if (reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
)
930 reader
->streams
[i
].flags
|= STREAM_FLAG_PRESENTED
;
938 static BOOL
source_reader_got_response_for_stream(struct source_reader
*reader
, struct media_stream
*stream
)
940 struct stream_response
*response
;
942 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
944 if (response
->stream_index
== stream
->index
)
951 static BOOL
source_reader_get_read_result(struct source_reader
*reader
, struct media_stream
*stream
, DWORD flags
,
952 HRESULT
*status
, DWORD
*stream_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
954 struct stream_response
*response
= NULL
;
955 BOOL request_sample
= FALSE
;
957 if ((response
= media_stream_pop_response(reader
, stream
)))
959 *status
= response
->status
;
960 *stream_index
= stream
->index
;
961 *stream_flags
= response
->stream_flags
;
962 *timestamp
= response
->timestamp
;
963 *sample
= response
->sample
;
965 IMFSample_AddRef(*sample
);
967 source_reader_release_response(response
);
972 *stream_index
= stream
->index
;
976 if (stream
->state
== STREAM_STATE_EOS
)
978 *stream_flags
= MF_SOURCE_READERF_ENDOFSTREAM
;
982 request_sample
= !(flags
& MF_SOURCE_READER_CONTROLF_DRAIN
);
987 return !request_sample
;
990 static HRESULT
source_reader_get_first_selected_stream(struct source_reader
*reader
, unsigned int flags
,
991 unsigned int *stream_index
)
993 unsigned int i
, first_selected
= ~0u;
994 BOOL selected
, stream_drained
;
996 for (i
= 0; i
< reader
->stream_count
; ++i
)
998 stream_drained
= reader
->streams
[i
].state
== STREAM_STATE_EOS
&& !reader
->streams
[i
].responses
;
999 selected
= SUCCEEDED(source_reader_get_stream_selection(reader
, i
, &selected
)) && selected
;
1001 if (selected
&& !(reader
->streams
[i
].flags
& flags
))
1003 if (first_selected
== ~0u)
1006 if (!stream_drained
)
1014 /* If all selected streams reached EOS, use first selected. This fallback only applies after reader went through all
1015 selected streams once. */
1016 if (i
== reader
->stream_count
&& first_selected
!= ~0u && !flags
)
1018 *stream_index
= first_selected
;
1022 return i
== reader
->stream_count
? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED
: S_OK
;
1025 static HRESULT
source_reader_get_stream_read_index(struct source_reader
*reader
, unsigned int index
, unsigned int *stream_index
)
1032 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1033 *stream_index
= reader
->first_video_stream_index
;
1035 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1036 *stream_index
= reader
->first_audio_stream_index
;
1038 case MF_SOURCE_READER_ANY_STREAM
:
1039 if (reader
->async_callback
)
1041 /* Pick first selected stream. */
1042 hr
= source_reader_get_first_selected_stream(reader
, 0, stream_index
);
1046 /* Cycle through all selected streams once, next pick first selected. */
1047 if (FAILED(hr
= source_reader_get_first_selected_stream(reader
, STREAM_FLAG_REQUESTED_ONCE
, stream_index
)))
1048 hr
= source_reader_get_first_selected_stream(reader
, 0, stream_index
);
1052 *stream_index
= index
;
1055 /* Can't read from deselected streams. */
1056 if (SUCCEEDED(hr
= source_reader_get_stream_selection(reader
, *stream_index
, &selected
)) && !selected
)
1057 hr
= MF_E_INVALIDREQUEST
;
1062 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
)
1064 struct stream_response
*ptr
, *next
;
1066 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &reader
->responses
, struct stream_response
, entry
)
1068 if (stream
&& stream
->index
!= ptr
->stream_index
&&
1069 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_VIDEO_STREAM
&&
1070 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_AUDIO_STREAM
&&
1071 ptr
->stream_index
!= MF_SOURCE_READER_ANY_STREAM
)
1075 media_stream_detach_response(reader
, ptr
);
1076 source_reader_release_response(ptr
);
1080 static void source_reader_flush_stream(struct source_reader
*reader
, DWORD stream_index
)
1082 struct media_stream
*stream
= &reader
->streams
[stream_index
];
1084 source_reader_release_responses(reader
, stream
);
1085 if (stream
->decoder
)
1086 IMFTransform_ProcessMessage(stream
->decoder
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
1087 stream
->requests
= 0;
1090 static HRESULT
source_reader_flush(struct source_reader
*reader
, unsigned int index
)
1092 unsigned int stream_index
;
1095 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1097 for (stream_index
= 0; stream_index
< reader
->stream_count
; ++stream_index
)
1098 source_reader_flush_stream(reader
, stream_index
);
1104 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1105 stream_index
= reader
->first_video_stream_index
;
1107 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1108 stream_index
= reader
->first_audio_stream_index
;
1111 stream_index
= index
;
1114 if (stream_index
< reader
->stream_count
)
1115 source_reader_flush_stream(reader
, stream_index
);
1117 hr
= MF_E_INVALIDSTREAMNUMBER
;
1123 static HRESULT WINAPI
source_reader_async_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1125 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1126 struct media_stream
*stream
, stub_stream
= { .requests
= 1 };
1127 struct source_reader_async_command
*command
;
1128 struct stream_response
*response
;
1129 DWORD stream_index
, stream_flags
;
1130 BOOL report_sample
= FALSE
;
1131 IMFSample
*sample
= NULL
;
1132 LONGLONG timestamp
= 0;
1136 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
1139 command
= impl_from_async_command_IUnknown(state
);
1141 switch (command
->op
)
1143 case SOURCE_READER_ASYNC_READ
:
1144 EnterCriticalSection(&reader
->cs
);
1146 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1148 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, command
->u
.read
.stream_index
, &stream_index
)))
1150 stream
= &reader
->streams
[stream_index
];
1152 if (!(report_sample
= source_reader_get_read_result(reader
, stream
, command
->u
.read
.flags
, &status
,
1153 &stream_index
, &stream_flags
, ×tamp
, &sample
)))
1156 source_reader_request_sample(reader
, stream
);
1157 /* FIXME: set error stream/reader state on request failure */
1162 stub_stream
.index
= command
->u
.read
.stream_index
;
1163 source_reader_queue_response(reader
, &stub_stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
1167 LeaveCriticalSection(&reader
->cs
);
1170 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, status
, stream_index
, stream_flags
,
1174 IMFSample_Release(sample
);
1178 case SOURCE_READER_ASYNC_SEEK
:
1180 EnterCriticalSection(&reader
->cs
);
1181 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &command
->u
.seek
.format
,
1182 &command
->u
.seek
.position
)))
1184 reader
->flags
|= SOURCE_READER_SEEKING
;
1186 LeaveCriticalSection(&reader
->cs
);
1190 case SOURCE_READER_ASYNC_SAMPLE_READY
:
1192 EnterCriticalSection(&reader
->cs
);
1193 response
= media_stream_pop_response(reader
, NULL
);
1194 LeaveCriticalSection(&reader
->cs
);
1198 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, response
->status
, response
->stream_index
,
1199 response
->stream_flags
, response
->timestamp
, response
->sample
);
1200 source_reader_release_response(response
);
1204 case SOURCE_READER_ASYNC_FLUSH
:
1205 EnterCriticalSection(&reader
->cs
);
1206 source_reader_flush(reader
, command
->u
.flush
.stream_index
);
1207 reader
->flags
&= ~SOURCE_READER_FLUSHING
;
1208 LeaveCriticalSection(&reader
->cs
);
1210 IMFSourceReaderCallback_OnFlush(reader
->async_callback
, command
->u
.flush
.stream_index
);
1216 IUnknown_Release(state
);
1221 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl
=
1223 source_reader_callback_QueryInterface
,
1224 source_reader_async_commands_callback_AddRef
,
1225 source_reader_async_commands_callback_Release
,
1226 source_reader_callback_GetParameters
,
1227 source_reader_async_commands_callback_Invoke
,
1230 static HRESULT WINAPI
src_reader_QueryInterface(IMFSourceReader
*iface
, REFIID riid
, void **out
)
1232 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1234 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1236 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
1237 IsEqualGUID(riid
, &IID_IMFSourceReader
))
1239 *out
= &reader
->IMFSourceReader_iface
;
1243 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1245 return E_NOINTERFACE
;
1248 IUnknown_AddRef((IUnknown
*)*out
);
1252 static ULONG WINAPI
src_reader_AddRef(IMFSourceReader
*iface
)
1254 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1255 ULONG refcount
= InterlockedIncrement(&reader
->refcount
);
1257 TRACE("%p, refcount %u.\n", iface
, refcount
);
1262 static ULONG WINAPI
src_reader_Release(IMFSourceReader
*iface
)
1264 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1265 ULONG refcount
= InterlockedDecrement(&reader
->refcount
);
1268 TRACE("%p, refcount %u.\n", iface
, refcount
);
1272 if (reader
->async_callback
)
1273 IMFSourceReaderCallback_Release(reader
->async_callback
);
1274 if (reader
->flags
& SOURCE_READER_SHUTDOWN_ON_RELEASE
)
1275 IMFMediaSource_Shutdown(reader
->source
);
1276 if (reader
->descriptor
)
1277 IMFPresentationDescriptor_Release(reader
->descriptor
);
1278 IMFMediaSource_Release(reader
->source
);
1280 for (i
= 0; i
< reader
->stream_count
; ++i
)
1282 struct media_stream
*stream
= &reader
->streams
[i
];
1285 IMFMediaStream_Release(stream
->stream
);
1286 if (stream
->current
)
1287 IMFMediaType_Release(stream
->current
);
1288 if (stream
->decoder
)
1289 IMFTransform_Release(stream
->decoder
);
1291 source_reader_release_responses(reader
, NULL
);
1292 heap_free(reader
->streams
);
1293 DeleteCriticalSection(&reader
->cs
);
1300 static HRESULT WINAPI
src_reader_GetStreamSelection(IMFSourceReader
*iface
, DWORD index
, BOOL
*selected
)
1302 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1304 TRACE("%p, %#x, %p.\n", iface
, index
, selected
);
1308 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1309 index
= reader
->first_video_stream_index
;
1311 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1312 index
= reader
->first_audio_stream_index
;
1318 return source_reader_get_stream_selection(reader
, index
, selected
);
1321 static HRESULT WINAPI
src_reader_SetStreamSelection(IMFSourceReader
*iface
, DWORD index
, BOOL selection
)
1323 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1325 BOOL selection_changed
= FALSE
, selected
;
1328 TRACE("%p, %#x, %d.\n", iface
, index
, selection
);
1330 selection
= !!selection
;
1332 EnterCriticalSection(&reader
->cs
);
1334 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1336 for (i
= 0; i
< reader
->stream_count
; ++i
)
1338 if (!selection_changed
)
1340 source_reader_get_stream_selection(reader
, i
, &selected
);
1341 if (selected
^ selection
)
1342 selection_changed
= TRUE
;
1346 IMFPresentationDescriptor_SelectStream(reader
->descriptor
, i
);
1348 IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, i
);
1355 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1356 index
= reader
->first_video_stream_index
;
1358 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1359 index
= reader
->first_audio_stream_index
;
1365 source_reader_get_stream_selection(reader
, index
, &selected
);
1366 if (selected
^ selection
)
1367 selection_changed
= TRUE
;
1370 hr
= IMFPresentationDescriptor_SelectStream(reader
->descriptor
, index
);
1372 hr
= IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, index
);
1375 if (SUCCEEDED(hr
) && selection_changed
)
1377 for (i
= 0; i
< reader
->stream_count
; ++i
)
1378 reader
->streams
[i
].flags
&= ~STREAM_FLAG_REQUESTED_ONCE
;
1381 LeaveCriticalSection(&reader
->cs
);
1383 return SUCCEEDED(hr
) ? S_OK
: MF_E_INVALIDSTREAMNUMBER
;
1386 static HRESULT
source_reader_get_native_media_type(struct source_reader
*reader
, DWORD index
, DWORD type_index
,
1387 IMFMediaType
**type
)
1389 IMFMediaTypeHandler
*handler
;
1390 IMFStreamDescriptor
*sd
;
1391 IMFMediaType
*src_type
;
1397 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1398 index
= reader
->first_video_stream_index
;
1400 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1401 index
= reader
->first_audio_stream_index
;
1407 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1408 return MF_E_INVALIDSTREAMNUMBER
;
1410 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
1411 IMFStreamDescriptor_Release(sd
);
1415 if (type_index
== MF_SOURCE_READER_CURRENT_TYPE_INDEX
)
1416 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &src_type
);
1418 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, type_index
, &src_type
);
1419 IMFMediaTypeHandler_Release(handler
);
1423 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
1424 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)*type
);
1425 IMFMediaType_Release(src_type
);
1431 static HRESULT WINAPI
src_reader_GetNativeMediaType(IMFSourceReader
*iface
, DWORD index
, DWORD type_index
,
1432 IMFMediaType
**type
)
1434 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1436 TRACE("%p, %#x, %#x, %p.\n", iface
, index
, type_index
, type
);
1438 return source_reader_get_native_media_type(reader
, index
, type_index
, type
);
1441 static HRESULT WINAPI
src_reader_GetCurrentMediaType(IMFSourceReader
*iface
, DWORD index
, IMFMediaType
**type
)
1443 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1446 TRACE("%p, %#x, %p.\n", iface
, index
, type
);
1450 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1451 index
= reader
->first_video_stream_index
;
1453 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1454 index
= reader
->first_audio_stream_index
;
1460 if (index
>= reader
->stream_count
)
1461 return MF_E_INVALIDSTREAMNUMBER
;
1463 if (FAILED(hr
= MFCreateMediaType(type
)))
1466 EnterCriticalSection(&reader
->cs
);
1468 hr
= IMFMediaType_CopyAllItems(reader
->streams
[index
].current
, (IMFAttributes
*)*type
);
1470 LeaveCriticalSection(&reader
->cs
);
1475 static HRESULT
source_reader_get_source_type_handler(struct source_reader
*reader
, DWORD index
,
1476 IMFMediaTypeHandler
**handler
)
1478 IMFStreamDescriptor
*sd
;
1482 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1485 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, handler
);
1486 IMFStreamDescriptor_Release(sd
);
1491 static HRESULT
source_reader_set_compatible_media_type(struct source_reader
*reader
, DWORD index
, IMFMediaType
*type
)
1493 IMFMediaTypeHandler
*type_handler
;
1494 IMFMediaType
*native_type
;
1495 BOOL type_set
= FALSE
;
1500 if (FAILED(hr
= IMFMediaType_IsEqual(type
, reader
->streams
[index
].current
, &flags
)))
1503 if (!(flags
& MF_MEDIATYPE_EQUAL_MAJOR_TYPES
))
1504 return MF_E_INVALIDMEDIATYPE
;
1506 /* No need for a decoder or type change. */
1507 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_TYPES
)
1510 if (FAILED(hr
= source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1513 while (!type_set
&& IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler
, i
++, &native_type
) == S_OK
)
1515 static const DWORD compare_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_TYPES
;
1517 if (SUCCEEDED(IMFMediaType_IsEqual(native_type
, type
, &flags
)) && (flags
& compare_flags
) == compare_flags
)
1519 if ((type_set
= SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, native_type
))))
1520 IMFMediaType_CopyAllItems(native_type
, (IMFAttributes
*)reader
->streams
[index
].current
);
1523 IMFMediaType_Release(native_type
);
1526 IMFMediaTypeHandler_Release(type_handler
);
1528 return type_set
? S_OK
: S_FALSE
;
1531 static HRESULT
source_reader_configure_decoder(struct source_reader
*reader
, DWORD index
, const CLSID
*clsid
,
1532 IMFMediaType
*input_type
, IMFMediaType
*output_type
)
1534 IMFMediaTypeHandler
*type_handler
;
1535 IMFTransform
*transform
= NULL
;
1536 IMFMediaType
*type
= NULL
;
1541 if (FAILED(hr
= CoCreateInstance(clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTransform
, (void **)&transform
)))
1543 WARN("Failed to create transform object, hr %#x.\n", hr
);
1547 if (FAILED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0)))
1549 WARN("Failed to set decoder input type, hr %#x.\n", hr
);
1550 IMFTransform_Release(transform
);
1554 /* Find the relevant output type. */
1555 while (IMFTransform_GetOutputAvailableType(transform
, 0, i
++, &type
) == S_OK
)
1559 if (SUCCEEDED(IMFMediaType_IsEqual(type
, output_type
, &flags
)))
1561 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_TYPES
)
1563 if (SUCCEEDED(IMFTransform_SetOutputType(transform
, 0, type
, 0)))
1565 if (SUCCEEDED(source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1567 IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, input_type
);
1568 IMFMediaTypeHandler_Release(type_handler
);
1571 if (FAILED(hr
= IMFMediaType_CopyAllItems(type
, (IMFAttributes
*)reader
->streams
[index
].current
)))
1572 WARN("Failed to copy attributes, hr %#x.\n", hr
);
1573 IMFMediaType_Release(type
);
1575 if (reader
->streams
[index
].decoder
)
1576 IMFTransform_Release(reader
->streams
[index
].decoder
);
1578 reader
->streams
[index
].decoder
= transform
;
1585 IMFMediaType_Release(type
);
1588 WARN("Failed to find suitable decoder output type.\n");
1590 IMFTransform_Release(transform
);
1592 return MF_E_TOPO_CODEC_NOT_FOUND
;
1595 static HRESULT
source_reader_create_decoder_for_stream(struct source_reader
*reader
, DWORD index
, IMFMediaType
*output_type
)
1597 MFT_REGISTER_TYPE_INFO in_type
, out_type
;
1598 CLSID
*clsids
, mft_clsid
, category
;
1599 unsigned int i
= 0, count
;
1600 IMFMediaType
*input_type
;
1603 /* TODO: should we check if the source type is compressed? */
1605 if (FAILED(hr
= IMFMediaType_GetMajorType(output_type
, &out_type
.guidMajorType
)))
1608 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
))
1610 category
= MFT_CATEGORY_VIDEO_DECODER
;
1612 else if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1614 category
= MFT_CATEGORY_AUDIO_DECODER
;
1618 WARN("Unhandled major type %s.\n", debugstr_guid(&out_type
.guidMajorType
));
1619 return MF_E_TOPO_CODEC_NOT_FOUND
;
1622 if (FAILED(hr
= IMFMediaType_GetGUID(output_type
, &MF_MT_SUBTYPE
, &out_type
.guidSubtype
)))
1625 in_type
.guidMajorType
= out_type
.guidMajorType
;
1627 while (source_reader_get_native_media_type(reader
, index
, i
++, &input_type
) == S_OK
)
1629 if (SUCCEEDED(IMFMediaType_GetGUID(input_type
, &MF_MT_SUBTYPE
, &in_type
.guidSubtype
)))
1632 if (SUCCEEDED(hr
= MFTEnum(category
, 0, &in_type
, &out_type
, NULL
, &clsids
, &count
)) && count
)
1634 mft_clsid
= clsids
[0];
1635 CoTaskMemFree(clsids
);
1637 /* TODO: Should we iterate over all of them? */
1638 if (SUCCEEDED(source_reader_configure_decoder(reader
, index
, &mft_clsid
, input_type
, output_type
)))
1640 IMFMediaType_Release(input_type
);
1647 IMFMediaType_Release(input_type
);
1650 return MF_E_TOPO_CODEC_NOT_FOUND
;
1653 static HRESULT WINAPI
src_reader_SetCurrentMediaType(IMFSourceReader
*iface
, DWORD index
, DWORD
*reserved
,
1656 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1659 TRACE("%p, %#x, %p, %p.\n", iface
, index
, reserved
, type
);
1663 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1664 index
= reader
->first_video_stream_index
;
1666 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1667 index
= reader
->first_audio_stream_index
;
1673 if (index
>= reader
->stream_count
)
1674 return MF_E_INVALIDSTREAMNUMBER
;
1676 /* FIXME: setting the output type while streaming should trigger a flush */
1678 EnterCriticalSection(&reader
->cs
);
1680 if ((hr
= source_reader_set_compatible_media_type(reader
, index
, type
)) == S_FALSE
)
1681 hr
= source_reader_create_decoder_for_stream(reader
, index
, type
);
1683 LeaveCriticalSection(&reader
->cs
);
1688 static HRESULT WINAPI
src_reader_SetCurrentPosition(IMFSourceReader
*iface
, REFGUID format
, REFPROPVARIANT position
)
1690 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1691 struct source_reader_async_command
*command
;
1692 unsigned int i
, flags
;
1695 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), position
);
1697 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
1700 if (!(flags
& MFMEDIASOURCE_CAN_SEEK
))
1701 return MF_E_INVALIDREQUEST
;
1703 EnterCriticalSection(&reader
->cs
);
1705 /* Check if we got pending requests. */
1706 for (i
= 0; i
< reader
->stream_count
; ++i
)
1708 if (reader
->streams
[i
].requests
)
1710 hr
= MF_E_INVALIDREQUEST
;
1717 if (reader
->async_callback
)
1719 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK
, &command
)))
1721 command
->u
.seek
.format
= *format
;
1722 PropVariantCopy(&command
->u
.seek
.position
, position
);
1724 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED
, &reader
->async_commands_callback
,
1725 &command
->IUnknown_iface
);
1726 IUnknown_Release(&command
->IUnknown_iface
);
1731 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, format
, position
)))
1733 reader
->flags
|= SOURCE_READER_SEEKING
;
1734 while (reader
->flags
& SOURCE_READER_SEEKING
)
1736 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
1742 LeaveCriticalSection(&reader
->cs
);
1747 static HRESULT
source_reader_read_sample(struct source_reader
*reader
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
1748 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1750 unsigned int actual_index_tmp
;
1751 struct media_stream
*stream
;
1752 LONGLONG timestamp_tmp
;
1756 if (!stream_flags
|| !sample
)
1762 timestamp
= ×tamp_tmp
;
1765 actual_index
= &actual_index_tmp
;
1767 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1769 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, index
, &stream_index
)))
1771 *actual_index
= stream_index
;
1773 stream
= &reader
->streams
[stream_index
];
1775 if (!source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
1778 while (!source_reader_got_response_for_stream(reader
, stream
) && stream
->state
!= STREAM_STATE_EOS
)
1781 if (FAILED(hr
= source_reader_request_sample(reader
, stream
)))
1782 WARN("Failed to request a sample, hr %#x.\n", hr
);
1783 SleepConditionVariableCS(&reader
->sample_event
, &reader
->cs
, INFINITE
);
1786 source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
1792 *actual_index
= index
;
1793 *stream_flags
= MF_SOURCE_READERF_ERROR
;
1798 TRACE("Stream %u, got sample %p, flags %#x.\n", *actual_index
, *sample
, *stream_flags
);
1803 static HRESULT
source_reader_read_sample_async(struct source_reader
*reader
, unsigned int index
, unsigned int flags
,
1804 unsigned int *actual_index
, unsigned int *stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1806 struct source_reader_async_command
*command
;
1809 if (actual_index
|| stream_flags
|| timestamp
|| sample
)
1810 return E_INVALIDARG
;
1812 if (reader
->flags
& SOURCE_READER_FLUSHING
)
1813 hr
= MF_E_NOTACCEPTING
;
1816 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_READ
, &command
)))
1818 command
->u
.read
.stream_index
= index
;
1819 command
->u
.read
.flags
= flags
;
1821 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
1822 IUnknown_Release(&command
->IUnknown_iface
);
1829 static HRESULT WINAPI
src_reader_ReadSample(IMFSourceReader
*iface
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
1830 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1832 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1835 TRACE("%p, %#x, %#x, %p, %p, %p, %p\n", iface
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
1837 EnterCriticalSection(&reader
->cs
);
1839 while (reader
->flags
& SOURCE_READER_SEEKING
)
1841 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
1844 if (reader
->async_callback
)
1845 hr
= source_reader_read_sample_async(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
1847 hr
= source_reader_read_sample(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
1849 LeaveCriticalSection(&reader
->cs
);
1854 static HRESULT
source_reader_flush_async(struct source_reader
*reader
, unsigned int index
)
1856 struct source_reader_async_command
*command
;
1857 unsigned int stream_index
;
1860 if (reader
->flags
& SOURCE_READER_FLUSHING
)
1861 return MF_E_INVALIDREQUEST
;
1865 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1866 stream_index
= reader
->first_video_stream_index
;
1868 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1869 stream_index
= reader
->first_audio_stream_index
;
1872 stream_index
= index
;
1875 reader
->flags
|= SOURCE_READER_FLUSHING
;
1877 if (stream_index
!= MF_SOURCE_READER_ALL_STREAMS
&& stream_index
>= reader
->stream_count
)
1878 return MF_E_INVALIDSTREAMNUMBER
;
1880 if (FAILED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH
, &command
)))
1883 command
->u
.flush
.stream_index
= stream_index
;
1885 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
1886 IUnknown_Release(&command
->IUnknown_iface
);
1891 static HRESULT WINAPI
src_reader_Flush(IMFSourceReader
*iface
, DWORD index
)
1893 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1896 TRACE("%p, %#x.\n", iface
, index
);
1898 EnterCriticalSection(&reader
->cs
);
1900 if (reader
->async_callback
)
1901 hr
= source_reader_flush_async(reader
, index
);
1903 hr
= source_reader_flush(reader
, index
);
1905 LeaveCriticalSection(&reader
->cs
);
1910 static HRESULT WINAPI
src_reader_GetServiceForStream(IMFSourceReader
*iface
, DWORD index
, REFGUID service
,
1911 REFIID riid
, void **object
)
1913 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1914 IUnknown
*obj
= NULL
;
1917 TRACE("%p, %#x, %s, %s, %p\n", iface
, index
, debugstr_guid(service
), debugstr_guid(riid
), object
);
1921 case MF_SOURCE_READER_MEDIASOURCE
:
1922 obj
= (IUnknown
*)reader
->source
;
1925 FIXME("Unsupported index %#x.\n", index
);
1929 if (IsEqualGUID(service
, &GUID_NULL
))
1931 hr
= IUnknown_QueryInterface(obj
, riid
, object
);
1937 hr
= IUnknown_QueryInterface(obj
, &IID_IMFGetService
, (void **)&gs
);
1940 hr
= IMFGetService_GetService(gs
, service
, riid
, object
);
1941 IMFGetService_Release(gs
);
1948 static HRESULT WINAPI
src_reader_GetPresentationAttribute(IMFSourceReader
*iface
, DWORD index
,
1949 REFGUID guid
, PROPVARIANT
*value
)
1951 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1952 IMFStreamDescriptor
*sd
;
1956 TRACE("%p, %#x, %s, %p.\n", iface
, index
, debugstr_guid(guid
), value
);
1960 case MF_SOURCE_READER_MEDIASOURCE
:
1961 if (IsEqualGUID(guid
, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS
))
1965 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
1969 value
->u
.ulVal
= flags
;
1974 return IMFPresentationDescriptor_GetItem(reader
->descriptor
, guid
, value
);
1977 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1978 index
= reader
->first_video_stream_index
;
1980 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1981 index
= reader
->first_audio_stream_index
;
1987 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1990 hr
= IMFStreamDescriptor_GetItem(sd
, guid
, value
);
1991 IMFStreamDescriptor_Release(sd
);
1996 struct IMFSourceReaderVtbl srcreader_vtbl
=
1998 src_reader_QueryInterface
,
2001 src_reader_GetStreamSelection
,
2002 src_reader_SetStreamSelection
,
2003 src_reader_GetNativeMediaType
,
2004 src_reader_GetCurrentMediaType
,
2005 src_reader_SetCurrentMediaType
,
2006 src_reader_SetCurrentPosition
,
2007 src_reader_ReadSample
,
2009 src_reader_GetServiceForStream
,
2010 src_reader_GetPresentationAttribute
2013 static DWORD
reader_get_first_stream_index(IMFPresentationDescriptor
*descriptor
, const GUID
*major
)
2015 unsigned int count
, i
;
2020 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
2021 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2023 for (i
= 0; i
< count
; ++i
)
2025 IMFMediaTypeHandler
*handler
;
2026 IMFStreamDescriptor
*sd
;
2028 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
, &selected
, &sd
)))
2030 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2031 IMFStreamDescriptor_Release(sd
);
2034 hr
= IMFMediaTypeHandler_GetMajorType(handler
, &guid
);
2035 IMFMediaTypeHandler_Release(handler
);
2038 WARN("Failed to get stream major type, hr %#x.\n", hr
);
2042 if (IsEqualGUID(&guid
, major
))
2050 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2053 static HRESULT
create_source_reader_from_source(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2054 BOOL shutdown_on_release
, REFIID riid
, void **out
)
2056 struct source_reader
*object
;
2060 object
= heap_alloc_zero(sizeof(*object
));
2062 return E_OUTOFMEMORY
;
2064 object
->IMFSourceReader_iface
.lpVtbl
= &srcreader_vtbl
;
2065 object
->source_events_callback
.lpVtbl
= &source_events_callback_vtbl
;
2066 object
->stream_events_callback
.lpVtbl
= &stream_events_callback_vtbl
;
2067 object
->async_commands_callback
.lpVtbl
= &async_commands_callback_vtbl
;
2068 object
->refcount
= 1;
2069 list_init(&object
->responses
);
2070 if (shutdown_on_release
)
2071 object
->flags
|= SOURCE_READER_SHUTDOWN_ON_RELEASE
;
2072 object
->source
= source
;
2073 IMFMediaSource_AddRef(object
->source
);
2074 InitializeCriticalSection(&object
->cs
);
2075 InitializeConditionVariable(&object
->sample_event
);
2076 InitializeConditionVariable(&object
->state_event
);
2078 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(object
->source
, &object
->descriptor
)))
2081 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(object
->descriptor
, &object
->stream_count
)))
2084 if (!(object
->streams
= heap_alloc_zero(object
->stream_count
* sizeof(*object
->streams
))))
2090 /* Set initial current media types. */
2091 for (i
= 0; i
< object
->stream_count
; ++i
)
2093 IMFMediaTypeHandler
*handler
;
2094 IMFStreamDescriptor
*sd
;
2095 IMFMediaType
*src_type
;
2098 if (FAILED(hr
= MFCreateMediaType(&object
->streams
[i
].current
)))
2101 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(object
->descriptor
, i
, &selected
, &sd
)))
2104 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &object
->streams
[i
].id
)))
2105 WARN("Failed to get stream identifier, hr %#x.\n", hr
);
2107 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2108 IMFStreamDescriptor_Release(sd
);
2112 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, 0, &src_type
);
2113 IMFMediaTypeHandler_Release(handler
);
2117 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)object
->streams
[i
].current
);
2118 IMFMediaType_Release(src_type
);
2122 object
->streams
[i
].index
= i
;
2128 /* At least one major type has to be set. */
2129 object
->first_audio_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Audio
);
2130 object
->first_video_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Video
);
2132 if (object
->first_audio_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
&&
2133 object
->first_video_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
)
2135 hr
= MF_E_ATTRIBUTENOTFOUND
;
2138 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(object
->source
, &object
->source_events_callback
,
2139 (IUnknown
*)object
->source
)))
2146 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_ASYNC_CALLBACK
, &IID_IMFSourceReaderCallback
,
2147 (void **)&object
->async_callback
);
2148 if (object
->async_callback
)
2149 TRACE("Using async callback %p.\n", object
->async_callback
);
2152 hr
= IMFSourceReader_QueryInterface(&object
->IMFSourceReader_iface
, riid
, out
);
2155 IMFSourceReader_Release(&object
->IMFSourceReader_iface
);
2159 static HRESULT
bytestream_get_url_hint(IMFByteStream
*stream
, WCHAR
const **url
)
2161 static const unsigned char asfmagic
[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c};
2162 static const unsigned char wavmagic
[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '};
2163 static const unsigned char wavmask
[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
2164 static const unsigned char isommagic
[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00};
2165 static const unsigned char mp42magic
[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00};
2166 static const unsigned char mp4mask
[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00};
2167 static const struct stream_content_url_hint
2169 const unsigned char *magic
;
2171 const unsigned char *mask
;
2175 { asfmagic
, L
".asf" },
2176 { wavmagic
, L
".wav", wavmask
},
2177 { isommagic
, L
".mp4", mp4mask
},
2178 { mp42magic
, L
".mp4", mp4mask
},
2180 unsigned char buffer
[4 * sizeof(unsigned int)], pattern
[4 * sizeof(unsigned int)];
2181 unsigned int i
, j
, length
= 0, caps
= 0;
2182 IMFAttributes
*attributes
;
2188 if (SUCCEEDED(IMFByteStream_QueryInterface(stream
, &IID_IMFAttributes
, (void **)&attributes
)))
2190 IMFAttributes_GetStringLength(attributes
, &MF_BYTESTREAM_CONTENT_TYPE
, &length
);
2191 IMFAttributes_Release(attributes
);
2197 if (FAILED(hr
= IMFByteStream_GetCapabilities(stream
, &caps
)))
2200 if (!(caps
& MFBYTESTREAM_IS_SEEKABLE
))
2203 if (FAILED(hr
= IMFByteStream_GetCurrentPosition(stream
, &position
)))
2206 hr
= IMFByteStream_Read(stream
, buffer
, sizeof(buffer
), &length
);
2207 IMFByteStream_SetCurrentPosition(stream
, position
);
2211 if (length
< sizeof(buffer
))
2214 for (i
= 0; i
< ARRAY_SIZE(url_hints
); ++i
)
2216 memcpy(pattern
, buffer
, sizeof(buffer
));
2217 if (url_hints
[i
].mask
)
2219 unsigned int *mask
= (unsigned int *)url_hints
[i
].mask
;
2220 unsigned int *data
= (unsigned int *)pattern
;
2222 for (j
= 0; j
< sizeof(buffer
) / sizeof(unsigned int); ++j
)
2226 if (!memcmp(pattern
, url_hints
[i
].magic
, sizeof(pattern
)))
2228 *url
= url_hints
[i
].url
;
2234 TRACE("Stream type guessed as %s from %s.\n", debugstr_w(*url
), debugstr_an((char *)buffer
, length
));
2236 WARN("Unrecognized content type %s.\n", debugstr_an((char *)buffer
, length
));
2241 static HRESULT
create_source_reader_from_stream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2242 REFIID riid
, void **out
)
2244 IPropertyStore
*props
= NULL
;
2245 IMFSourceResolver
*resolver
;
2246 MF_OBJECT_TYPE obj_type
;
2247 IMFMediaSource
*source
;
2251 /* If stream does not have content type set, try to guess from starting byte sequence. */
2252 if (FAILED(hr
= bytestream_get_url_hint(stream
, &url
)))
2255 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2259 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2262 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, stream
, url
, MF_RESOLUTION_MEDIASOURCE
, props
,
2263 &obj_type
, (IUnknown
**)&source
);
2264 IMFSourceResolver_Release(resolver
);
2266 IPropertyStore_Release(props
);
2270 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2271 IMFMediaSource_Release(source
);
2275 static HRESULT
create_source_reader_from_url(const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2277 IPropertyStore
*props
= NULL
;
2278 IMFSourceResolver
*resolver
;
2279 IUnknown
*object
= NULL
;
2280 MF_OBJECT_TYPE obj_type
;
2281 IMFMediaSource
*source
;
2284 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2288 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2291 hr
= IMFSourceResolver_CreateObjectFromURL(resolver
, url
, MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
,
2297 case MF_OBJECT_BYTESTREAM
:
2298 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, (IMFByteStream
*)object
, NULL
,
2299 MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
, (IUnknown
**)&source
);
2301 case MF_OBJECT_MEDIASOURCE
:
2302 source
= (IMFMediaSource
*)object
;
2303 IMFMediaSource_AddRef(source
);
2306 WARN("Unknown object type %d.\n", obj_type
);
2309 IUnknown_Release(object
);
2312 IMFSourceResolver_Release(resolver
);
2314 IPropertyStore_Release(props
);
2318 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2319 IMFMediaSource_Release(source
);
2323 static HRESULT
create_source_reader_from_object(IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2325 IMFMediaSource
*source
= NULL
;
2326 IMFByteStream
*stream
= NULL
;
2329 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSource
, (void **)&source
);
2331 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2335 UINT32 disconnect
= 0;
2338 IMFAttributes_GetUINT32(attributes
, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN
, &disconnect
);
2339 hr
= create_source_reader_from_source(source
, attributes
, !disconnect
, riid
, out
);
2342 hr
= create_source_reader_from_stream(stream
, attributes
, riid
, out
);
2345 IMFMediaSource_Release(source
);
2347 IMFByteStream_Release(stream
);
2352 /***********************************************************************
2353 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2355 HRESULT WINAPI
MFCreateSourceReaderFromByteStream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2356 IMFSourceReader
**reader
)
2358 TRACE("%p, %p, %p.\n", stream
, attributes
, reader
);
2360 return create_source_reader_from_object((IUnknown
*)stream
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2363 /***********************************************************************
2364 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2366 HRESULT WINAPI
MFCreateSourceReaderFromMediaSource(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2367 IMFSourceReader
**reader
)
2369 TRACE("%p, %p, %p.\n", source
, attributes
, reader
);
2371 return create_source_reader_from_object((IUnknown
*)source
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2374 /***********************************************************************
2375 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2377 HRESULT WINAPI
MFCreateSourceReaderFromURL(const WCHAR
*url
, IMFAttributes
*attributes
, IMFSourceReader
**reader
)
2379 TRACE("%s, %p, %p.\n", debugstr_w(url
), attributes
, reader
);
2381 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2384 static HRESULT WINAPI
readwrite_factory_QueryInterface(IMFReadWriteClassFactory
*iface
, REFIID riid
, void **out
)
2386 if (IsEqualIID(riid
, &IID_IMFReadWriteClassFactory
) ||
2387 IsEqualIID(riid
, &IID_IUnknown
))
2390 IMFReadWriteClassFactory_AddRef(iface
);
2394 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2396 return E_NOINTERFACE
;
2399 static ULONG WINAPI
readwrite_factory_AddRef(IMFReadWriteClassFactory
*iface
)
2404 static ULONG WINAPI
readwrite_factory_Release(IMFReadWriteClassFactory
*iface
)
2409 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2410 const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2412 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid
), debugstr_w(url
), attributes
, debugstr_guid(riid
), out
);
2414 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2416 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, out
);
2419 FIXME("Unsupported %s.\n", debugstr_guid(clsid
));
2424 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2425 IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2429 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid
), unk
, attributes
, debugstr_guid(riid
), out
);
2431 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2433 return create_source_reader_from_object(unk
, attributes
, riid
, out
);
2435 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2437 IMFByteStream
*stream
= NULL
;
2438 IMFMediaSink
*sink
= NULL
;
2440 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2442 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSink
, (void **)&sink
);
2445 hr
= create_sink_writer_from_stream(stream
, attributes
, riid
, out
);
2447 hr
= create_sink_writer_from_sink(sink
, attributes
, riid
, out
);
2450 IMFMediaSink_Release(sink
);
2452 IMFByteStream_Release(stream
);
2458 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2464 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl
=
2466 readwrite_factory_QueryInterface
,
2467 readwrite_factory_AddRef
,
2468 readwrite_factory_Release
,
2469 readwrite_factory_CreateInstanceFromURL
,
2470 readwrite_factory_CreateInstanceFromObject
,
2473 static IMFReadWriteClassFactory readwrite_factory
= { &readwrite_factory_vtbl
};
2475 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **out
)
2477 TRACE("%s, %p.\n", debugstr_guid(riid
), out
);
2479 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2480 IsEqualGUID(riid
, &IID_IUnknown
))
2482 IClassFactory_AddRef(iface
);
2487 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2489 return E_NOINTERFACE
;
2492 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2497 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2502 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **out
)
2504 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), out
);
2509 return CLASS_E_NOAGGREGATION
;
2511 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory
, riid
, out
);
2514 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2516 FIXME("%d.\n", dolock
);
2520 static const struct IClassFactoryVtbl classfactoryvtbl
=
2522 classfactory_QueryInterface
,
2523 classfactory_AddRef
,
2524 classfactory_Release
,
2525 classfactory_CreateInstance
,
2526 classfactory_LockServer
,
2529 static IClassFactory classfactory
= { &classfactoryvtbl
};
2531 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
2533 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
2535 if (IsEqualGUID(clsid
, &CLSID_MFReadWriteClassFactory
))
2536 return IClassFactory_QueryInterface(&classfactory
, riid
, out
);
2538 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2540 return CLASS_E_CLASSNOTAVAILABLE
;