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. */
108 IMFMediaStream
*stream
;
109 IMFMediaType
*current
;
110 IMFTransform
*decoder
;
113 enum media_stream_state state
;
115 unsigned int requests
;
116 unsigned int responses
;
119 enum source_reader_async_op
121 SOURCE_READER_ASYNC_READ
,
122 SOURCE_READER_ASYNC_SEEK
,
123 SOURCE_READER_ASYNC_FLUSH
,
124 SOURCE_READER_ASYNC_SAMPLE_READY
,
127 struct source_reader_async_command
129 IUnknown IUnknown_iface
;
131 enum source_reader_async_op op
;
137 unsigned int stream_index
;
142 PROPVARIANT position
;
146 unsigned int stream_index
;
150 unsigned int stream_index
;
155 enum source_reader_flags
157 SOURCE_READER_FLUSHING
= 0x1,
158 SOURCE_READER_SEEKING
= 0x2,
159 SOURCE_READER_SHUTDOWN_ON_RELEASE
= 0x4,
164 IMFSourceReader IMFSourceReader_iface
;
165 IMFAsyncCallback source_events_callback
;
166 IMFAsyncCallback stream_events_callback
;
167 IMFAsyncCallback async_commands_callback
;
169 IMFMediaSource
*source
;
170 IMFPresentationDescriptor
*descriptor
;
171 IMFSourceReaderCallback
*async_callback
;
172 unsigned int first_audio_stream_index
;
173 unsigned int first_video_stream_index
;
174 unsigned int last_read_index
;
175 unsigned int stream_count
;
177 enum media_source_state source_state
;
178 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
;
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 if (FAILED(source_reader_request_sample(reader
, &reader
->streams
[i
])))
443 WakeAllConditionVariable(&reader
->sample_event
);
449 if (i
== reader
->stream_count
)
450 WARN("Stream with id %#x was not present in presentation descriptor.\n", id
);
452 LeaveCriticalSection(&reader
->cs
);
454 IMFMediaStream_Release(stream
);
459 static HRESULT
source_reader_source_state_handler(struct source_reader
*reader
, MediaEventType event_type
)
461 EnterCriticalSection(&reader
->cs
);
465 case MESourceStarted
:
466 reader
->source_state
= SOURCE_STATE_STARTED
;
468 case MESourceStopped
:
469 reader
->source_state
= SOURCE_STATE_STOPPED
;
472 reader
->flags
&= ~SOURCE_READER_SEEKING
;
475 WARN("Unhandled event %d.\n", event_type
);
478 LeaveCriticalSection(&reader
->cs
);
480 WakeAllConditionVariable(&reader
->state_event
);
485 static HRESULT WINAPI
source_reader_source_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
487 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
488 MediaEventType event_type
;
489 IMFMediaSource
*source
;
490 IMFMediaEvent
*event
;
493 TRACE("%p, %p.\n", iface
, result
);
495 source
= (IMFMediaSource
*)IMFAsyncResult_GetStateNoAddRef(result
);
497 if (FAILED(hr
= IMFMediaSource_EndGetEvent(source
, result
, &event
)))
500 IMFMediaEvent_GetType(event
, &event_type
);
502 TRACE("Got event %u.\n", event_type
);
507 hr
= source_reader_new_stream_handler(reader
, event
);
509 case MESourceStarted
:
511 case MESourceStopped
:
513 hr
= source_reader_source_state_handler(reader
, event_type
);
515 case MEBufferingStarted
:
516 case MEBufferingStopped
:
520 case MESourceCharacteristicsChanged
:
521 case MESourceMetadataChanged
:
522 case MEContentProtectionMetadata
:
523 case MEDeviceThermalStateChanged
:
524 if (reader
->async_callback
)
525 IMFSourceReaderCallback_OnEvent(reader
->async_callback
, MF_SOURCE_READER_MEDIASOURCE
, event
);
532 WARN("Failed while handling %d event, hr %#x.\n", event_type
, hr
);
534 IMFMediaEvent_Release(event
);
536 IMFMediaSource_BeginGetEvent(source
, iface
, (IUnknown
*)source
);
541 static const IMFAsyncCallbackVtbl source_events_callback_vtbl
=
543 source_reader_callback_QueryInterface
,
544 source_reader_source_events_callback_AddRef
,
545 source_reader_source_events_callback_Release
,
546 source_reader_callback_GetParameters
,
547 source_reader_source_events_callback_Invoke
,
550 static ULONG WINAPI
source_reader_stream_events_callback_AddRef(IMFAsyncCallback
*iface
)
552 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
553 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
556 static ULONG WINAPI
source_reader_stream_events_callback_Release(IMFAsyncCallback
*iface
)
558 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
559 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
562 static HRESULT
source_reader_pull_stream_samples(struct source_reader
*reader
, struct media_stream
*stream
)
564 MFT_OUTPUT_STREAM_INFO stream_info
= { 0 };
565 MFT_OUTPUT_DATA_BUFFER out_buffer
;
566 IMFMediaBuffer
*buffer
;
571 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(stream
->decoder
, 0, &stream_info
)))
573 WARN("Failed to get output stream info, hr %#x.\n", hr
);
579 memset(&out_buffer
, 0, sizeof(out_buffer
));
581 if (!(stream_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
))
583 if (FAILED(hr
= MFCreateSample(&out_buffer
.pSample
)))
586 if (FAILED(hr
= MFCreateAlignedMemoryBuffer(stream_info
.cbSize
, stream_info
.cbAlignment
, &buffer
)))
588 IMFSample_Release(out_buffer
.pSample
);
592 IMFSample_AddBuffer(out_buffer
.pSample
, buffer
);
593 IMFMediaBuffer_Release(buffer
);
596 if (FAILED(hr
= IMFTransform_ProcessOutput(stream
->decoder
, 0, 1, &out_buffer
, &status
)))
598 if (out_buffer
.pSample
)
599 IMFSample_Release(out_buffer
.pSample
);
604 if (FAILED(IMFSample_GetSampleTime(out_buffer
.pSample
, ×tamp
)))
605 WARN("Sample time wasn't set.\n");
607 source_reader_queue_response(reader
, stream
, S_OK
/* FIXME */, 0, timestamp
, out_buffer
.pSample
);
608 if (out_buffer
.pSample
)
609 IMFSample_Release(out_buffer
.pSample
);
610 if (out_buffer
.pEvents
)
611 IMFCollection_Release(out_buffer
.pEvents
);
617 static HRESULT
source_reader_process_sample(struct source_reader
*reader
, struct media_stream
*stream
,
623 if (!stream
->decoder
)
626 if (FAILED(IMFSample_GetSampleTime(sample
, ×tamp
)))
627 WARN("Sample time wasn't set.\n");
629 source_reader_queue_response(reader
, stream
, S_OK
, 0, timestamp
, sample
);
633 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
635 hr
= source_reader_pull_stream_samples(reader
, stream
);
636 if (hr
== MF_E_TRANSFORM_NEED_MORE_INPUT
)
638 if (FAILED(hr
= IMFTransform_ProcessInput(stream
->decoder
, 0, sample
, 0)))
640 WARN("Transform failed to process input, hr %#x.\n", hr
);
644 if ((hr
= source_reader_pull_stream_samples(reader
, stream
)) == MF_E_TRANSFORM_NEED_MORE_INPUT
)
648 WARN("Transform failed to process output, hr %#x.\n", hr
);
653 static HRESULT
source_reader_media_sample_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
654 IMFMediaEvent
*event
)
661 TRACE("Got new sample for stream %p.\n", stream
);
663 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFSample
, (void **)&sample
)))
665 WARN("Failed to get sample object, hr %#x.\n", hr
);
669 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
671 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
672 IMFSample_Release(sample
);
676 EnterCriticalSection(&reader
->cs
);
678 for (i
= 0; i
< reader
->stream_count
; ++i
)
680 if (id
== reader
->streams
[i
].id
)
682 /* FIXME: propagate processing errors? */
684 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
685 hr
= source_reader_process_sample(reader
, &reader
->streams
[i
], sample
);
686 if (reader
->streams
[i
].requests
)
687 source_reader_request_sample(reader
, &reader
->streams
[i
]);
693 if (i
== reader
->stream_count
)
694 WARN("Stream with id %#x was not present in presentation descriptor.\n", id
);
696 LeaveCriticalSection(&reader
->cs
);
698 IMFSample_Release(sample
);
703 static HRESULT
source_reader_media_stream_state_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
704 IMFMediaEvent
*event
)
706 MediaEventType event_type
;
713 IMFMediaEvent_GetType(event
, &event_type
);
715 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
717 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
721 EnterCriticalSection(&reader
->cs
);
723 for (i
= 0; i
< reader
->stream_count
; ++i
)
725 struct media_stream
*stream
= &reader
->streams
[i
];
727 if (id
== stream
->id
)
732 stream
->state
= STREAM_STATE_EOS
;
733 stream
->flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
735 if (stream
->decoder
&& SUCCEEDED(IMFTransform_ProcessMessage(stream
->decoder
,
736 MFT_MESSAGE_COMMAND_DRAIN
, 0)))
738 if ((hr
= source_reader_pull_stream_samples(reader
, stream
)) != MF_E_TRANSFORM_NEED_MORE_INPUT
)
739 WARN("Failed to pull pending samples, hr %#x.\n", hr
);
742 while (stream
->requests
)
743 source_reader_queue_response(reader
, stream
, S_OK
, MF_SOURCE_READERF_ENDOFSTREAM
, 0, NULL
);
747 case MEStreamStarted
:
748 stream
->state
= STREAM_STATE_READY
;
752 hr
= SUCCEEDED(IMFMediaEvent_GetValue(event
, &value
)) && value
.vt
== VT_I8
? S_OK
: E_UNEXPECTED
;
753 timestamp
= SUCCEEDED(hr
) ? value
.u
.hVal
.QuadPart
: 0;
754 PropVariantClear(&value
);
756 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_STREAMTICK
, timestamp
, NULL
);
767 LeaveCriticalSection(&reader
->cs
);
772 static HRESULT WINAPI
source_reader_stream_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
774 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
775 MediaEventType event_type
;
776 IMFMediaStream
*stream
;
777 IMFMediaEvent
*event
;
780 TRACE("%p, %p.\n", iface
, result
);
782 stream
= (IMFMediaStream
*)IMFAsyncResult_GetStateNoAddRef(result
);
784 if (FAILED(hr
= IMFMediaStream_EndGetEvent(stream
, result
, &event
)))
787 IMFMediaEvent_GetType(event
, &event_type
);
789 TRACE("Got event %u.\n", event_type
);
794 hr
= source_reader_media_sample_handler(reader
, stream
, event
);
797 case MEStreamStarted
:
800 hr
= source_reader_media_stream_state_handler(reader
, stream
, event
);
807 WARN("Failed while handling %d event, hr %#x.\n", event_type
, hr
);
809 IMFMediaEvent_Release(event
);
811 IMFMediaStream_BeginGetEvent(stream
, iface
, (IUnknown
*)stream
);
816 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl
=
818 source_reader_callback_QueryInterface
,
819 source_reader_stream_events_callback_AddRef
,
820 source_reader_stream_events_callback_Release
,
821 source_reader_callback_GetParameters
,
822 source_reader_stream_events_callback_Invoke
,
825 static ULONG WINAPI
source_reader_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
827 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
828 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
831 static ULONG WINAPI
source_reader_async_commands_callback_Release(IMFAsyncCallback
*iface
)
833 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
834 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
837 static struct stream_response
* media_stream_detach_response(struct source_reader
*reader
, struct stream_response
*response
)
839 struct media_stream
*stream
;
841 list_remove(&response
->entry
);
843 if (response
->stream_index
< reader
->stream_count
)
845 stream
= &reader
->streams
[response
->stream_index
];
846 if (stream
->responses
)
853 static struct stream_response
*media_stream_pop_response(struct source_reader
*reader
, struct media_stream
*stream
)
855 struct stream_response
*response
;
860 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
862 if (response
->stream_index
== stream
->index
)
863 return media_stream_detach_response(reader
, response
);
868 if ((head
= list_head(&reader
->responses
)))
869 return media_stream_detach_response(reader
, LIST_ENTRY(head
, struct stream_response
, entry
));
875 static void source_reader_release_response(struct stream_response
*response
)
877 if (response
->sample
)
878 IMFSample_Release(response
->sample
);
882 static HRESULT
source_reader_get_stream_selection(const struct source_reader
*reader
, DWORD index
, BOOL
*selected
)
884 IMFStreamDescriptor
*sd
;
886 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, selected
, &sd
)))
887 return MF_E_INVALIDSTREAMNUMBER
;
888 IMFStreamDescriptor_Release(sd
);
893 static HRESULT
source_reader_start_source(struct source_reader
*reader
)
895 BOOL selected
, selection_changed
= FALSE
;
896 PROPVARIANT position
;
900 for (i
= 0; i
< reader
->stream_count
; ++i
)
902 source_reader_get_stream_selection(reader
, i
, &selected
);
904 reader
->streams
[i
].flags
|= STREAM_FLAG_SELECTED
;
906 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SELECTED
;
909 if (reader
->source_state
== SOURCE_STATE_STARTED
)
911 for (i
= 0; i
< reader
->stream_count
; ++i
)
913 selection_changed
= !!(reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
) ^
914 !!(reader
->streams
[i
].flags
& STREAM_FLAG_PRESENTED
);
915 if (selection_changed
)
920 position
.u
.hVal
.QuadPart
= 0;
921 if (reader
->source_state
!= SOURCE_STATE_STARTED
|| selection_changed
)
923 position
.vt
= reader
->source_state
== SOURCE_STATE_STARTED
? VT_EMPTY
: VT_I8
;
925 /* Update cached stream selection if descriptor was accepted. */
926 if (SUCCEEDED(hr
= IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &GUID_NULL
, &position
)))
928 for (i
= 0; i
< reader
->stream_count
; ++i
)
930 if (reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
)
931 reader
->streams
[i
].flags
|= STREAM_FLAG_PRESENTED
;
939 static BOOL
source_reader_got_response_for_stream(struct source_reader
*reader
, struct media_stream
*stream
)
941 struct stream_response
*response
;
943 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
945 if (response
->stream_index
== stream
->index
)
952 static BOOL
source_reader_get_read_result(struct source_reader
*reader
, struct media_stream
*stream
, DWORD flags
,
953 HRESULT
*status
, DWORD
*stream_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
955 struct stream_response
*response
= NULL
;
956 BOOL request_sample
= FALSE
;
958 if ((response
= media_stream_pop_response(reader
, stream
)))
960 *status
= response
->status
;
961 *stream_index
= stream
->index
;
962 *stream_flags
= response
->stream_flags
;
963 *timestamp
= response
->timestamp
;
964 *sample
= response
->sample
;
966 IMFSample_AddRef(*sample
);
968 source_reader_release_response(response
);
973 *stream_index
= stream
->index
;
977 if (stream
->state
== STREAM_STATE_EOS
)
979 *stream_flags
= MF_SOURCE_READERF_ENDOFSTREAM
;
983 request_sample
= !(flags
& MF_SOURCE_READER_CONTROLF_DRAIN
);
988 return !request_sample
;
991 static HRESULT
source_reader_get_next_selected_stream(struct source_reader
*reader
, unsigned int *stream_index
)
993 unsigned int i
, start_idx
, stop_idx
, first_selected
= ~0u, requests
= ~0u;
994 BOOL selected
, stream_drained
;
996 start_idx
= (reader
->last_read_index
+ 1) % reader
->stream_count
;
997 stop_idx
= reader
->last_read_index
== ~0u ? reader
->stream_count
: reader
->last_read_index
;
999 for (i
= start_idx
; i
< reader
->stream_count
&& i
!= stop_idx
; i
= (i
+ 1) % (reader
->stream_count
+ 1))
1001 stream_drained
= reader
->streams
[i
].state
== STREAM_STATE_EOS
&& !reader
->streams
[i
].responses
;
1002 selected
= SUCCEEDED(source_reader_get_stream_selection(reader
, i
, &selected
)) && selected
;
1006 if (first_selected
== ~0u)
1009 /* Try to balance pending reads. */
1010 if (!stream_drained
&& reader
->streams
[i
].requests
< requests
)
1012 requests
= reader
->streams
[i
].requests
;
1018 /* If all selected streams reached EOS, use first selected. */
1019 if (first_selected
!= ~0u)
1021 if (requests
== ~0u)
1022 *stream_index
= first_selected
;
1023 reader
->last_read_index
= *stream_index
;
1026 return first_selected
== ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED
: S_OK
;
1029 static HRESULT
source_reader_get_stream_read_index(struct source_reader
*reader
, unsigned int index
, unsigned int *stream_index
)
1036 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1037 *stream_index
= reader
->first_video_stream_index
;
1039 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1040 *stream_index
= reader
->first_audio_stream_index
;
1042 case MF_SOURCE_READER_ANY_STREAM
:
1043 return source_reader_get_next_selected_stream(reader
, stream_index
);
1045 *stream_index
= index
;
1048 /* Can't read from deselected streams. */
1049 if (SUCCEEDED(hr
= source_reader_get_stream_selection(reader
, *stream_index
, &selected
)) && !selected
)
1050 hr
= MF_E_INVALIDREQUEST
;
1055 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
)
1057 struct stream_response
*ptr
, *next
;
1059 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &reader
->responses
, struct stream_response
, entry
)
1061 if (stream
&& stream
->index
!= ptr
->stream_index
&&
1062 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_VIDEO_STREAM
&&
1063 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_AUDIO_STREAM
&&
1064 ptr
->stream_index
!= MF_SOURCE_READER_ANY_STREAM
)
1068 media_stream_detach_response(reader
, ptr
);
1069 source_reader_release_response(ptr
);
1073 static void source_reader_flush_stream(struct source_reader
*reader
, DWORD stream_index
)
1075 struct media_stream
*stream
= &reader
->streams
[stream_index
];
1077 source_reader_release_responses(reader
, stream
);
1078 if (stream
->decoder
)
1079 IMFTransform_ProcessMessage(stream
->decoder
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
1080 stream
->requests
= 0;
1083 static HRESULT
source_reader_flush(struct source_reader
*reader
, unsigned int index
)
1085 unsigned int stream_index
;
1088 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1090 for (stream_index
= 0; stream_index
< reader
->stream_count
; ++stream_index
)
1091 source_reader_flush_stream(reader
, stream_index
);
1097 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1098 stream_index
= reader
->first_video_stream_index
;
1100 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1101 stream_index
= reader
->first_audio_stream_index
;
1104 stream_index
= index
;
1107 if (stream_index
< reader
->stream_count
)
1108 source_reader_flush_stream(reader
, stream_index
);
1110 hr
= MF_E_INVALIDSTREAMNUMBER
;
1116 static HRESULT WINAPI
source_reader_async_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1118 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1119 struct media_stream
*stream
, stub_stream
= { .requests
= 1 };
1120 struct source_reader_async_command
*command
;
1121 struct stream_response
*response
;
1122 DWORD stream_index
, stream_flags
;
1123 BOOL report_sample
= FALSE
;
1124 IMFSample
*sample
= NULL
;
1125 LONGLONG timestamp
= 0;
1129 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
1132 command
= impl_from_async_command_IUnknown(state
);
1134 switch (command
->op
)
1136 case SOURCE_READER_ASYNC_READ
:
1137 EnterCriticalSection(&reader
->cs
);
1139 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1141 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, command
->u
.read
.stream_index
, &stream_index
)))
1143 stream
= &reader
->streams
[stream_index
];
1145 if (!(report_sample
= source_reader_get_read_result(reader
, stream
, command
->u
.read
.flags
, &status
,
1146 &stream_index
, &stream_flags
, ×tamp
, &sample
)))
1149 source_reader_request_sample(reader
, stream
);
1150 /* FIXME: set error stream/reader state on request failure */
1155 stub_stream
.index
= command
->u
.read
.stream_index
;
1156 source_reader_queue_response(reader
, &stub_stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
1160 LeaveCriticalSection(&reader
->cs
);
1163 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, status
, stream_index
, stream_flags
,
1167 IMFSample_Release(sample
);
1171 case SOURCE_READER_ASYNC_SEEK
:
1173 EnterCriticalSection(&reader
->cs
);
1174 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &command
->u
.seek
.format
,
1175 &command
->u
.seek
.position
)))
1177 reader
->flags
|= SOURCE_READER_SEEKING
;
1179 LeaveCriticalSection(&reader
->cs
);
1183 case SOURCE_READER_ASYNC_SAMPLE_READY
:
1185 EnterCriticalSection(&reader
->cs
);
1186 response
= media_stream_pop_response(reader
, NULL
);
1187 LeaveCriticalSection(&reader
->cs
);
1191 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, response
->status
, response
->stream_index
,
1192 response
->stream_flags
, response
->timestamp
, response
->sample
);
1193 source_reader_release_response(response
);
1197 case SOURCE_READER_ASYNC_FLUSH
:
1198 EnterCriticalSection(&reader
->cs
);
1199 source_reader_flush(reader
, command
->u
.flush
.stream_index
);
1200 reader
->flags
&= ~SOURCE_READER_FLUSHING
;
1201 LeaveCriticalSection(&reader
->cs
);
1203 IMFSourceReaderCallback_OnFlush(reader
->async_callback
, command
->u
.flush
.stream_index
);
1209 IUnknown_Release(state
);
1214 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl
=
1216 source_reader_callback_QueryInterface
,
1217 source_reader_async_commands_callback_AddRef
,
1218 source_reader_async_commands_callback_Release
,
1219 source_reader_callback_GetParameters
,
1220 source_reader_async_commands_callback_Invoke
,
1223 static HRESULT WINAPI
src_reader_QueryInterface(IMFSourceReader
*iface
, REFIID riid
, void **out
)
1225 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1227 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1229 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
1230 IsEqualGUID(riid
, &IID_IMFSourceReader
))
1232 *out
= &reader
->IMFSourceReader_iface
;
1236 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1238 return E_NOINTERFACE
;
1241 IUnknown_AddRef((IUnknown
*)*out
);
1245 static ULONG WINAPI
src_reader_AddRef(IMFSourceReader
*iface
)
1247 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1248 ULONG refcount
= InterlockedIncrement(&reader
->refcount
);
1250 TRACE("%p, refcount %u.\n", iface
, refcount
);
1255 static ULONG WINAPI
src_reader_Release(IMFSourceReader
*iface
)
1257 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1258 ULONG refcount
= InterlockedDecrement(&reader
->refcount
);
1261 TRACE("%p, refcount %u.\n", iface
, refcount
);
1265 if (reader
->async_callback
)
1266 IMFSourceReaderCallback_Release(reader
->async_callback
);
1267 if (reader
->flags
& SOURCE_READER_SHUTDOWN_ON_RELEASE
)
1268 IMFMediaSource_Shutdown(reader
->source
);
1269 if (reader
->descriptor
)
1270 IMFPresentationDescriptor_Release(reader
->descriptor
);
1271 IMFMediaSource_Release(reader
->source
);
1273 for (i
= 0; i
< reader
->stream_count
; ++i
)
1275 struct media_stream
*stream
= &reader
->streams
[i
];
1278 IMFMediaStream_Release(stream
->stream
);
1279 if (stream
->current
)
1280 IMFMediaType_Release(stream
->current
);
1281 if (stream
->decoder
)
1282 IMFTransform_Release(stream
->decoder
);
1284 source_reader_release_responses(reader
, NULL
);
1285 heap_free(reader
->streams
);
1286 DeleteCriticalSection(&reader
->cs
);
1293 static HRESULT WINAPI
src_reader_GetStreamSelection(IMFSourceReader
*iface
, DWORD index
, BOOL
*selected
)
1295 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1297 TRACE("%p, %#x, %p.\n", iface
, index
, selected
);
1301 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1302 index
= reader
->first_video_stream_index
;
1304 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1305 index
= reader
->first_audio_stream_index
;
1311 return source_reader_get_stream_selection(reader
, index
, selected
);
1314 static HRESULT WINAPI
src_reader_SetStreamSelection(IMFSourceReader
*iface
, DWORD index
, BOOL selection
)
1316 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1318 BOOL selection_changed
= FALSE
, selected
;
1321 TRACE("%p, %#x, %d.\n", iface
, index
, selection
);
1323 selection
= !!selection
;
1325 EnterCriticalSection(&reader
->cs
);
1327 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1329 for (i
= 0; i
< reader
->stream_count
; ++i
)
1331 if (!selection_changed
)
1333 source_reader_get_stream_selection(reader
, i
, &selected
);
1334 selection_changed
= !!(selected
^ selection
);
1338 IMFPresentationDescriptor_SelectStream(reader
->descriptor
, i
);
1340 IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, i
);
1347 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1348 index
= reader
->first_video_stream_index
;
1350 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1351 index
= reader
->first_audio_stream_index
;
1357 source_reader_get_stream_selection(reader
, index
, &selected
);
1358 selection_changed
= !!(selected
^ selection
);
1361 hr
= IMFPresentationDescriptor_SelectStream(reader
->descriptor
, index
);
1363 hr
= IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, index
);
1366 if (selection_changed
)
1367 reader
->last_read_index
= ~0u;
1369 LeaveCriticalSection(&reader
->cs
);
1371 return SUCCEEDED(hr
) ? S_OK
: MF_E_INVALIDSTREAMNUMBER
;
1374 static HRESULT
source_reader_get_native_media_type(struct source_reader
*reader
, DWORD index
, DWORD type_index
,
1375 IMFMediaType
**type
)
1377 IMFMediaTypeHandler
*handler
;
1378 IMFStreamDescriptor
*sd
;
1379 IMFMediaType
*src_type
;
1385 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1386 index
= reader
->first_video_stream_index
;
1388 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1389 index
= reader
->first_audio_stream_index
;
1395 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1396 return MF_E_INVALIDSTREAMNUMBER
;
1398 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
1399 IMFStreamDescriptor_Release(sd
);
1403 if (type_index
== MF_SOURCE_READER_CURRENT_TYPE_INDEX
)
1404 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &src_type
);
1406 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, type_index
, &src_type
);
1407 IMFMediaTypeHandler_Release(handler
);
1411 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
1412 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)*type
);
1413 IMFMediaType_Release(src_type
);
1419 static HRESULT WINAPI
src_reader_GetNativeMediaType(IMFSourceReader
*iface
, DWORD index
, DWORD type_index
,
1420 IMFMediaType
**type
)
1422 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1424 TRACE("%p, %#x, %#x, %p.\n", iface
, index
, type_index
, type
);
1426 return source_reader_get_native_media_type(reader
, index
, type_index
, type
);
1429 static HRESULT WINAPI
src_reader_GetCurrentMediaType(IMFSourceReader
*iface
, DWORD index
, IMFMediaType
**type
)
1431 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1434 TRACE("%p, %#x, %p.\n", iface
, index
, type
);
1438 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1439 index
= reader
->first_video_stream_index
;
1441 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1442 index
= reader
->first_audio_stream_index
;
1448 if (index
>= reader
->stream_count
)
1449 return MF_E_INVALIDSTREAMNUMBER
;
1451 if (FAILED(hr
= MFCreateMediaType(type
)))
1454 EnterCriticalSection(&reader
->cs
);
1456 hr
= IMFMediaType_CopyAllItems(reader
->streams
[index
].current
, (IMFAttributes
*)*type
);
1458 LeaveCriticalSection(&reader
->cs
);
1463 static HRESULT
source_reader_get_source_type_handler(struct source_reader
*reader
, DWORD index
,
1464 IMFMediaTypeHandler
**handler
)
1466 IMFStreamDescriptor
*sd
;
1470 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1473 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, handler
);
1474 IMFStreamDescriptor_Release(sd
);
1479 static HRESULT
source_reader_set_compatible_media_type(struct source_reader
*reader
, DWORD index
, IMFMediaType
*type
)
1481 IMFMediaTypeHandler
*type_handler
;
1482 IMFMediaType
*native_type
;
1483 BOOL type_set
= FALSE
;
1488 if (FAILED(hr
= IMFMediaType_IsEqual(type
, reader
->streams
[index
].current
, &flags
)))
1491 if (!(flags
& MF_MEDIATYPE_EQUAL_MAJOR_TYPES
))
1492 return MF_E_INVALIDMEDIATYPE
;
1494 /* No need for a decoder or type change. */
1495 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_TYPES
)
1498 if (FAILED(hr
= source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1501 while (!type_set
&& IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler
, i
++, &native_type
) == S_OK
)
1503 static const DWORD compare_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_TYPES
;
1505 if (SUCCEEDED(IMFMediaType_IsEqual(native_type
, type
, &flags
)) && (flags
& compare_flags
) == compare_flags
)
1507 if ((type_set
= SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, native_type
))))
1508 IMFMediaType_CopyAllItems(native_type
, (IMFAttributes
*)reader
->streams
[index
].current
);
1511 IMFMediaType_Release(native_type
);
1514 IMFMediaTypeHandler_Release(type_handler
);
1516 return type_set
? S_OK
: S_FALSE
;
1519 static HRESULT
source_reader_configure_decoder(struct source_reader
*reader
, DWORD index
, const CLSID
*clsid
,
1520 IMFMediaType
*input_type
, IMFMediaType
*output_type
)
1522 IMFMediaTypeHandler
*type_handler
;
1523 IMFTransform
*transform
= NULL
;
1524 IMFMediaType
*type
= NULL
;
1529 if (FAILED(hr
= CoCreateInstance(clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTransform
, (void **)&transform
)))
1531 WARN("Failed to create transform object, hr %#x.\n", hr
);
1535 if (FAILED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0)))
1537 WARN("Failed to set decoder input type, hr %#x.\n", hr
);
1538 IMFTransform_Release(transform
);
1542 /* Find the relevant output type. */
1543 while (IMFTransform_GetOutputAvailableType(transform
, 0, i
++, &type
) == S_OK
)
1547 if (SUCCEEDED(IMFMediaType_IsEqual(type
, output_type
, &flags
)))
1549 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_TYPES
)
1551 if (SUCCEEDED(IMFTransform_SetOutputType(transform
, 0, type
, 0)))
1553 if (SUCCEEDED(source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1555 IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, input_type
);
1556 IMFMediaTypeHandler_Release(type_handler
);
1559 if (FAILED(hr
= IMFMediaType_CopyAllItems(type
, (IMFAttributes
*)reader
->streams
[index
].current
)))
1560 WARN("Failed to copy attributes, hr %#x.\n", hr
);
1561 IMFMediaType_Release(type
);
1563 if (reader
->streams
[index
].decoder
)
1564 IMFTransform_Release(reader
->streams
[index
].decoder
);
1566 reader
->streams
[index
].decoder
= transform
;
1573 IMFMediaType_Release(type
);
1576 WARN("Failed to find suitable decoder output type.\n");
1578 IMFTransform_Release(transform
);
1580 return MF_E_TOPO_CODEC_NOT_FOUND
;
1583 static HRESULT
source_reader_create_decoder_for_stream(struct source_reader
*reader
, DWORD index
, IMFMediaType
*output_type
)
1585 MFT_REGISTER_TYPE_INFO in_type
, out_type
;
1586 CLSID
*clsids
, mft_clsid
, category
;
1587 unsigned int i
= 0, count
;
1588 IMFMediaType
*input_type
;
1591 /* TODO: should we check if the source type is compressed? */
1593 if (FAILED(hr
= IMFMediaType_GetMajorType(output_type
, &out_type
.guidMajorType
)))
1596 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
))
1598 category
= MFT_CATEGORY_VIDEO_DECODER
;
1600 else if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1602 category
= MFT_CATEGORY_AUDIO_DECODER
;
1606 WARN("Unhandled major type %s.\n", debugstr_guid(&out_type
.guidMajorType
));
1607 return MF_E_TOPO_CODEC_NOT_FOUND
;
1610 if (FAILED(hr
= IMFMediaType_GetGUID(output_type
, &MF_MT_SUBTYPE
, &out_type
.guidSubtype
)))
1613 in_type
.guidMajorType
= out_type
.guidMajorType
;
1615 while (source_reader_get_native_media_type(reader
, index
, i
++, &input_type
) == S_OK
)
1617 if (SUCCEEDED(IMFMediaType_GetGUID(input_type
, &MF_MT_SUBTYPE
, &in_type
.guidSubtype
)))
1620 if (SUCCEEDED(hr
= MFTEnum(category
, 0, &in_type
, &out_type
, NULL
, &clsids
, &count
)) && count
)
1622 mft_clsid
= clsids
[0];
1623 CoTaskMemFree(clsids
);
1625 /* TODO: Should we iterate over all of them? */
1626 if (SUCCEEDED(source_reader_configure_decoder(reader
, index
, &mft_clsid
, input_type
, output_type
)))
1628 IMFMediaType_Release(input_type
);
1635 IMFMediaType_Release(input_type
);
1638 return MF_E_TOPO_CODEC_NOT_FOUND
;
1641 static HRESULT WINAPI
src_reader_SetCurrentMediaType(IMFSourceReader
*iface
, DWORD index
, DWORD
*reserved
,
1644 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1647 TRACE("%p, %#x, %p, %p.\n", iface
, index
, reserved
, type
);
1651 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1652 index
= reader
->first_video_stream_index
;
1654 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1655 index
= reader
->first_audio_stream_index
;
1661 if (index
>= reader
->stream_count
)
1662 return MF_E_INVALIDSTREAMNUMBER
;
1664 /* FIXME: setting the output type while streaming should trigger a flush */
1666 EnterCriticalSection(&reader
->cs
);
1668 if ((hr
= source_reader_set_compatible_media_type(reader
, index
, type
)) == S_FALSE
)
1669 hr
= source_reader_create_decoder_for_stream(reader
, index
, type
);
1671 LeaveCriticalSection(&reader
->cs
);
1676 static HRESULT WINAPI
src_reader_SetCurrentPosition(IMFSourceReader
*iface
, REFGUID format
, REFPROPVARIANT position
)
1678 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1679 struct source_reader_async_command
*command
;
1680 unsigned int i
, flags
;
1683 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), position
);
1685 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
1688 if (!(flags
& MFMEDIASOURCE_CAN_SEEK
))
1689 return MF_E_INVALIDREQUEST
;
1691 EnterCriticalSection(&reader
->cs
);
1693 /* Check if we got pending requests. */
1694 for (i
= 0; i
< reader
->stream_count
; ++i
)
1696 if (reader
->streams
[i
].requests
)
1698 hr
= MF_E_INVALIDREQUEST
;
1705 if (reader
->async_callback
)
1707 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK
, &command
)))
1709 command
->u
.seek
.format
= *format
;
1710 PropVariantCopy(&command
->u
.seek
.position
, position
);
1712 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED
, &reader
->async_commands_callback
,
1713 &command
->IUnknown_iface
);
1714 IUnknown_Release(&command
->IUnknown_iface
);
1719 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, format
, position
)))
1721 reader
->flags
|= SOURCE_READER_SEEKING
;
1722 while (reader
->flags
& SOURCE_READER_SEEKING
)
1724 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
1730 LeaveCriticalSection(&reader
->cs
);
1735 static HRESULT
source_reader_read_sample(struct source_reader
*reader
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
1736 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1738 unsigned int actual_index_tmp
;
1739 struct media_stream
*stream
;
1740 LONGLONG timestamp_tmp
;
1744 if (!stream_flags
|| !sample
)
1750 timestamp
= ×tamp_tmp
;
1753 actual_index
= &actual_index_tmp
;
1755 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1757 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, index
, &stream_index
)))
1759 *actual_index
= stream_index
;
1761 stream
= &reader
->streams
[stream_index
];
1763 if (!source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
1766 while (!source_reader_got_response_for_stream(reader
, stream
) && stream
->state
!= STREAM_STATE_EOS
)
1769 if (FAILED(hr
= source_reader_request_sample(reader
, stream
)))
1770 WARN("Failed to request a sample, hr %#x.\n", hr
);
1771 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
1773 *stream_flags
= MF_SOURCE_READERF_ERROR
;
1777 SleepConditionVariableCS(&reader
->sample_event
, &reader
->cs
, INFINITE
);
1780 source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
1786 *actual_index
= index
;
1787 *stream_flags
= MF_SOURCE_READERF_ERROR
;
1792 TRACE("Stream %u, got sample %p, flags %#x.\n", *actual_index
, *sample
, *stream_flags
);
1797 static HRESULT
source_reader_read_sample_async(struct source_reader
*reader
, unsigned int index
, unsigned int flags
,
1798 unsigned int *actual_index
, unsigned int *stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1800 struct source_reader_async_command
*command
;
1803 if (actual_index
|| stream_flags
|| timestamp
|| sample
)
1804 return E_INVALIDARG
;
1806 if (reader
->flags
& SOURCE_READER_FLUSHING
)
1807 hr
= MF_E_NOTACCEPTING
;
1810 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_READ
, &command
)))
1812 command
->u
.read
.stream_index
= index
;
1813 command
->u
.read
.flags
= flags
;
1815 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
1816 IUnknown_Release(&command
->IUnknown_iface
);
1823 static HRESULT WINAPI
src_reader_ReadSample(IMFSourceReader
*iface
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
1824 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1826 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1829 TRACE("%p, %#x, %#x, %p, %p, %p, %p\n", iface
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
1831 EnterCriticalSection(&reader
->cs
);
1833 while (reader
->flags
& SOURCE_READER_SEEKING
)
1835 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
1838 if (reader
->async_callback
)
1839 hr
= source_reader_read_sample_async(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
1841 hr
= source_reader_read_sample(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
1843 LeaveCriticalSection(&reader
->cs
);
1848 static HRESULT
source_reader_flush_async(struct source_reader
*reader
, unsigned int index
)
1850 struct source_reader_async_command
*command
;
1851 unsigned int stream_index
;
1854 if (reader
->flags
& SOURCE_READER_FLUSHING
)
1855 return MF_E_INVALIDREQUEST
;
1859 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1860 stream_index
= reader
->first_video_stream_index
;
1862 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1863 stream_index
= reader
->first_audio_stream_index
;
1866 stream_index
= index
;
1869 reader
->flags
|= SOURCE_READER_FLUSHING
;
1871 if (stream_index
!= MF_SOURCE_READER_ALL_STREAMS
&& stream_index
>= reader
->stream_count
)
1872 return MF_E_INVALIDSTREAMNUMBER
;
1874 if (FAILED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH
, &command
)))
1877 command
->u
.flush
.stream_index
= stream_index
;
1879 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
1880 IUnknown_Release(&command
->IUnknown_iface
);
1885 static HRESULT WINAPI
src_reader_Flush(IMFSourceReader
*iface
, DWORD index
)
1887 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1890 TRACE("%p, %#x.\n", iface
, index
);
1892 EnterCriticalSection(&reader
->cs
);
1894 if (reader
->async_callback
)
1895 hr
= source_reader_flush_async(reader
, index
);
1897 hr
= source_reader_flush(reader
, index
);
1899 LeaveCriticalSection(&reader
->cs
);
1904 static HRESULT WINAPI
src_reader_GetServiceForStream(IMFSourceReader
*iface
, DWORD index
, REFGUID service
,
1905 REFIID riid
, void **object
)
1907 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1908 IUnknown
*obj
= NULL
;
1911 TRACE("%p, %#x, %s, %s, %p\n", iface
, index
, debugstr_guid(service
), debugstr_guid(riid
), object
);
1913 EnterCriticalSection(&reader
->cs
);
1917 case MF_SOURCE_READER_MEDIASOURCE
:
1918 obj
= (IUnknown
*)reader
->source
;
1921 if (index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
1922 index
= reader
->first_video_stream_index
;
1923 else if (index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
1924 index
= reader
->first_audio_stream_index
;
1926 if (index
>= reader
->stream_count
)
1927 hr
= MF_E_INVALIDSTREAMNUMBER
;
1930 obj
= (IUnknown
*)reader
->streams
[index
].decoder
;
1931 if (!obj
) hr
= E_NOINTERFACE
;
1937 IUnknown_AddRef(obj
);
1939 LeaveCriticalSection(&reader
->cs
);
1943 if (IsEqualGUID(service
, &GUID_NULL
))
1945 hr
= IUnknown_QueryInterface(obj
, riid
, object
);
1951 hr
= IUnknown_QueryInterface(obj
, &IID_IMFGetService
, (void **)&gs
);
1954 hr
= IMFGetService_GetService(gs
, service
, riid
, object
);
1955 IMFGetService_Release(gs
);
1961 IUnknown_Release(obj
);
1966 static HRESULT WINAPI
src_reader_GetPresentationAttribute(IMFSourceReader
*iface
, DWORD index
,
1967 REFGUID guid
, PROPVARIANT
*value
)
1969 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1970 IMFStreamDescriptor
*sd
;
1974 TRACE("%p, %#x, %s, %p.\n", iface
, index
, debugstr_guid(guid
), value
);
1978 case MF_SOURCE_READER_MEDIASOURCE
:
1979 if (IsEqualGUID(guid
, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS
))
1983 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
1987 value
->u
.ulVal
= flags
;
1992 return IMFPresentationDescriptor_GetItem(reader
->descriptor
, guid
, value
);
1995 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1996 index
= reader
->first_video_stream_index
;
1998 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1999 index
= reader
->first_audio_stream_index
;
2005 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
2008 hr
= IMFStreamDescriptor_GetItem(sd
, guid
, value
);
2009 IMFStreamDescriptor_Release(sd
);
2014 static const IMFSourceReaderVtbl srcreader_vtbl
=
2016 src_reader_QueryInterface
,
2019 src_reader_GetStreamSelection
,
2020 src_reader_SetStreamSelection
,
2021 src_reader_GetNativeMediaType
,
2022 src_reader_GetCurrentMediaType
,
2023 src_reader_SetCurrentMediaType
,
2024 src_reader_SetCurrentPosition
,
2025 src_reader_ReadSample
,
2027 src_reader_GetServiceForStream
,
2028 src_reader_GetPresentationAttribute
2031 static DWORD
reader_get_first_stream_index(IMFPresentationDescriptor
*descriptor
, const GUID
*major
)
2033 unsigned int count
, i
;
2038 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
2039 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2041 for (i
= 0; i
< count
; ++i
)
2043 IMFMediaTypeHandler
*handler
;
2044 IMFStreamDescriptor
*sd
;
2046 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
, &selected
, &sd
)))
2048 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2049 IMFStreamDescriptor_Release(sd
);
2052 hr
= IMFMediaTypeHandler_GetMajorType(handler
, &guid
);
2053 IMFMediaTypeHandler_Release(handler
);
2056 WARN("Failed to get stream major type, hr %#x.\n", hr
);
2060 if (IsEqualGUID(&guid
, major
))
2068 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2071 static HRESULT
create_source_reader_from_source(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2072 BOOL shutdown_on_release
, REFIID riid
, void **out
)
2074 struct source_reader
*object
;
2078 object
= heap_alloc_zero(sizeof(*object
));
2080 return E_OUTOFMEMORY
;
2082 object
->IMFSourceReader_iface
.lpVtbl
= &srcreader_vtbl
;
2083 object
->source_events_callback
.lpVtbl
= &source_events_callback_vtbl
;
2084 object
->stream_events_callback
.lpVtbl
= &stream_events_callback_vtbl
;
2085 object
->async_commands_callback
.lpVtbl
= &async_commands_callback_vtbl
;
2086 object
->refcount
= 1;
2087 list_init(&object
->responses
);
2088 if (shutdown_on_release
)
2089 object
->flags
|= SOURCE_READER_SHUTDOWN_ON_RELEASE
;
2090 object
->source
= source
;
2091 IMFMediaSource_AddRef(object
->source
);
2092 InitializeCriticalSection(&object
->cs
);
2093 InitializeConditionVariable(&object
->sample_event
);
2094 InitializeConditionVariable(&object
->state_event
);
2096 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(object
->source
, &object
->descriptor
)))
2099 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(object
->descriptor
, &object
->stream_count
)))
2102 if (!(object
->streams
= heap_alloc_zero(object
->stream_count
* sizeof(*object
->streams
))))
2108 /* Set initial current media types. */
2109 for (i
= 0; i
< object
->stream_count
; ++i
)
2111 IMFMediaTypeHandler
*handler
;
2112 IMFStreamDescriptor
*sd
;
2113 IMFMediaType
*src_type
;
2116 if (FAILED(hr
= MFCreateMediaType(&object
->streams
[i
].current
)))
2119 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(object
->descriptor
, i
, &selected
, &sd
)))
2122 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &object
->streams
[i
].id
)))
2123 WARN("Failed to get stream identifier, hr %#x.\n", hr
);
2125 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2126 IMFStreamDescriptor_Release(sd
);
2130 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, 0, &src_type
);
2131 IMFMediaTypeHandler_Release(handler
);
2135 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)object
->streams
[i
].current
);
2136 IMFMediaType_Release(src_type
);
2140 object
->streams
[i
].index
= i
;
2146 /* At least one major type has to be set. */
2147 object
->first_audio_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Audio
);
2148 object
->first_video_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Video
);
2149 object
->last_read_index
= ~0u;
2151 if (object
->first_audio_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
&&
2152 object
->first_video_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
)
2154 hr
= MF_E_ATTRIBUTENOTFOUND
;
2157 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(object
->source
, &object
->source_events_callback
,
2158 (IUnknown
*)object
->source
)))
2165 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_ASYNC_CALLBACK
, &IID_IMFSourceReaderCallback
,
2166 (void **)&object
->async_callback
);
2167 if (object
->async_callback
)
2168 TRACE("Using async callback %p.\n", object
->async_callback
);
2171 hr
= IMFSourceReader_QueryInterface(&object
->IMFSourceReader_iface
, riid
, out
);
2174 IMFSourceReader_Release(&object
->IMFSourceReader_iface
);
2178 static HRESULT
bytestream_get_url_hint(IMFByteStream
*stream
, WCHAR
const **url
)
2180 static const unsigned char asfmagic
[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c};
2181 static const unsigned char wavmagic
[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '};
2182 static const unsigned char wavmask
[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
2183 static const unsigned char isommagic
[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00};
2184 static const unsigned char mp42magic
[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00};
2185 static const unsigned char mp4mask
[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00};
2186 static const struct stream_content_url_hint
2188 const unsigned char *magic
;
2190 const unsigned char *mask
;
2194 { asfmagic
, L
".asf" },
2195 { wavmagic
, L
".wav", wavmask
},
2196 { isommagic
, L
".mp4", mp4mask
},
2197 { mp42magic
, L
".mp4", mp4mask
},
2199 unsigned char buffer
[4 * sizeof(unsigned int)], pattern
[4 * sizeof(unsigned int)];
2200 unsigned int i
, j
, length
= 0, caps
= 0;
2201 IMFAttributes
*attributes
;
2207 if (SUCCEEDED(IMFByteStream_QueryInterface(stream
, &IID_IMFAttributes
, (void **)&attributes
)))
2209 IMFAttributes_GetStringLength(attributes
, &MF_BYTESTREAM_CONTENT_TYPE
, &length
);
2210 IMFAttributes_Release(attributes
);
2216 if (FAILED(hr
= IMFByteStream_GetCapabilities(stream
, &caps
)))
2219 if (!(caps
& MFBYTESTREAM_IS_SEEKABLE
))
2222 if (FAILED(hr
= IMFByteStream_GetCurrentPosition(stream
, &position
)))
2225 hr
= IMFByteStream_Read(stream
, buffer
, sizeof(buffer
), &length
);
2226 IMFByteStream_SetCurrentPosition(stream
, position
);
2230 if (length
< sizeof(buffer
))
2233 for (i
= 0; i
< ARRAY_SIZE(url_hints
); ++i
)
2235 memcpy(pattern
, buffer
, sizeof(buffer
));
2236 if (url_hints
[i
].mask
)
2238 unsigned int *mask
= (unsigned int *)url_hints
[i
].mask
;
2239 unsigned int *data
= (unsigned int *)pattern
;
2241 for (j
= 0; j
< sizeof(buffer
) / sizeof(unsigned int); ++j
)
2245 if (!memcmp(pattern
, url_hints
[i
].magic
, sizeof(pattern
)))
2247 *url
= url_hints
[i
].url
;
2253 TRACE("Stream type guessed as %s from %s.\n", debugstr_w(*url
), debugstr_an((char *)buffer
, length
));
2255 WARN("Unrecognized content type %s.\n", debugstr_an((char *)buffer
, length
));
2260 static HRESULT
create_source_reader_from_stream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2261 REFIID riid
, void **out
)
2263 IPropertyStore
*props
= NULL
;
2264 IMFSourceResolver
*resolver
;
2265 MF_OBJECT_TYPE obj_type
;
2266 IMFMediaSource
*source
;
2270 /* If stream does not have content type set, try to guess from starting byte sequence. */
2271 if (FAILED(hr
= bytestream_get_url_hint(stream
, &url
)))
2274 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2278 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2281 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, stream
, url
, MF_RESOLUTION_MEDIASOURCE
, props
,
2282 &obj_type
, (IUnknown
**)&source
);
2283 IMFSourceResolver_Release(resolver
);
2285 IPropertyStore_Release(props
);
2289 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2290 IMFMediaSource_Release(source
);
2294 static HRESULT
create_source_reader_from_url(const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2296 IPropertyStore
*props
= NULL
;
2297 IMFSourceResolver
*resolver
;
2298 IUnknown
*object
= NULL
;
2299 MF_OBJECT_TYPE obj_type
;
2300 IMFMediaSource
*source
;
2303 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2307 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2310 hr
= IMFSourceResolver_CreateObjectFromURL(resolver
, url
, MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
,
2316 case MF_OBJECT_BYTESTREAM
:
2317 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, (IMFByteStream
*)object
, NULL
,
2318 MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
, (IUnknown
**)&source
);
2320 case MF_OBJECT_MEDIASOURCE
:
2321 source
= (IMFMediaSource
*)object
;
2322 IMFMediaSource_AddRef(source
);
2325 WARN("Unknown object type %d.\n", obj_type
);
2328 IUnknown_Release(object
);
2331 IMFSourceResolver_Release(resolver
);
2333 IPropertyStore_Release(props
);
2337 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2338 IMFMediaSource_Release(source
);
2342 static HRESULT
create_source_reader_from_object(IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2344 IMFMediaSource
*source
= NULL
;
2345 IMFByteStream
*stream
= NULL
;
2348 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSource
, (void **)&source
);
2350 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2354 UINT32 disconnect
= 0;
2357 IMFAttributes_GetUINT32(attributes
, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN
, &disconnect
);
2358 hr
= create_source_reader_from_source(source
, attributes
, !disconnect
, riid
, out
);
2361 hr
= create_source_reader_from_stream(stream
, attributes
, riid
, out
);
2364 IMFMediaSource_Release(source
);
2366 IMFByteStream_Release(stream
);
2371 /***********************************************************************
2372 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2374 HRESULT WINAPI
MFCreateSourceReaderFromByteStream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2375 IMFSourceReader
**reader
)
2377 TRACE("%p, %p, %p.\n", stream
, attributes
, reader
);
2379 return create_source_reader_from_object((IUnknown
*)stream
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2382 /***********************************************************************
2383 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2385 HRESULT WINAPI
MFCreateSourceReaderFromMediaSource(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2386 IMFSourceReader
**reader
)
2388 TRACE("%p, %p, %p.\n", source
, attributes
, reader
);
2390 return create_source_reader_from_object((IUnknown
*)source
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2393 /***********************************************************************
2394 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2396 HRESULT WINAPI
MFCreateSourceReaderFromURL(const WCHAR
*url
, IMFAttributes
*attributes
, IMFSourceReader
**reader
)
2398 TRACE("%s, %p, %p.\n", debugstr_w(url
), attributes
, reader
);
2400 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2403 static HRESULT WINAPI
readwrite_factory_QueryInterface(IMFReadWriteClassFactory
*iface
, REFIID riid
, void **out
)
2405 if (IsEqualIID(riid
, &IID_IMFReadWriteClassFactory
) ||
2406 IsEqualIID(riid
, &IID_IUnknown
))
2409 IMFReadWriteClassFactory_AddRef(iface
);
2413 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2415 return E_NOINTERFACE
;
2418 static ULONG WINAPI
readwrite_factory_AddRef(IMFReadWriteClassFactory
*iface
)
2423 static ULONG WINAPI
readwrite_factory_Release(IMFReadWriteClassFactory
*iface
)
2428 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2429 const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2431 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid
), debugstr_w(url
), attributes
, debugstr_guid(riid
), out
);
2433 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2435 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, out
);
2438 FIXME("Unsupported %s.\n", debugstr_guid(clsid
));
2443 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2444 IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2448 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid
), unk
, attributes
, debugstr_guid(riid
), out
);
2450 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2452 return create_source_reader_from_object(unk
, attributes
, riid
, out
);
2454 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2456 IMFByteStream
*stream
= NULL
;
2457 IMFMediaSink
*sink
= NULL
;
2459 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2461 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSink
, (void **)&sink
);
2464 hr
= create_sink_writer_from_stream(stream
, attributes
, riid
, out
);
2466 hr
= create_sink_writer_from_sink(sink
, attributes
, riid
, out
);
2469 IMFMediaSink_Release(sink
);
2471 IMFByteStream_Release(stream
);
2477 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2483 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl
=
2485 readwrite_factory_QueryInterface
,
2486 readwrite_factory_AddRef
,
2487 readwrite_factory_Release
,
2488 readwrite_factory_CreateInstanceFromURL
,
2489 readwrite_factory_CreateInstanceFromObject
,
2492 static IMFReadWriteClassFactory readwrite_factory
= { &readwrite_factory_vtbl
};
2494 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **out
)
2496 TRACE("%s, %p.\n", debugstr_guid(riid
), out
);
2498 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2499 IsEqualGUID(riid
, &IID_IUnknown
))
2501 IClassFactory_AddRef(iface
);
2506 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2508 return E_NOINTERFACE
;
2511 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2516 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2521 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **out
)
2523 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), out
);
2528 return CLASS_E_NOAGGREGATION
;
2530 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory
, riid
, out
);
2533 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2535 FIXME("%d.\n", dolock
);
2539 static const IClassFactoryVtbl classfactoryvtbl
=
2541 classfactory_QueryInterface
,
2542 classfactory_AddRef
,
2543 classfactory_Release
,
2544 classfactory_CreateInstance
,
2545 classfactory_LockServer
,
2548 static IClassFactory classfactory
= { &classfactoryvtbl
};
2550 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
2552 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
2554 if (IsEqualGUID(clsid
, &CLSID_MFReadWriteClassFactory
))
2555 return IClassFactory_QueryInterface(&classfactory
, riid
, out
);
2557 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2559 return CLASS_E_CLASSNOTAVAILABLE
;