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"
40 #include "wine/debug.h"
41 #include "wine/heap.h"
42 #include "wine/list.h"
44 #include "mf_private.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
48 static HINSTANCE mfinstance
;
50 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, LPVOID reserved
)
54 case DLL_PROCESS_ATTACH
:
55 mfinstance
= instance
;
56 DisableThreadLibraryCalls(instance
);
63 HRESULT WINAPI
DllCanUnloadNow(void)
68 HRESULT WINAPI
DllRegisterServer(void)
70 return __wine_register_resources( mfinstance
);
73 HRESULT WINAPI
DllUnregisterServer(void)
75 return __wine_unregister_resources( mfinstance
);
78 struct stream_response
86 unsigned int sa_pending
: 1;
89 enum media_stream_state
91 STREAM_STATE_READY
= 0,
95 enum media_source_state
97 SOURCE_STATE_STOPPED
= 0,
101 enum media_stream_flags
103 STREAM_FLAG_SAMPLE_REQUESTED
= 0x1, /* Protects from making multiple sample requests. */
104 STREAM_FLAG_SELECTED
= 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
105 STREAM_FLAG_PRESENTED
= 0x4, /* Set if stream was selected last time Start() was called. */
108 struct stream_transform
110 IMFTransform
*transform
;
111 unsigned int min_buffer_size
;
116 IMFMediaStream
*stream
;
117 IMFMediaType
*current
;
118 struct stream_transform decoder
;
119 IMFVideoSampleAllocatorEx
*allocator
;
120 IMFVideoSampleAllocatorNotify notify_cb
;
123 enum media_stream_state state
;
125 unsigned int requests
;
126 unsigned int responses
;
127 struct source_reader
*reader
;
130 enum source_reader_async_op
132 SOURCE_READER_ASYNC_READ
,
133 SOURCE_READER_ASYNC_SEEK
,
134 SOURCE_READER_ASYNC_FLUSH
,
135 SOURCE_READER_ASYNC_SAMPLE_READY
,
136 SOURCE_READER_ASYNC_SA_READY
,
139 struct source_reader_async_command
141 IUnknown IUnknown_iface
;
143 enum source_reader_async_op op
;
149 unsigned int stream_index
;
154 PROPVARIANT position
;
158 unsigned int stream_index
;
162 unsigned int stream_index
;
166 unsigned int stream_index
;
171 enum source_reader_flags
173 SOURCE_READER_FLUSHING
= 0x1,
174 SOURCE_READER_SEEKING
= 0x2,
175 SOURCE_READER_SHUTDOWN_ON_RELEASE
= 0x4,
176 SOURCE_READER_D3D9_DEVICE_MANAGER
= 0x8,
177 SOURCE_READER_DXGI_DEVICE_MANAGER
= 0x10,
178 SOURCE_READER_HAS_DEVICE_MANAGER
= SOURCE_READER_D3D9_DEVICE_MANAGER
| SOURCE_READER_DXGI_DEVICE_MANAGER
,
183 IMFSourceReader IMFSourceReader_iface
;
184 IMFAsyncCallback source_events_callback
;
185 IMFAsyncCallback stream_events_callback
;
186 IMFAsyncCallback async_commands_callback
;
188 IMFMediaSource
*source
;
189 IMFPresentationDescriptor
*descriptor
;
190 IMFSourceReaderCallback
*async_callback
;
191 IMFAttributes
*attributes
;
192 IUnknown
*device_manager
;
193 unsigned int first_audio_stream_index
;
194 unsigned int first_video_stream_index
;
195 unsigned int last_read_index
;
196 unsigned int stream_count
;
198 enum media_source_state source_state
;
199 struct media_stream
*streams
;
200 struct list responses
;
202 CONDITION_VARIABLE sample_event
;
203 CONDITION_VARIABLE state_event
;
206 static inline struct source_reader
*impl_from_IMFSourceReader(IMFSourceReader
*iface
)
208 return CONTAINING_RECORD(iface
, struct source_reader
, IMFSourceReader_iface
);
211 static struct source_reader
*impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
213 return CONTAINING_RECORD(iface
, struct source_reader
, source_events_callback
);
216 static struct source_reader
*impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
218 return CONTAINING_RECORD(iface
, struct source_reader
, stream_events_callback
);
221 static struct source_reader
*impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
223 return CONTAINING_RECORD(iface
, struct source_reader
, async_commands_callback
);
226 static struct source_reader_async_command
*impl_from_async_command_IUnknown(IUnknown
*iface
)
228 return CONTAINING_RECORD(iface
, struct source_reader_async_command
, IUnknown_iface
);
231 static struct media_stream
*impl_stream_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify
*iface
)
233 return CONTAINING_RECORD(iface
, struct media_stream
, notify_cb
);
236 static HRESULT WINAPI
source_reader_async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
238 if (IsEqualIID(riid
, &IID_IUnknown
))
241 IUnknown_AddRef(iface
);
245 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
247 return E_NOINTERFACE
;
250 static ULONG WINAPI
source_reader_async_command_AddRef(IUnknown
*iface
)
252 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
253 return InterlockedIncrement(&command
->refcount
);
256 static ULONG WINAPI
source_reader_async_command_Release(IUnknown
*iface
)
258 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
259 ULONG refcount
= InterlockedIncrement(&command
->refcount
);
263 if (command
->op
== SOURCE_READER_ASYNC_SEEK
)
264 PropVariantClear(&command
->u
.seek
.position
);
271 static const IUnknownVtbl source_reader_async_command_vtbl
=
273 source_reader_async_command_QueryInterface
,
274 source_reader_async_command_AddRef
,
275 source_reader_async_command_Release
,
278 static HRESULT
source_reader_create_async_op(enum source_reader_async_op op
, struct source_reader_async_command
**ret
)
280 struct source_reader_async_command
*command
;
282 if (!(command
= heap_alloc_zero(sizeof(*command
))))
283 return E_OUTOFMEMORY
;
285 command
->IUnknown_iface
.lpVtbl
= &source_reader_async_command_vtbl
;
293 static HRESULT
media_event_get_object(IMFMediaEvent
*event
, REFIID riid
, void **obj
)
298 PropVariantInit(&value
);
299 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
301 WARN("Failed to get event value, hr %#x.\n", hr
);
305 if (value
.vt
!= VT_UNKNOWN
|| !value
.punkVal
)
307 WARN("Unexpected value type %d.\n", value
.vt
);
308 PropVariantClear(&value
);
312 hr
= IUnknown_QueryInterface(value
.punkVal
, riid
, obj
);
313 PropVariantClear(&value
);
316 WARN("Unexpected object type.\n");
323 static HRESULT
media_stream_get_id(IMFMediaStream
*stream
, DWORD
*id
)
325 IMFStreamDescriptor
*sd
;
328 if (SUCCEEDED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
330 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, id
);
331 IMFStreamDescriptor_Release(sd
);
337 static HRESULT WINAPI
source_reader_callback_QueryInterface(IMFAsyncCallback
*iface
,
338 REFIID riid
, void **obj
)
340 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
342 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
343 IsEqualIID(riid
, &IID_IUnknown
))
346 IMFAsyncCallback_AddRef(iface
);
350 WARN("Unsupported %s.\n", debugstr_guid(riid
));
352 return E_NOINTERFACE
;
355 static ULONG WINAPI
source_reader_source_events_callback_AddRef(IMFAsyncCallback
*iface
)
357 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
358 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
361 static ULONG WINAPI
source_reader_source_events_callback_Release(IMFAsyncCallback
*iface
)
363 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
364 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
367 static HRESULT WINAPI
source_reader_callback_GetParameters(IMFAsyncCallback
*iface
,
368 DWORD
*flags
, DWORD
*queue
)
373 static void source_reader_response_ready(struct source_reader
*reader
, struct stream_response
*response
)
375 struct source_reader_async_command
*command
;
376 struct media_stream
*stream
= &reader
->streams
[response
->stream_index
];
379 if (!stream
->requests
|| response
->sa_pending
)
382 if (reader
->async_callback
)
384 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY
, &command
)))
386 command
->u
.sample
.stream_index
= stream
->index
;
387 if (FAILED(hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &reader
->async_commands_callback
,
388 &command
->IUnknown_iface
)))
389 WARN("Failed to submit async result, hr %#x.\n", hr
);
390 IUnknown_Release(&command
->IUnknown_iface
);
394 WakeAllConditionVariable(&reader
->sample_event
);
399 static void source_reader_copy_sample_buffer(IMFSample
*src
, IMFSample
*dst
)
401 IMFMediaBuffer
*buffer
;
406 IMFSample_CopyAllItems(src
, (IMFAttributes
*)dst
);
408 IMFSample_SetSampleDuration(dst
, 0);
409 IMFSample_SetSampleTime(dst
, 0);
410 IMFSample_SetSampleFlags(dst
, 0);
412 if (SUCCEEDED(IMFSample_GetSampleDuration(src
, &time
)))
413 IMFSample_SetSampleDuration(dst
, time
);
415 if (SUCCEEDED(IMFSample_GetSampleTime(src
, &time
)))
416 IMFSample_SetSampleTime(dst
, time
);
418 if (SUCCEEDED(IMFSample_GetSampleFlags(src
, &flags
)))
419 IMFSample_SetSampleFlags(dst
, flags
);
421 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src
, NULL
)))
423 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst
, 0, &buffer
)))
425 if (FAILED(hr
= IMFSample_CopyToBuffer(src
, buffer
)))
426 WARN("Failed to copy a buffer, hr %#x.\n", hr
);
427 IMFMediaBuffer_Release(buffer
);
432 static void source_reader_set_sa_response(struct source_reader
*reader
, struct stream_response
*response
)
434 struct media_stream
*stream
= &reader
->streams
[response
->stream_index
];
437 if (SUCCEEDED(IMFVideoSampleAllocatorEx_AllocateSample(stream
->allocator
, &sample
)))
439 source_reader_copy_sample_buffer(response
->sample
, sample
);
440 response
->sa_pending
= 0;
441 IMFSample_Release(response
->sample
);
442 response
->sample
= sample
;
446 static void source_reader_queue_response(struct source_reader
*reader
, struct media_stream
*stream
, HRESULT status
,
447 DWORD stream_flags
, LONGLONG timestamp
, IMFSample
*sample
)
449 struct stream_response
*response
;
451 response
= heap_alloc_zero(sizeof(*response
));
452 response
->status
= status
;
453 response
->stream_index
= stream
->index
;
454 response
->stream_flags
= stream_flags
;
455 response
->timestamp
= timestamp
;
456 response
->sample
= sample
;
457 if (response
->sample
)
458 IMFSample_AddRef(response
->sample
);
460 if (response
->sample
&& stream
->allocator
)
462 response
->sa_pending
= 1;
463 source_reader_set_sa_response(reader
, response
);
466 list_add_tail(&reader
->responses
, &response
->entry
);
469 source_reader_response_ready(reader
, response
);
472 static HRESULT
source_reader_request_sample(struct source_reader
*reader
, struct media_stream
*stream
)
476 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
478 if (FAILED(hr
= IMFMediaStream_RequestSample(stream
->stream
, NULL
)))
479 WARN("Sample request failed, hr %#x.\n", hr
);
482 stream
->flags
|= STREAM_FLAG_SAMPLE_REQUESTED
;
489 static HRESULT
source_reader_new_stream_handler(struct source_reader
*reader
, IMFMediaEvent
*event
)
491 IMFMediaStream
*stream
;
496 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFMediaStream
, (void **)&stream
)))
498 WARN("Failed to get stream object, hr %#x.\n", hr
);
502 TRACE("Got new stream %p.\n", stream
);
504 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
506 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
507 IMFMediaStream_Release(stream
);
511 EnterCriticalSection(&reader
->cs
);
513 for (i
= 0; i
< reader
->stream_count
; ++i
)
515 if (id
== reader
->streams
[i
].id
)
517 if (!reader
->streams
[i
].stream
)
519 reader
->streams
[i
].stream
= stream
;
520 IMFMediaStream_AddRef(reader
->streams
[i
].stream
);
521 if (FAILED(hr
= IMFMediaStream_BeginGetEvent(stream
, &reader
->stream_events_callback
,
522 (IUnknown
*)stream
)))
524 WARN("Failed to subscribe to stream events, hr %#x.\n", hr
);
527 if (reader
->streams
[i
].requests
)
528 if (FAILED(source_reader_request_sample(reader
, &reader
->streams
[i
])))
529 WakeAllConditionVariable(&reader
->sample_event
);
535 if (i
== reader
->stream_count
)
536 WARN("Stream with id %#x was not present in presentation descriptor.\n", id
);
538 LeaveCriticalSection(&reader
->cs
);
540 IMFMediaStream_Release(stream
);
545 static HRESULT
source_reader_source_state_handler(struct source_reader
*reader
, MediaEventType event_type
)
547 EnterCriticalSection(&reader
->cs
);
551 case MESourceStarted
:
552 reader
->source_state
= SOURCE_STATE_STARTED
;
553 reader
->flags
&= ~SOURCE_READER_SEEKING
;
555 case MESourceStopped
:
556 reader
->source_state
= SOURCE_STATE_STOPPED
;
557 reader
->flags
&= ~SOURCE_READER_SEEKING
;
560 reader
->flags
&= ~SOURCE_READER_SEEKING
;
563 WARN("Unhandled event %d.\n", event_type
);
566 LeaveCriticalSection(&reader
->cs
);
568 WakeAllConditionVariable(&reader
->state_event
);
573 static HRESULT WINAPI
source_reader_source_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
575 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
576 MediaEventType event_type
;
577 IMFMediaSource
*source
;
578 IMFMediaEvent
*event
;
581 TRACE("%p, %p.\n", iface
, result
);
583 source
= (IMFMediaSource
*)IMFAsyncResult_GetStateNoAddRef(result
);
585 if (FAILED(hr
= IMFMediaSource_EndGetEvent(source
, result
, &event
)))
588 IMFMediaEvent_GetType(event
, &event_type
);
590 TRACE("Got event %u.\n", event_type
);
595 hr
= source_reader_new_stream_handler(reader
, event
);
597 case MESourceStarted
:
599 case MESourceStopped
:
601 hr
= source_reader_source_state_handler(reader
, event_type
);
603 case MEBufferingStarted
:
604 case MEBufferingStopped
:
608 case MESourceCharacteristicsChanged
:
609 case MESourceMetadataChanged
:
610 case MEContentProtectionMetadata
:
611 case MEDeviceThermalStateChanged
:
612 if (reader
->async_callback
)
613 IMFSourceReaderCallback_OnEvent(reader
->async_callback
, MF_SOURCE_READER_MEDIASOURCE
, event
);
620 WARN("Failed while handling %d event, hr %#x.\n", event_type
, hr
);
622 IMFMediaEvent_Release(event
);
624 IMFMediaSource_BeginGetEvent(source
, iface
, (IUnknown
*)source
);
629 static const IMFAsyncCallbackVtbl source_events_callback_vtbl
=
631 source_reader_callback_QueryInterface
,
632 source_reader_source_events_callback_AddRef
,
633 source_reader_source_events_callback_Release
,
634 source_reader_callback_GetParameters
,
635 source_reader_source_events_callback_Invoke
,
638 static ULONG WINAPI
source_reader_stream_events_callback_AddRef(IMFAsyncCallback
*iface
)
640 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
641 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
644 static ULONG WINAPI
source_reader_stream_events_callback_Release(IMFAsyncCallback
*iface
)
646 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
647 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
650 static HRESULT
source_reader_pull_stream_samples(struct source_reader
*reader
, struct media_stream
*stream
)
652 MFT_OUTPUT_STREAM_INFO stream_info
= { 0 };
653 MFT_OUTPUT_DATA_BUFFER out_buffer
;
654 unsigned int buffer_size
;
655 IMFMediaBuffer
*buffer
;
660 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(stream
->decoder
.transform
, 0, &stream_info
)))
662 WARN("Failed to get output stream info, hr %#x.\n", hr
);
668 memset(&out_buffer
, 0, sizeof(out_buffer
));
670 if (!(stream_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
))
672 if (FAILED(hr
= MFCreateSample(&out_buffer
.pSample
)))
675 buffer_size
= max(stream_info
.cbSize
, stream
->decoder
.min_buffer_size
);
677 if (FAILED(hr
= MFCreateAlignedMemoryBuffer(buffer_size
, stream_info
.cbAlignment
, &buffer
)))
679 IMFSample_Release(out_buffer
.pSample
);
683 IMFSample_AddBuffer(out_buffer
.pSample
, buffer
);
684 IMFMediaBuffer_Release(buffer
);
687 if (FAILED(hr
= IMFTransform_ProcessOutput(stream
->decoder
.transform
, 0, 1, &out_buffer
, &status
)))
689 if (out_buffer
.pSample
)
690 IMFSample_Release(out_buffer
.pSample
);
695 if (FAILED(IMFSample_GetSampleTime(out_buffer
.pSample
, ×tamp
)))
696 WARN("Sample time wasn't set.\n");
698 source_reader_queue_response(reader
, stream
, S_OK
/* FIXME */, 0, timestamp
, out_buffer
.pSample
);
699 if (out_buffer
.pSample
)
700 IMFSample_Release(out_buffer
.pSample
);
701 if (out_buffer
.pEvents
)
702 IMFCollection_Release(out_buffer
.pEvents
);
708 static HRESULT
source_reader_process_sample(struct source_reader
*reader
, struct media_stream
*stream
,
714 if (!stream
->decoder
.transform
)
717 if (FAILED(IMFSample_GetSampleTime(sample
, ×tamp
)))
718 WARN("Sample time wasn't set.\n");
720 source_reader_queue_response(reader
, stream
, S_OK
, 0, timestamp
, sample
);
724 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
726 hr
= source_reader_pull_stream_samples(reader
, stream
);
727 if (hr
== MF_E_TRANSFORM_NEED_MORE_INPUT
)
729 if (FAILED(hr
= IMFTransform_ProcessInput(stream
->decoder
.transform
, 0, sample
, 0)))
731 WARN("Transform failed to process input, hr %#x.\n", hr
);
735 if ((hr
= source_reader_pull_stream_samples(reader
, stream
)) == MF_E_TRANSFORM_NEED_MORE_INPUT
)
739 WARN("Transform failed to process output, hr %#x.\n", hr
);
744 static HRESULT
source_reader_media_sample_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
745 IMFMediaEvent
*event
)
752 TRACE("Got new sample for stream %p.\n", stream
);
754 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFSample
, (void **)&sample
)))
756 WARN("Failed to get sample object, hr %#x.\n", hr
);
760 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
762 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
763 IMFSample_Release(sample
);
767 EnterCriticalSection(&reader
->cs
);
769 for (i
= 0; i
< reader
->stream_count
; ++i
)
771 if (id
== reader
->streams
[i
].id
)
773 /* FIXME: propagate processing errors? */
775 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
776 hr
= source_reader_process_sample(reader
, &reader
->streams
[i
], sample
);
777 if (reader
->streams
[i
].requests
)
778 source_reader_request_sample(reader
, &reader
->streams
[i
]);
784 if (i
== reader
->stream_count
)
785 WARN("Stream with id %#x was not present in presentation descriptor.\n", id
);
787 LeaveCriticalSection(&reader
->cs
);
789 IMFSample_Release(sample
);
794 static HRESULT
source_reader_media_stream_state_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
795 IMFMediaEvent
*event
)
797 MediaEventType event_type
;
804 IMFMediaEvent_GetType(event
, &event_type
);
806 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
808 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
812 EnterCriticalSection(&reader
->cs
);
814 for (i
= 0; i
< reader
->stream_count
; ++i
)
816 struct media_stream
*stream
= &reader
->streams
[i
];
818 if (id
== stream
->id
)
823 stream
->state
= STREAM_STATE_EOS
;
824 stream
->flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
826 if (stream
->decoder
.transform
&& SUCCEEDED(IMFTransform_ProcessMessage(stream
->decoder
.transform
,
827 MFT_MESSAGE_COMMAND_DRAIN
, 0)))
829 if ((hr
= source_reader_pull_stream_samples(reader
, stream
)) != MF_E_TRANSFORM_NEED_MORE_INPUT
)
830 WARN("Failed to pull pending samples, hr %#x.\n", hr
);
833 while (stream
->requests
)
834 source_reader_queue_response(reader
, stream
, S_OK
, MF_SOURCE_READERF_ENDOFSTREAM
, 0, NULL
);
838 case MEStreamStarted
:
839 stream
->state
= STREAM_STATE_READY
;
843 hr
= SUCCEEDED(IMFMediaEvent_GetValue(event
, &value
)) && value
.vt
== VT_I8
? S_OK
: E_UNEXPECTED
;
844 timestamp
= SUCCEEDED(hr
) ? value
.hVal
.QuadPart
: 0;
845 PropVariantClear(&value
);
847 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_STREAMTICK
, timestamp
, NULL
);
858 LeaveCriticalSection(&reader
->cs
);
863 static HRESULT WINAPI
source_reader_stream_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
865 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
866 MediaEventType event_type
;
867 IMFMediaStream
*stream
;
868 IMFMediaEvent
*event
;
871 TRACE("%p, %p.\n", iface
, result
);
873 stream
= (IMFMediaStream
*)IMFAsyncResult_GetStateNoAddRef(result
);
875 if (FAILED(hr
= IMFMediaStream_EndGetEvent(stream
, result
, &event
)))
878 IMFMediaEvent_GetType(event
, &event_type
);
880 TRACE("Got event %u.\n", event_type
);
885 hr
= source_reader_media_sample_handler(reader
, stream
, event
);
888 case MEStreamStarted
:
891 hr
= source_reader_media_stream_state_handler(reader
, stream
, event
);
898 WARN("Failed while handling %d event, hr %#x.\n", event_type
, hr
);
900 IMFMediaEvent_Release(event
);
902 IMFMediaStream_BeginGetEvent(stream
, iface
, (IUnknown
*)stream
);
907 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl
=
909 source_reader_callback_QueryInterface
,
910 source_reader_stream_events_callback_AddRef
,
911 source_reader_stream_events_callback_Release
,
912 source_reader_callback_GetParameters
,
913 source_reader_stream_events_callback_Invoke
,
916 static ULONG WINAPI
source_reader_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
918 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
919 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
922 static ULONG WINAPI
source_reader_async_commands_callback_Release(IMFAsyncCallback
*iface
)
924 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
925 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
928 static struct stream_response
* media_stream_detach_response(struct source_reader
*reader
, struct stream_response
*response
)
930 struct media_stream
*stream
;
932 list_remove(&response
->entry
);
934 if (response
->stream_index
< reader
->stream_count
)
936 stream
= &reader
->streams
[response
->stream_index
];
937 if (stream
->responses
)
944 static struct stream_response
*media_stream_pop_response(struct source_reader
*reader
, struct media_stream
*stream
)
946 struct stream_response
*response
;
948 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
950 if ((stream
&& response
->stream_index
!= stream
->index
) || response
->sa_pending
)
953 return media_stream_detach_response(reader
, response
);
959 static struct stream_response
*media_stream_pick_pending_response(struct source_reader
*reader
, unsigned int stream
)
961 struct stream_response
*response
;
963 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
965 if (response
->stream_index
== stream
&& response
->sa_pending
)
972 static void source_reader_release_response(struct stream_response
*response
)
974 if (response
->sample
)
975 IMFSample_Release(response
->sample
);
979 static HRESULT
source_reader_get_stream_selection(const struct source_reader
*reader
, DWORD index
, BOOL
*selected
)
981 IMFStreamDescriptor
*sd
;
983 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, selected
, &sd
)))
984 return MF_E_INVALIDSTREAMNUMBER
;
985 IMFStreamDescriptor_Release(sd
);
990 static HRESULT
source_reader_start_source(struct source_reader
*reader
)
992 BOOL selected
, selection_changed
= FALSE
;
993 PROPVARIANT position
;
997 for (i
= 0; i
< reader
->stream_count
; ++i
)
999 source_reader_get_stream_selection(reader
, i
, &selected
);
1001 reader
->streams
[i
].flags
|= STREAM_FLAG_SELECTED
;
1003 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SELECTED
;
1006 if (reader
->source_state
== SOURCE_STATE_STARTED
)
1008 for (i
= 0; i
< reader
->stream_count
; ++i
)
1010 selection_changed
= !!(reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
) ^
1011 !!(reader
->streams
[i
].flags
& STREAM_FLAG_PRESENTED
);
1012 if (selection_changed
)
1017 position
.hVal
.QuadPart
= 0;
1018 if (reader
->source_state
!= SOURCE_STATE_STARTED
|| selection_changed
)
1020 position
.vt
= reader
->source_state
== SOURCE_STATE_STARTED
? VT_EMPTY
: VT_I8
;
1022 /* Update cached stream selection if descriptor was accepted. */
1023 if (SUCCEEDED(hr
= IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &GUID_NULL
, &position
)))
1025 for (i
= 0; i
< reader
->stream_count
; ++i
)
1027 if (reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
)
1028 reader
->streams
[i
].flags
|= STREAM_FLAG_PRESENTED
;
1036 static BOOL
source_reader_got_response_for_stream(struct source_reader
*reader
, struct media_stream
*stream
)
1038 struct stream_response
*response
;
1040 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1042 if (response
->stream_index
== stream
->index
&& !response
->sa_pending
)
1049 static BOOL
source_reader_get_read_result(struct source_reader
*reader
, struct media_stream
*stream
, DWORD flags
,
1050 HRESULT
*status
, DWORD
*stream_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1052 struct stream_response
*response
= NULL
;
1053 BOOL request_sample
= FALSE
;
1055 if ((response
= media_stream_pop_response(reader
, stream
)))
1057 *status
= response
->status
;
1058 *stream_index
= stream
->index
;
1059 *stream_flags
= response
->stream_flags
;
1060 *timestamp
= response
->timestamp
;
1061 *sample
= response
->sample
;
1063 IMFSample_AddRef(*sample
);
1065 source_reader_release_response(response
);
1070 *stream_index
= stream
->index
;
1074 if (stream
->state
== STREAM_STATE_EOS
)
1076 *stream_flags
= MF_SOURCE_READERF_ENDOFSTREAM
;
1080 request_sample
= !(flags
& MF_SOURCE_READER_CONTROLF_DRAIN
);
1085 return !request_sample
;
1088 static HRESULT
source_reader_get_next_selected_stream(struct source_reader
*reader
, unsigned int *stream_index
)
1090 unsigned int i
, first_selected
= ~0u, requests
= ~0u;
1091 BOOL selected
, stream_drained
;
1093 for (i
= (reader
->last_read_index
+ 1) % reader
->stream_count
; ; i
= (i
+ 1) % reader
->stream_count
)
1095 stream_drained
= reader
->streams
[i
].state
== STREAM_STATE_EOS
&& !reader
->streams
[i
].responses
;
1096 selected
= SUCCEEDED(source_reader_get_stream_selection(reader
, i
, &selected
)) && selected
;
1100 if (first_selected
== ~0u)
1103 /* Try to balance pending reads. */
1104 if (!stream_drained
&& reader
->streams
[i
].requests
< requests
)
1106 requests
= reader
->streams
[i
].requests
;
1111 if (i
== reader
->last_read_index
)
1115 /* If all selected streams reached EOS, use first selected. */
1116 if (first_selected
!= ~0u)
1118 if (requests
== ~0u)
1119 *stream_index
= first_selected
;
1120 reader
->last_read_index
= *stream_index
;
1123 return first_selected
== ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED
: S_OK
;
1126 static HRESULT
source_reader_get_stream_read_index(struct source_reader
*reader
, unsigned int index
, unsigned int *stream_index
)
1133 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1134 *stream_index
= reader
->first_video_stream_index
;
1136 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1137 *stream_index
= reader
->first_audio_stream_index
;
1139 case MF_SOURCE_READER_ANY_STREAM
:
1140 return source_reader_get_next_selected_stream(reader
, stream_index
);
1142 *stream_index
= index
;
1145 /* Can't read from deselected streams. */
1146 if (SUCCEEDED(hr
= source_reader_get_stream_selection(reader
, *stream_index
, &selected
)) && !selected
)
1147 hr
= MF_E_INVALIDREQUEST
;
1152 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
)
1154 struct stream_response
*ptr
, *next
;
1156 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &reader
->responses
, struct stream_response
, entry
)
1158 if (stream
&& stream
->index
!= ptr
->stream_index
&&
1159 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_VIDEO_STREAM
&&
1160 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_AUDIO_STREAM
&&
1161 ptr
->stream_index
!= MF_SOURCE_READER_ANY_STREAM
)
1165 media_stream_detach_response(reader
, ptr
);
1166 source_reader_release_response(ptr
);
1170 static void source_reader_flush_stream(struct source_reader
*reader
, DWORD stream_index
)
1172 struct media_stream
*stream
= &reader
->streams
[stream_index
];
1174 source_reader_release_responses(reader
, stream
);
1175 if (stream
->decoder
.transform
)
1176 IMFTransform_ProcessMessage(stream
->decoder
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
1177 stream
->requests
= 0;
1180 static HRESULT
source_reader_flush(struct source_reader
*reader
, unsigned int index
)
1182 unsigned int stream_index
;
1185 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1187 for (stream_index
= 0; stream_index
< reader
->stream_count
; ++stream_index
)
1188 source_reader_flush_stream(reader
, stream_index
);
1194 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1195 stream_index
= reader
->first_video_stream_index
;
1197 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1198 stream_index
= reader
->first_audio_stream_index
;
1201 stream_index
= index
;
1204 if (stream_index
< reader
->stream_count
)
1205 source_reader_flush_stream(reader
, stream_index
);
1207 hr
= MF_E_INVALIDSTREAMNUMBER
;
1213 static HRESULT WINAPI
source_reader_async_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1215 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1216 struct media_stream
*stream
, stub_stream
= { .requests
= 1 };
1217 struct source_reader_async_command
*command
;
1218 struct stream_response
*response
;
1219 DWORD stream_index
, stream_flags
;
1220 BOOL report_sample
= FALSE
;
1221 IMFSample
*sample
= NULL
;
1222 LONGLONG timestamp
= 0;
1226 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
1229 command
= impl_from_async_command_IUnknown(state
);
1231 switch (command
->op
)
1233 case SOURCE_READER_ASYNC_READ
:
1234 EnterCriticalSection(&reader
->cs
);
1236 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1238 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, command
->u
.read
.stream_index
, &stream_index
)))
1240 stream
= &reader
->streams
[stream_index
];
1242 if (!(report_sample
= source_reader_get_read_result(reader
, stream
, command
->u
.read
.flags
, &status
,
1243 &stream_index
, &stream_flags
, ×tamp
, &sample
)))
1246 source_reader_request_sample(reader
, stream
);
1247 /* FIXME: set error stream/reader state on request failure */
1252 stub_stream
.index
= command
->u
.read
.stream_index
;
1253 source_reader_queue_response(reader
, &stub_stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
1257 LeaveCriticalSection(&reader
->cs
);
1260 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, status
, stream_index
, stream_flags
,
1264 IMFSample_Release(sample
);
1268 case SOURCE_READER_ASYNC_SEEK
:
1270 EnterCriticalSection(&reader
->cs
);
1271 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &command
->u
.seek
.format
,
1272 &command
->u
.seek
.position
)))
1274 reader
->flags
|= SOURCE_READER_SEEKING
;
1276 LeaveCriticalSection(&reader
->cs
);
1280 case SOURCE_READER_ASYNC_SA_READY
:
1282 EnterCriticalSection(&reader
->cs
);
1283 if ((response
= media_stream_pick_pending_response(reader
, command
->u
.sa
.stream_index
)))
1285 source_reader_set_sa_response(reader
, response
);
1286 source_reader_response_ready(reader
, response
);
1288 LeaveCriticalSection(&reader
->cs
);
1292 case SOURCE_READER_ASYNC_SAMPLE_READY
:
1294 EnterCriticalSection(&reader
->cs
);
1295 response
= media_stream_pop_response(reader
, NULL
);
1296 LeaveCriticalSection(&reader
->cs
);
1300 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, response
->status
, response
->stream_index
,
1301 response
->stream_flags
, response
->timestamp
, response
->sample
);
1302 source_reader_release_response(response
);
1306 case SOURCE_READER_ASYNC_FLUSH
:
1307 EnterCriticalSection(&reader
->cs
);
1308 source_reader_flush(reader
, command
->u
.flush
.stream_index
);
1309 reader
->flags
&= ~SOURCE_READER_FLUSHING
;
1310 LeaveCriticalSection(&reader
->cs
);
1312 IMFSourceReaderCallback_OnFlush(reader
->async_callback
, command
->u
.flush
.stream_index
);
1318 IUnknown_Release(state
);
1323 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl
=
1325 source_reader_callback_QueryInterface
,
1326 source_reader_async_commands_callback_AddRef
,
1327 source_reader_async_commands_callback_Release
,
1328 source_reader_callback_GetParameters
,
1329 source_reader_async_commands_callback_Invoke
,
1332 static HRESULT WINAPI
src_reader_QueryInterface(IMFSourceReader
*iface
, REFIID riid
, void **out
)
1334 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1336 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1338 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
1339 IsEqualGUID(riid
, &IID_IMFSourceReader
))
1341 *out
= &reader
->IMFSourceReader_iface
;
1345 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1347 return E_NOINTERFACE
;
1350 IUnknown_AddRef((IUnknown
*)*out
);
1354 static ULONG WINAPI
src_reader_AddRef(IMFSourceReader
*iface
)
1356 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1357 ULONG refcount
= InterlockedIncrement(&reader
->refcount
);
1359 TRACE("%p, refcount %u.\n", iface
, refcount
);
1364 static ULONG WINAPI
src_reader_Release(IMFSourceReader
*iface
)
1366 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1367 ULONG refcount
= InterlockedDecrement(&reader
->refcount
);
1370 TRACE("%p, refcount %u.\n", iface
, refcount
);
1374 if (reader
->async_callback
)
1375 IMFSourceReaderCallback_Release(reader
->async_callback
);
1376 if (reader
->flags
& SOURCE_READER_SHUTDOWN_ON_RELEASE
)
1377 IMFMediaSource_Shutdown(reader
->source
);
1378 if (reader
->descriptor
)
1379 IMFPresentationDescriptor_Release(reader
->descriptor
);
1380 if (reader
->attributes
)
1381 IMFAttributes_Release(reader
->attributes
);
1382 IMFMediaSource_Release(reader
->source
);
1384 for (i
= 0; i
< reader
->stream_count
; ++i
)
1386 struct media_stream
*stream
= &reader
->streams
[i
];
1389 IMFMediaStream_Release(stream
->stream
);
1390 if (stream
->current
)
1391 IMFMediaType_Release(stream
->current
);
1392 if (stream
->decoder
.transform
)
1393 IMFTransform_Release(stream
->decoder
.transform
);
1394 if (stream
->allocator
)
1395 IMFVideoSampleAllocatorEx_Release(stream
->allocator
);
1397 source_reader_release_responses(reader
, NULL
);
1398 heap_free(reader
->streams
);
1399 DeleteCriticalSection(&reader
->cs
);
1406 static HRESULT WINAPI
src_reader_GetStreamSelection(IMFSourceReader
*iface
, DWORD index
, BOOL
*selected
)
1408 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1410 TRACE("%p, %#x, %p.\n", iface
, index
, selected
);
1414 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1415 index
= reader
->first_video_stream_index
;
1417 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1418 index
= reader
->first_audio_stream_index
;
1424 return source_reader_get_stream_selection(reader
, index
, selected
);
1427 static HRESULT WINAPI
src_reader_SetStreamSelection(IMFSourceReader
*iface
, DWORD index
, BOOL selection
)
1429 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1431 BOOL selection_changed
= FALSE
, selected
;
1434 TRACE("%p, %#x, %d.\n", iface
, index
, selection
);
1436 selection
= !!selection
;
1438 EnterCriticalSection(&reader
->cs
);
1440 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1442 for (i
= 0; i
< reader
->stream_count
; ++i
)
1444 if (!selection_changed
)
1446 source_reader_get_stream_selection(reader
, i
, &selected
);
1447 selection_changed
= !!(selected
^ selection
);
1451 IMFPresentationDescriptor_SelectStream(reader
->descriptor
, i
);
1453 IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, i
);
1460 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1461 index
= reader
->first_video_stream_index
;
1463 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1464 index
= reader
->first_audio_stream_index
;
1470 source_reader_get_stream_selection(reader
, index
, &selected
);
1471 selection_changed
= !!(selected
^ selection
);
1474 hr
= IMFPresentationDescriptor_SelectStream(reader
->descriptor
, index
);
1476 hr
= IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, index
);
1479 if (selection_changed
)
1480 reader
->last_read_index
= reader
->stream_count
- 1;
1482 LeaveCriticalSection(&reader
->cs
);
1484 return SUCCEEDED(hr
) ? S_OK
: MF_E_INVALIDSTREAMNUMBER
;
1487 static HRESULT
source_reader_get_native_media_type(struct source_reader
*reader
, DWORD index
, DWORD type_index
,
1488 IMFMediaType
**type
)
1490 IMFMediaTypeHandler
*handler
;
1491 IMFStreamDescriptor
*sd
;
1492 IMFMediaType
*src_type
;
1498 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1499 index
= reader
->first_video_stream_index
;
1501 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1502 index
= reader
->first_audio_stream_index
;
1508 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1509 return MF_E_INVALIDSTREAMNUMBER
;
1511 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
1512 IMFStreamDescriptor_Release(sd
);
1516 if (type_index
== MF_SOURCE_READER_CURRENT_TYPE_INDEX
)
1517 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &src_type
);
1519 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, type_index
, &src_type
);
1520 IMFMediaTypeHandler_Release(handler
);
1524 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
1525 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)*type
);
1526 IMFMediaType_Release(src_type
);
1532 static HRESULT WINAPI
src_reader_GetNativeMediaType(IMFSourceReader
*iface
, DWORD index
, DWORD type_index
,
1533 IMFMediaType
**type
)
1535 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1537 TRACE("%p, %#x, %#x, %p.\n", iface
, index
, type_index
, type
);
1539 return source_reader_get_native_media_type(reader
, index
, type_index
, type
);
1542 static HRESULT WINAPI
src_reader_GetCurrentMediaType(IMFSourceReader
*iface
, DWORD index
, IMFMediaType
**type
)
1544 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1547 TRACE("%p, %#x, %p.\n", iface
, index
, type
);
1551 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1552 index
= reader
->first_video_stream_index
;
1554 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1555 index
= reader
->first_audio_stream_index
;
1561 if (index
>= reader
->stream_count
)
1562 return MF_E_INVALIDSTREAMNUMBER
;
1564 if (FAILED(hr
= MFCreateMediaType(type
)))
1567 EnterCriticalSection(&reader
->cs
);
1569 hr
= IMFMediaType_CopyAllItems(reader
->streams
[index
].current
, (IMFAttributes
*)*type
);
1571 LeaveCriticalSection(&reader
->cs
);
1576 static HRESULT
source_reader_get_source_type_handler(struct source_reader
*reader
, DWORD index
,
1577 IMFMediaTypeHandler
**handler
)
1579 IMFStreamDescriptor
*sd
;
1583 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1586 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, handler
);
1587 IMFStreamDescriptor_Release(sd
);
1592 static HRESULT
source_reader_set_compatible_media_type(struct source_reader
*reader
, DWORD index
, IMFMediaType
*type
)
1594 IMFMediaTypeHandler
*type_handler
;
1595 IMFMediaType
*native_type
;
1596 BOOL type_set
= FALSE
;
1601 if (FAILED(hr
= IMFMediaType_IsEqual(type
, reader
->streams
[index
].current
, &flags
)))
1604 if (!(flags
& MF_MEDIATYPE_EQUAL_MAJOR_TYPES
))
1605 return MF_E_INVALIDMEDIATYPE
;
1607 /* No need for a decoder or type change. */
1608 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_TYPES
)
1611 if (FAILED(hr
= source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1614 while (!type_set
&& IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler
, i
++, &native_type
) == S_OK
)
1616 static const DWORD compare_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_TYPES
;
1618 if (SUCCEEDED(IMFMediaType_IsEqual(native_type
, type
, &flags
)) && (flags
& compare_flags
) == compare_flags
)
1620 if ((type_set
= SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, native_type
))))
1621 IMFMediaType_CopyAllItems(native_type
, (IMFAttributes
*)reader
->streams
[index
].current
);
1624 IMFMediaType_Release(native_type
);
1627 IMFMediaTypeHandler_Release(type_handler
);
1629 return type_set
? S_OK
: S_FALSE
;
1632 static HRESULT
source_reader_setup_sample_allocator(struct source_reader
*reader
, unsigned int index
)
1634 struct media_stream
*stream
= &reader
->streams
[index
];
1635 IMFVideoSampleAllocatorCallback
*callback
;
1639 IMFMediaType_GetMajorType(stream
->current
, &major
);
1640 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
1643 if (!(reader
->flags
& SOURCE_READER_HAS_DEVICE_MANAGER
))
1646 if (!stream
->allocator
)
1648 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&stream
->allocator
)))
1650 WARN("Failed to create sample allocator, hr %#x.\n", hr
);
1655 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream
->allocator
);
1656 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(stream
->allocator
, reader
->device_manager
)))
1658 WARN("Failed to set device manager, hr %#x.\n", hr
);
1662 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream
->allocator
, 2, 8, NULL
, stream
->current
)))
1663 WARN("Failed to initialize sample allocator, hr %#x.\n", hr
);
1665 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream
->allocator
, &IID_IMFVideoSampleAllocatorCallback
, (void **)&callback
)))
1667 if (FAILED(hr
= IMFVideoSampleAllocatorCallback_SetCallback(callback
, &stream
->notify_cb
)))
1668 WARN("Failed to set allocator callback, hr %#x.\n", hr
);
1669 IMFVideoSampleAllocatorCallback_Release(callback
);
1675 static HRESULT
source_reader_configure_decoder(struct source_reader
*reader
, DWORD index
, const CLSID
*clsid
,
1676 IMFMediaType
*input_type
, IMFMediaType
*output_type
)
1678 IMFMediaTypeHandler
*type_handler
;
1679 unsigned int block_alignment
= 0;
1680 IMFTransform
*transform
= NULL
;
1681 IMFMediaType
*type
= NULL
;
1687 if (FAILED(hr
= CoCreateInstance(clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTransform
, (void **)&transform
)))
1689 WARN("Failed to create transform object, hr %#x.\n", hr
);
1693 if (FAILED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0)))
1695 WARN("Failed to set decoder input type, hr %#x.\n", hr
);
1696 IMFTransform_Release(transform
);
1700 /* Find the relevant output type. */
1701 while (IMFTransform_GetOutputAvailableType(transform
, 0, i
++, &type
) == S_OK
)
1705 if (SUCCEEDED(IMFMediaType_IsEqual(type
, output_type
, &flags
)))
1707 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_TYPES
)
1709 if (SUCCEEDED(IMFTransform_SetOutputType(transform
, 0, type
, 0)))
1711 if (SUCCEEDED(source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1713 IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, input_type
);
1714 IMFMediaTypeHandler_Release(type_handler
);
1717 if (FAILED(hr
= IMFMediaType_CopyAllItems(type
, (IMFAttributes
*)reader
->streams
[index
].current
)))
1718 WARN("Failed to copy attributes, hr %#x.\n", hr
);
1719 if (SUCCEEDED(IMFMediaType_GetMajorType(type
, &major
)) && IsEqualGUID(&major
, &MFMediaType_Audio
))
1720 IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
);
1721 IMFMediaType_Release(type
);
1723 if (reader
->streams
[index
].decoder
.transform
)
1724 IMFTransform_Release(reader
->streams
[index
].decoder
.transform
);
1726 reader
->streams
[index
].decoder
.transform
= transform
;
1727 reader
->streams
[index
].decoder
.min_buffer_size
= block_alignment
;
1734 IMFMediaType_Release(type
);
1737 WARN("Failed to find suitable decoder output type.\n");
1739 IMFTransform_Release(transform
);
1741 return MF_E_TOPO_CODEC_NOT_FOUND
;
1744 static HRESULT
source_reader_create_decoder_for_stream(struct source_reader
*reader
, DWORD index
, IMFMediaType
*output_type
)
1746 MFT_REGISTER_TYPE_INFO in_type
, out_type
;
1747 CLSID
*clsids
, mft_clsid
, category
;
1748 unsigned int i
= 0, count
;
1749 IMFMediaType
*input_type
;
1752 /* TODO: should we check if the source type is compressed? */
1754 if (FAILED(hr
= IMFMediaType_GetMajorType(output_type
, &out_type
.guidMajorType
)))
1757 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
))
1759 category
= MFT_CATEGORY_VIDEO_DECODER
;
1761 else if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1763 category
= MFT_CATEGORY_AUDIO_DECODER
;
1767 WARN("Unhandled major type %s.\n", debugstr_guid(&out_type
.guidMajorType
));
1768 return MF_E_TOPO_CODEC_NOT_FOUND
;
1771 if (FAILED(hr
= IMFMediaType_GetGUID(output_type
, &MF_MT_SUBTYPE
, &out_type
.guidSubtype
)))
1774 in_type
.guidMajorType
= out_type
.guidMajorType
;
1776 while (source_reader_get_native_media_type(reader
, index
, i
++, &input_type
) == S_OK
)
1778 if (SUCCEEDED(IMFMediaType_GetGUID(input_type
, &MF_MT_SUBTYPE
, &in_type
.guidSubtype
)))
1781 if (SUCCEEDED(hr
= MFTEnum(category
, 0, &in_type
, &out_type
, NULL
, &clsids
, &count
)) && count
)
1783 mft_clsid
= clsids
[0];
1784 CoTaskMemFree(clsids
);
1786 /* TODO: Should we iterate over all of them? */
1787 if (SUCCEEDED(source_reader_configure_decoder(reader
, index
, &mft_clsid
, input_type
, output_type
)))
1789 IMFMediaType_Release(input_type
);
1796 IMFMediaType_Release(input_type
);
1799 return MF_E_TOPO_CODEC_NOT_FOUND
;
1802 static HRESULT WINAPI
src_reader_SetCurrentMediaType(IMFSourceReader
*iface
, DWORD index
, DWORD
*reserved
,
1805 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1808 TRACE("%p, %#x, %p, %p.\n", iface
, index
, reserved
, type
);
1812 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1813 index
= reader
->first_video_stream_index
;
1815 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1816 index
= reader
->first_audio_stream_index
;
1822 if (index
>= reader
->stream_count
)
1823 return MF_E_INVALIDSTREAMNUMBER
;
1825 /* FIXME: setting the output type while streaming should trigger a flush */
1827 EnterCriticalSection(&reader
->cs
);
1829 hr
= source_reader_set_compatible_media_type(reader
, index
, type
);
1831 hr
= source_reader_create_decoder_for_stream(reader
, index
, type
);
1833 hr
= source_reader_setup_sample_allocator(reader
, index
);
1835 LeaveCriticalSection(&reader
->cs
);
1840 static HRESULT WINAPI
src_reader_SetCurrentPosition(IMFSourceReader
*iface
, REFGUID format
, REFPROPVARIANT position
)
1842 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1843 struct source_reader_async_command
*command
;
1844 unsigned int i
, flags
;
1847 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), position
);
1849 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
1852 if (!(flags
& MFMEDIASOURCE_CAN_SEEK
))
1853 return MF_E_INVALIDREQUEST
;
1855 EnterCriticalSection(&reader
->cs
);
1857 /* Check if we got pending requests. */
1858 for (i
= 0; i
< reader
->stream_count
; ++i
)
1860 if (reader
->streams
[i
].requests
)
1862 hr
= MF_E_INVALIDREQUEST
;
1869 if (reader
->async_callback
)
1871 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK
, &command
)))
1873 command
->u
.seek
.format
= *format
;
1874 PropVariantCopy(&command
->u
.seek
.position
, position
);
1876 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED
, &reader
->async_commands_callback
,
1877 &command
->IUnknown_iface
);
1878 IUnknown_Release(&command
->IUnknown_iface
);
1883 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, format
, position
)))
1885 reader
->flags
|= SOURCE_READER_SEEKING
;
1886 while (reader
->flags
& SOURCE_READER_SEEKING
)
1888 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
1894 LeaveCriticalSection(&reader
->cs
);
1899 static HRESULT
source_reader_read_sample(struct source_reader
*reader
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
1900 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1902 unsigned int actual_index_tmp
;
1903 struct media_stream
*stream
;
1904 LONGLONG timestamp_tmp
;
1908 if (!stream_flags
|| !sample
)
1914 timestamp
= ×tamp_tmp
;
1917 actual_index
= &actual_index_tmp
;
1919 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1921 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, index
, &stream_index
)))
1923 *actual_index
= stream_index
;
1925 stream
= &reader
->streams
[stream_index
];
1927 if (!source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
1930 while (!source_reader_got_response_for_stream(reader
, stream
) && stream
->state
!= STREAM_STATE_EOS
)
1933 if (FAILED(hr
= source_reader_request_sample(reader
, stream
)))
1934 WARN("Failed to request a sample, hr %#x.\n", hr
);
1935 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
1937 *stream_flags
= MF_SOURCE_READERF_ERROR
;
1941 SleepConditionVariableCS(&reader
->sample_event
, &reader
->cs
, INFINITE
);
1944 source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
1950 *actual_index
= index
;
1951 *stream_flags
= MF_SOURCE_READERF_ERROR
;
1956 TRACE("Stream %u, got sample %p, flags %#x.\n", *actual_index
, *sample
, *stream_flags
);
1961 static HRESULT
source_reader_read_sample_async(struct source_reader
*reader
, unsigned int index
, unsigned int flags
,
1962 unsigned int *actual_index
, unsigned int *stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1964 struct source_reader_async_command
*command
;
1967 if (actual_index
|| stream_flags
|| timestamp
|| sample
)
1968 return E_INVALIDARG
;
1970 if (reader
->flags
& SOURCE_READER_FLUSHING
)
1971 hr
= MF_E_NOTACCEPTING
;
1974 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_READ
, &command
)))
1976 command
->u
.read
.stream_index
= index
;
1977 command
->u
.read
.flags
= flags
;
1979 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
1980 IUnknown_Release(&command
->IUnknown_iface
);
1987 static HRESULT WINAPI
src_reader_ReadSample(IMFSourceReader
*iface
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
1988 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1990 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1993 TRACE("%p, %#x, %#x, %p, %p, %p, %p\n", iface
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
1995 EnterCriticalSection(&reader
->cs
);
1997 while (reader
->flags
& SOURCE_READER_SEEKING
)
1999 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2002 if (reader
->async_callback
)
2003 hr
= source_reader_read_sample_async(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2005 hr
= source_reader_read_sample(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2007 LeaveCriticalSection(&reader
->cs
);
2012 static HRESULT
source_reader_flush_async(struct source_reader
*reader
, unsigned int index
)
2014 struct source_reader_async_command
*command
;
2015 unsigned int stream_index
;
2018 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2019 return MF_E_INVALIDREQUEST
;
2023 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2024 stream_index
= reader
->first_video_stream_index
;
2026 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2027 stream_index
= reader
->first_audio_stream_index
;
2030 stream_index
= index
;
2033 reader
->flags
|= SOURCE_READER_FLUSHING
;
2035 if (stream_index
!= MF_SOURCE_READER_ALL_STREAMS
&& stream_index
>= reader
->stream_count
)
2036 return MF_E_INVALIDSTREAMNUMBER
;
2038 if (FAILED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH
, &command
)))
2041 command
->u
.flush
.stream_index
= stream_index
;
2043 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2044 IUnknown_Release(&command
->IUnknown_iface
);
2049 static HRESULT WINAPI
src_reader_Flush(IMFSourceReader
*iface
, DWORD index
)
2051 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
2054 TRACE("%p, %#x.\n", iface
, index
);
2056 EnterCriticalSection(&reader
->cs
);
2058 if (reader
->async_callback
)
2059 hr
= source_reader_flush_async(reader
, index
);
2061 hr
= source_reader_flush(reader
, index
);
2063 LeaveCriticalSection(&reader
->cs
);
2068 static HRESULT WINAPI
src_reader_GetServiceForStream(IMFSourceReader
*iface
, DWORD index
, REFGUID service
,
2069 REFIID riid
, void **object
)
2071 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
2072 IUnknown
*obj
= NULL
;
2075 TRACE("%p, %#x, %s, %s, %p\n", iface
, index
, debugstr_guid(service
), debugstr_guid(riid
), object
);
2077 EnterCriticalSection(&reader
->cs
);
2081 case MF_SOURCE_READER_MEDIASOURCE
:
2082 obj
= (IUnknown
*)reader
->source
;
2085 if (index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2086 index
= reader
->first_video_stream_index
;
2087 else if (index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2088 index
= reader
->first_audio_stream_index
;
2090 if (index
>= reader
->stream_count
)
2091 hr
= MF_E_INVALIDSTREAMNUMBER
;
2094 obj
= (IUnknown
*)reader
->streams
[index
].decoder
.transform
;
2095 if (!obj
) hr
= E_NOINTERFACE
;
2101 IUnknown_AddRef(obj
);
2103 LeaveCriticalSection(&reader
->cs
);
2107 if (IsEqualGUID(service
, &GUID_NULL
))
2109 hr
= IUnknown_QueryInterface(obj
, riid
, object
);
2115 hr
= IUnknown_QueryInterface(obj
, &IID_IMFGetService
, (void **)&gs
);
2118 hr
= IMFGetService_GetService(gs
, service
, riid
, object
);
2119 IMFGetService_Release(gs
);
2125 IUnknown_Release(obj
);
2130 static HRESULT WINAPI
src_reader_GetPresentationAttribute(IMFSourceReader
*iface
, DWORD index
,
2131 REFGUID guid
, PROPVARIANT
*value
)
2133 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
2134 IMFStreamDescriptor
*sd
;
2138 TRACE("%p, %#x, %s, %p.\n", iface
, index
, debugstr_guid(guid
), value
);
2142 case MF_SOURCE_READER_MEDIASOURCE
:
2143 if (IsEqualGUID(guid
, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS
))
2147 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2151 value
->ulVal
= flags
;
2156 return IMFPresentationDescriptor_GetItem(reader
->descriptor
, guid
, value
);
2159 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2160 index
= reader
->first_video_stream_index
;
2162 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2163 index
= reader
->first_audio_stream_index
;
2169 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
2172 hr
= IMFStreamDescriptor_GetItem(sd
, guid
, value
);
2173 IMFStreamDescriptor_Release(sd
);
2178 static const IMFSourceReaderVtbl srcreader_vtbl
=
2180 src_reader_QueryInterface
,
2183 src_reader_GetStreamSelection
,
2184 src_reader_SetStreamSelection
,
2185 src_reader_GetNativeMediaType
,
2186 src_reader_GetCurrentMediaType
,
2187 src_reader_SetCurrentMediaType
,
2188 src_reader_SetCurrentPosition
,
2189 src_reader_ReadSample
,
2191 src_reader_GetServiceForStream
,
2192 src_reader_GetPresentationAttribute
2195 static DWORD
reader_get_first_stream_index(IMFPresentationDescriptor
*descriptor
, const GUID
*major
)
2197 unsigned int count
, i
;
2202 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
2203 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2205 for (i
= 0; i
< count
; ++i
)
2207 IMFMediaTypeHandler
*handler
;
2208 IMFStreamDescriptor
*sd
;
2210 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
, &selected
, &sd
)))
2212 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2213 IMFStreamDescriptor_Release(sd
);
2216 hr
= IMFMediaTypeHandler_GetMajorType(handler
, &guid
);
2217 IMFMediaTypeHandler_Release(handler
);
2220 WARN("Failed to get stream major type, hr %#x.\n", hr
);
2224 if (IsEqualGUID(&guid
, major
))
2232 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2235 static HRESULT WINAPI
stream_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify
*iface
,
2236 REFIID riid
, void **obj
)
2238 if (IsEqualIID(riid
, &IID_IMFVideoSampleAllocatorNotify
) ||
2239 IsEqualIID(riid
, &IID_IUnknown
))
2242 IMFVideoSampleAllocatorNotify_AddRef(iface
);
2247 return E_NOINTERFACE
;
2250 static ULONG WINAPI
stream_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify
*iface
)
2255 static ULONG WINAPI
stream_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify
*iface
)
2260 static HRESULT WINAPI
stream_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify
*iface
)
2262 struct media_stream
*stream
= impl_stream_from_IMFVideoSampleAllocatorNotify(iface
);
2263 struct source_reader_async_command
*command
;
2265 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SA_READY
, &command
)))
2267 command
->u
.sa
.stream_index
= stream
->index
;
2268 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &stream
->reader
->async_commands_callback
, &command
->IUnknown_iface
);
2269 IUnknown_Release(&command
->IUnknown_iface
);
2275 static const IMFVideoSampleAllocatorNotifyVtbl stream_sample_allocator_cb_vtbl
=
2277 stream_sample_allocator_cb_QueryInterface
,
2278 stream_sample_allocator_cb_AddRef
,
2279 stream_sample_allocator_cb_Release
,
2280 stream_sample_allocator_cb_NotifyRelease
,
2283 static HRESULT
create_source_reader_from_source(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2284 BOOL shutdown_on_release
, REFIID riid
, void **out
)
2286 struct source_reader
*object
;
2290 object
= heap_alloc_zero(sizeof(*object
));
2292 return E_OUTOFMEMORY
;
2294 object
->IMFSourceReader_iface
.lpVtbl
= &srcreader_vtbl
;
2295 object
->source_events_callback
.lpVtbl
= &source_events_callback_vtbl
;
2296 object
->stream_events_callback
.lpVtbl
= &stream_events_callback_vtbl
;
2297 object
->async_commands_callback
.lpVtbl
= &async_commands_callback_vtbl
;
2298 object
->refcount
= 1;
2299 list_init(&object
->responses
);
2300 if (shutdown_on_release
)
2301 object
->flags
|= SOURCE_READER_SHUTDOWN_ON_RELEASE
;
2302 object
->source
= source
;
2303 IMFMediaSource_AddRef(object
->source
);
2304 InitializeCriticalSection(&object
->cs
);
2305 InitializeConditionVariable(&object
->sample_event
);
2306 InitializeConditionVariable(&object
->state_event
);
2308 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(object
->source
, &object
->descriptor
)))
2311 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(object
->descriptor
, &object
->stream_count
)))
2314 if (!(object
->streams
= heap_alloc_zero(object
->stream_count
* sizeof(*object
->streams
))))
2320 /* Set initial current media types. */
2321 for (i
= 0; i
< object
->stream_count
; ++i
)
2323 IMFMediaTypeHandler
*handler
;
2324 IMFStreamDescriptor
*sd
;
2325 IMFMediaType
*src_type
;
2328 if (FAILED(hr
= MFCreateMediaType(&object
->streams
[i
].current
)))
2331 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(object
->descriptor
, i
, &selected
, &sd
)))
2334 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &object
->streams
[i
].id
)))
2335 WARN("Failed to get stream identifier, hr %#x.\n", hr
);
2337 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2338 IMFStreamDescriptor_Release(sd
);
2342 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, 0, &src_type
);
2343 IMFMediaTypeHandler_Release(handler
);
2347 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)object
->streams
[i
].current
);
2348 IMFMediaType_Release(src_type
);
2352 object
->streams
[i
].notify_cb
.lpVtbl
= &stream_sample_allocator_cb_vtbl
;
2353 object
->streams
[i
].reader
= object
;
2354 object
->streams
[i
].index
= i
;
2360 /* At least one major type has to be set. */
2361 object
->first_audio_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Audio
);
2362 object
->first_video_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Video
);
2363 object
->last_read_index
= object
->stream_count
- 1;
2365 if (object
->first_audio_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
&&
2366 object
->first_video_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
)
2368 hr
= MF_E_ATTRIBUTENOTFOUND
;
2371 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(object
->source
, &object
->source_events_callback
,
2372 (IUnknown
*)object
->source
)))
2379 object
->attributes
= attributes
;
2380 IMFAttributes_AddRef(object
->attributes
);
2382 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_ASYNC_CALLBACK
, &IID_IMFSourceReaderCallback
,
2383 (void **)&object
->async_callback
);
2384 if (object
->async_callback
)
2385 TRACE("Using async callback %p.\n", object
->async_callback
);
2387 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_D3D_MANAGER
, &IID_IUnknown
, (void **)&object
->device_manager
);
2388 if (object
->device_manager
)
2390 IUnknown
*unk
= NULL
;
2392 if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IMFDXGIDeviceManager
, (void **)&unk
)))
2393 object
->flags
|= SOURCE_READER_DXGI_DEVICE_MANAGER
;
2394 else if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IDirect3DDeviceManager9
, (void **)&unk
)))
2395 object
->flags
|= SOURCE_READER_D3D9_DEVICE_MANAGER
;
2397 if (!(object
->flags
& (SOURCE_READER_HAS_DEVICE_MANAGER
)))
2399 WARN("Unknown device manager.\n");
2400 IUnknown_Release(object
->device_manager
);
2401 object
->device_manager
= NULL
;
2405 IUnknown_Release(unk
);
2409 hr
= IMFSourceReader_QueryInterface(&object
->IMFSourceReader_iface
, riid
, out
);
2412 IMFSourceReader_Release(&object
->IMFSourceReader_iface
);
2416 static HRESULT
bytestream_get_url_hint(IMFByteStream
*stream
, WCHAR
const **url
)
2418 static const unsigned char asfmagic
[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c};
2419 static const unsigned char wavmagic
[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '};
2420 static const unsigned char wavmask
[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
2421 static const unsigned char isommagic
[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00};
2422 static const unsigned char mp42magic
[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00};
2423 static const unsigned char mp4mask
[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00};
2424 static const struct stream_content_url_hint
2426 const unsigned char *magic
;
2428 const unsigned char *mask
;
2432 { asfmagic
, L
".asf" },
2433 { wavmagic
, L
".wav", wavmask
},
2434 { isommagic
, L
".mp4", mp4mask
},
2435 { mp42magic
, L
".mp4", mp4mask
},
2437 unsigned char buffer
[4 * sizeof(unsigned int)], pattern
[4 * sizeof(unsigned int)];
2438 unsigned int i
, j
, length
= 0, caps
= 0;
2439 IMFAttributes
*attributes
;
2445 if (SUCCEEDED(IMFByteStream_QueryInterface(stream
, &IID_IMFAttributes
, (void **)&attributes
)))
2447 IMFAttributes_GetStringLength(attributes
, &MF_BYTESTREAM_CONTENT_TYPE
, &length
);
2448 IMFAttributes_Release(attributes
);
2454 if (FAILED(hr
= IMFByteStream_GetCapabilities(stream
, &caps
)))
2457 if (!(caps
& MFBYTESTREAM_IS_SEEKABLE
))
2460 if (FAILED(hr
= IMFByteStream_GetCurrentPosition(stream
, &position
)))
2463 hr
= IMFByteStream_Read(stream
, buffer
, sizeof(buffer
), &length
);
2464 IMFByteStream_SetCurrentPosition(stream
, position
);
2468 if (length
< sizeof(buffer
))
2471 for (i
= 0; i
< ARRAY_SIZE(url_hints
); ++i
)
2473 memcpy(pattern
, buffer
, sizeof(buffer
));
2474 if (url_hints
[i
].mask
)
2476 unsigned int *mask
= (unsigned int *)url_hints
[i
].mask
;
2477 unsigned int *data
= (unsigned int *)pattern
;
2479 for (j
= 0; j
< sizeof(buffer
) / sizeof(unsigned int); ++j
)
2483 if (!memcmp(pattern
, url_hints
[i
].magic
, sizeof(pattern
)))
2485 *url
= url_hints
[i
].url
;
2491 TRACE("Stream type guessed as %s from %s.\n", debugstr_w(*url
), debugstr_an((char *)buffer
, length
));
2493 WARN("Unrecognized content type %s.\n", debugstr_an((char *)buffer
, length
));
2498 static HRESULT
create_source_reader_from_stream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2499 REFIID riid
, void **out
)
2501 IPropertyStore
*props
= NULL
;
2502 IMFSourceResolver
*resolver
;
2503 MF_OBJECT_TYPE obj_type
;
2504 IMFMediaSource
*source
;
2508 /* If stream does not have content type set, try to guess from starting byte sequence. */
2509 if (FAILED(hr
= bytestream_get_url_hint(stream
, &url
)))
2512 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2516 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2519 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, stream
, url
, MF_RESOLUTION_MEDIASOURCE
, props
,
2520 &obj_type
, (IUnknown
**)&source
);
2521 IMFSourceResolver_Release(resolver
);
2523 IPropertyStore_Release(props
);
2527 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2528 IMFMediaSource_Release(source
);
2532 static HRESULT
create_source_reader_from_url(const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2534 IPropertyStore
*props
= NULL
;
2535 IMFSourceResolver
*resolver
;
2536 IUnknown
*object
= NULL
;
2537 MF_OBJECT_TYPE obj_type
;
2538 IMFMediaSource
*source
;
2541 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2545 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2548 hr
= IMFSourceResolver_CreateObjectFromURL(resolver
, url
, MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
,
2554 case MF_OBJECT_BYTESTREAM
:
2555 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, (IMFByteStream
*)object
, NULL
,
2556 MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
, (IUnknown
**)&source
);
2558 case MF_OBJECT_MEDIASOURCE
:
2559 source
= (IMFMediaSource
*)object
;
2560 IMFMediaSource_AddRef(source
);
2563 WARN("Unknown object type %d.\n", obj_type
);
2566 IUnknown_Release(object
);
2569 IMFSourceResolver_Release(resolver
);
2571 IPropertyStore_Release(props
);
2575 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2576 IMFMediaSource_Release(source
);
2580 static HRESULT
create_source_reader_from_object(IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2582 IMFMediaSource
*source
= NULL
;
2583 IMFByteStream
*stream
= NULL
;
2586 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSource
, (void **)&source
);
2588 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2592 UINT32 disconnect
= 0;
2595 IMFAttributes_GetUINT32(attributes
, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN
, &disconnect
);
2596 hr
= create_source_reader_from_source(source
, attributes
, !disconnect
, riid
, out
);
2599 hr
= create_source_reader_from_stream(stream
, attributes
, riid
, out
);
2602 IMFMediaSource_Release(source
);
2604 IMFByteStream_Release(stream
);
2609 /***********************************************************************
2610 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2612 HRESULT WINAPI
MFCreateSourceReaderFromByteStream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2613 IMFSourceReader
**reader
)
2615 TRACE("%p, %p, %p.\n", stream
, attributes
, reader
);
2617 return create_source_reader_from_object((IUnknown
*)stream
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2620 /***********************************************************************
2621 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2623 HRESULT WINAPI
MFCreateSourceReaderFromMediaSource(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2624 IMFSourceReader
**reader
)
2626 TRACE("%p, %p, %p.\n", source
, attributes
, reader
);
2628 return create_source_reader_from_object((IUnknown
*)source
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2631 /***********************************************************************
2632 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2634 HRESULT WINAPI
MFCreateSourceReaderFromURL(const WCHAR
*url
, IMFAttributes
*attributes
, IMFSourceReader
**reader
)
2636 TRACE("%s, %p, %p.\n", debugstr_w(url
), attributes
, reader
);
2638 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2641 static HRESULT WINAPI
readwrite_factory_QueryInterface(IMFReadWriteClassFactory
*iface
, REFIID riid
, void **out
)
2643 if (IsEqualIID(riid
, &IID_IMFReadWriteClassFactory
) ||
2644 IsEqualIID(riid
, &IID_IUnknown
))
2647 IMFReadWriteClassFactory_AddRef(iface
);
2651 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2653 return E_NOINTERFACE
;
2656 static ULONG WINAPI
readwrite_factory_AddRef(IMFReadWriteClassFactory
*iface
)
2661 static ULONG WINAPI
readwrite_factory_Release(IMFReadWriteClassFactory
*iface
)
2666 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2667 const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2669 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid
), debugstr_w(url
), attributes
, debugstr_guid(riid
), out
);
2671 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2673 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, out
);
2676 FIXME("Unsupported %s.\n", debugstr_guid(clsid
));
2681 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2682 IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2686 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid
), unk
, attributes
, debugstr_guid(riid
), out
);
2688 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2690 return create_source_reader_from_object(unk
, attributes
, riid
, out
);
2692 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2694 IMFByteStream
*stream
= NULL
;
2695 IMFMediaSink
*sink
= NULL
;
2697 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2699 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSink
, (void **)&sink
);
2702 hr
= create_sink_writer_from_stream(stream
, attributes
, riid
, out
);
2704 hr
= create_sink_writer_from_sink(sink
, attributes
, riid
, out
);
2707 IMFMediaSink_Release(sink
);
2709 IMFByteStream_Release(stream
);
2715 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2721 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl
=
2723 readwrite_factory_QueryInterface
,
2724 readwrite_factory_AddRef
,
2725 readwrite_factory_Release
,
2726 readwrite_factory_CreateInstanceFromURL
,
2727 readwrite_factory_CreateInstanceFromObject
,
2730 static IMFReadWriteClassFactory readwrite_factory
= { &readwrite_factory_vtbl
};
2732 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **out
)
2734 TRACE("%s, %p.\n", debugstr_guid(riid
), out
);
2736 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2737 IsEqualGUID(riid
, &IID_IUnknown
))
2739 IClassFactory_AddRef(iface
);
2744 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2746 return E_NOINTERFACE
;
2749 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2754 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2759 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **out
)
2761 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), out
);
2766 return CLASS_E_NOAGGREGATION
;
2768 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory
, riid
, out
);
2771 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2773 FIXME("%d.\n", dolock
);
2777 static const IClassFactoryVtbl classfactoryvtbl
=
2779 classfactory_QueryInterface
,
2780 classfactory_AddRef
,
2781 classfactory_Release
,
2782 classfactory_CreateInstance
,
2783 classfactory_LockServer
,
2786 static IClassFactory classfactory
= { &classfactoryvtbl
};
2788 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
2790 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
2792 if (IsEqualGUID(clsid
, &CLSID_MFReadWriteClassFactory
))
2793 return IClassFactory_QueryInterface(&classfactory
, riid
, out
);
2795 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2797 return CLASS_E_CLASSNOTAVAILABLE
;