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/list.h"
43 #include "mf_private.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
47 struct stream_response
55 unsigned int sa_pending
: 1;
58 enum media_stream_state
60 STREAM_STATE_READY
= 0,
64 enum media_source_state
66 SOURCE_STATE_STOPPED
= 0,
70 enum media_stream_flags
72 STREAM_FLAG_SAMPLE_REQUESTED
= 0x1, /* Protects from making multiple sample requests. */
73 STREAM_FLAG_SELECTED
= 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
74 STREAM_FLAG_PRESENTED
= 0x4, /* Set if stream was selected last time Start() was called. */
77 struct stream_transform
79 IMFTransform
*transform
;
80 unsigned int min_buffer_size
;
85 IMFMediaStream
*stream
;
86 IMFMediaType
*current
;
87 struct stream_transform decoder
;
88 IMFVideoSampleAllocatorEx
*allocator
;
89 IMFVideoSampleAllocatorNotify notify_cb
;
92 enum media_stream_state state
;
94 unsigned int requests
;
95 unsigned int responses
;
96 struct source_reader
*reader
;
99 enum source_reader_async_op
101 SOURCE_READER_ASYNC_READ
,
102 SOURCE_READER_ASYNC_SEEK
,
103 SOURCE_READER_ASYNC_FLUSH
,
104 SOURCE_READER_ASYNC_SAMPLE_READY
,
105 SOURCE_READER_ASYNC_SA_READY
,
108 struct source_reader_async_command
110 IUnknown IUnknown_iface
;
112 enum source_reader_async_op op
;
118 unsigned int stream_index
;
123 PROPVARIANT position
;
127 unsigned int stream_index
;
131 unsigned int stream_index
;
135 unsigned int stream_index
;
140 enum source_reader_flags
142 SOURCE_READER_FLUSHING
= 0x1,
143 SOURCE_READER_SEEKING
= 0x2,
144 SOURCE_READER_SHUTDOWN_ON_RELEASE
= 0x4,
145 SOURCE_READER_D3D9_DEVICE_MANAGER
= 0x8,
146 SOURCE_READER_DXGI_DEVICE_MANAGER
= 0x10,
147 SOURCE_READER_HAS_DEVICE_MANAGER
= SOURCE_READER_D3D9_DEVICE_MANAGER
| SOURCE_READER_DXGI_DEVICE_MANAGER
,
152 IMFSourceReader IMFSourceReader_iface
;
153 IMFAsyncCallback source_events_callback
;
154 IMFAsyncCallback stream_events_callback
;
155 IMFAsyncCallback async_commands_callback
;
157 IMFMediaSource
*source
;
158 IMFPresentationDescriptor
*descriptor
;
159 IMFSourceReaderCallback
*async_callback
;
160 IMFAttributes
*attributes
;
161 IUnknown
*device_manager
;
162 unsigned int first_audio_stream_index
;
163 unsigned int first_video_stream_index
;
164 unsigned int last_read_index
;
165 unsigned int stream_count
;
168 enum media_source_state source_state
;
169 struct media_stream
*streams
;
170 struct list responses
;
172 CONDITION_VARIABLE sample_event
;
173 CONDITION_VARIABLE state_event
;
176 static inline struct source_reader
*impl_from_IMFSourceReader(IMFSourceReader
*iface
)
178 return CONTAINING_RECORD(iface
, struct source_reader
, IMFSourceReader_iface
);
181 static struct source_reader
*impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
183 return CONTAINING_RECORD(iface
, struct source_reader
, source_events_callback
);
186 static struct source_reader
*impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
188 return CONTAINING_RECORD(iface
, struct source_reader
, stream_events_callback
);
191 static struct source_reader
*impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
193 return CONTAINING_RECORD(iface
, struct source_reader
, async_commands_callback
);
196 static struct source_reader_async_command
*impl_from_async_command_IUnknown(IUnknown
*iface
)
198 return CONTAINING_RECORD(iface
, struct source_reader_async_command
, IUnknown_iface
);
201 static struct media_stream
*impl_stream_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify
*iface
)
203 return CONTAINING_RECORD(iface
, struct media_stream
, notify_cb
);
206 static HRESULT WINAPI
source_reader_async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
208 if (IsEqualIID(riid
, &IID_IUnknown
))
211 IUnknown_AddRef(iface
);
215 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
217 return E_NOINTERFACE
;
220 static ULONG WINAPI
source_reader_async_command_AddRef(IUnknown
*iface
)
222 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
223 return InterlockedIncrement(&command
->refcount
);
226 static ULONG WINAPI
source_reader_async_command_Release(IUnknown
*iface
)
228 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
229 ULONG refcount
= InterlockedIncrement(&command
->refcount
);
233 if (command
->op
== SOURCE_READER_ASYNC_SEEK
)
234 PropVariantClear(&command
->u
.seek
.position
);
241 static const IUnknownVtbl source_reader_async_command_vtbl
=
243 source_reader_async_command_QueryInterface
,
244 source_reader_async_command_AddRef
,
245 source_reader_async_command_Release
,
248 static HRESULT
source_reader_create_async_op(enum source_reader_async_op op
, struct source_reader_async_command
**ret
)
250 struct source_reader_async_command
*command
;
252 if (!(command
= calloc(1, sizeof(*command
))))
253 return E_OUTOFMEMORY
;
255 command
->IUnknown_iface
.lpVtbl
= &source_reader_async_command_vtbl
;
263 static HRESULT
media_event_get_object(IMFMediaEvent
*event
, REFIID riid
, void **obj
)
268 PropVariantInit(&value
);
269 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
271 WARN("Failed to get event value, hr %#x.\n", hr
);
275 if (value
.vt
!= VT_UNKNOWN
|| !value
.punkVal
)
277 WARN("Unexpected value type %d.\n", value
.vt
);
278 PropVariantClear(&value
);
282 hr
= IUnknown_QueryInterface(value
.punkVal
, riid
, obj
);
283 PropVariantClear(&value
);
286 WARN("Unexpected object type.\n");
293 static HRESULT
media_stream_get_id(IMFMediaStream
*stream
, DWORD
*id
)
295 IMFStreamDescriptor
*sd
;
298 if (SUCCEEDED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
300 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, id
);
301 IMFStreamDescriptor_Release(sd
);
307 static HRESULT WINAPI
source_reader_callback_QueryInterface(IMFAsyncCallback
*iface
,
308 REFIID riid
, void **obj
)
310 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
312 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
313 IsEqualIID(riid
, &IID_IUnknown
))
316 IMFAsyncCallback_AddRef(iface
);
320 WARN("Unsupported %s.\n", debugstr_guid(riid
));
322 return E_NOINTERFACE
;
325 static ULONG WINAPI
source_reader_source_events_callback_AddRef(IMFAsyncCallback
*iface
)
327 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
328 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
331 static ULONG WINAPI
source_reader_source_events_callback_Release(IMFAsyncCallback
*iface
)
333 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
334 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
337 static HRESULT WINAPI
source_reader_callback_GetParameters(IMFAsyncCallback
*iface
,
338 DWORD
*flags
, DWORD
*queue
)
343 static void source_reader_response_ready(struct source_reader
*reader
, struct stream_response
*response
)
345 struct source_reader_async_command
*command
;
346 struct media_stream
*stream
= &reader
->streams
[response
->stream_index
];
349 if (!stream
->requests
|| response
->sa_pending
)
352 if (reader
->async_callback
)
354 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY
, &command
)))
356 command
->u
.sample
.stream_index
= stream
->index
;
357 if (FAILED(hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
)))
358 WARN("Failed to submit async result, hr %#x.\n", hr
);
359 IUnknown_Release(&command
->IUnknown_iface
);
363 WakeAllConditionVariable(&reader
->sample_event
);
368 static void source_reader_copy_sample_buffer(IMFSample
*src
, IMFSample
*dst
)
370 IMFMediaBuffer
*buffer
;
375 IMFSample_CopyAllItems(src
, (IMFAttributes
*)dst
);
377 IMFSample_SetSampleDuration(dst
, 0);
378 IMFSample_SetSampleTime(dst
, 0);
379 IMFSample_SetSampleFlags(dst
, 0);
381 if (SUCCEEDED(IMFSample_GetSampleDuration(src
, &time
)))
382 IMFSample_SetSampleDuration(dst
, time
);
384 if (SUCCEEDED(IMFSample_GetSampleTime(src
, &time
)))
385 IMFSample_SetSampleTime(dst
, time
);
387 if (SUCCEEDED(IMFSample_GetSampleFlags(src
, &flags
)))
388 IMFSample_SetSampleFlags(dst
, flags
);
390 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src
, NULL
)))
392 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst
, 0, &buffer
)))
394 if (FAILED(hr
= IMFSample_CopyToBuffer(src
, buffer
)))
395 WARN("Failed to copy a buffer, hr %#x.\n", hr
);
396 IMFMediaBuffer_Release(buffer
);
401 static void source_reader_set_sa_response(struct source_reader
*reader
, struct stream_response
*response
)
403 struct media_stream
*stream
= &reader
->streams
[response
->stream_index
];
406 if (SUCCEEDED(IMFVideoSampleAllocatorEx_AllocateSample(stream
->allocator
, &sample
)))
408 source_reader_copy_sample_buffer(response
->sample
, sample
);
409 response
->sa_pending
= 0;
410 IMFSample_Release(response
->sample
);
411 response
->sample
= sample
;
415 static HRESULT
source_reader_queue_response(struct source_reader
*reader
, struct media_stream
*stream
, HRESULT status
,
416 DWORD stream_flags
, LONGLONG timestamp
, IMFSample
*sample
)
418 struct stream_response
*response
;
420 if (!(response
= calloc(1, sizeof(*response
))))
421 return E_OUTOFMEMORY
;
423 response
->status
= status
;
424 response
->stream_index
= stream
->index
;
425 response
->stream_flags
= stream_flags
;
426 response
->timestamp
= timestamp
;
427 response
->sample
= sample
;
428 if (response
->sample
)
429 IMFSample_AddRef(response
->sample
);
431 if (response
->sample
&& stream
->allocator
)
433 response
->sa_pending
= 1;
434 source_reader_set_sa_response(reader
, response
);
437 list_add_tail(&reader
->responses
, &response
->entry
);
440 source_reader_response_ready(reader
, response
);
445 static HRESULT
source_reader_request_sample(struct source_reader
*reader
, struct media_stream
*stream
)
449 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
451 if (FAILED(hr
= IMFMediaStream_RequestSample(stream
->stream
, NULL
)))
452 WARN("Sample request failed, hr %#x.\n", hr
);
455 stream
->flags
|= STREAM_FLAG_SAMPLE_REQUESTED
;
462 static HRESULT
source_reader_new_stream_handler(struct source_reader
*reader
, IMFMediaEvent
*event
)
464 IMFMediaStream
*stream
;
469 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFMediaStream
, (void **)&stream
)))
471 WARN("Failed to get stream object, hr %#x.\n", hr
);
475 TRACE("Got new stream %p.\n", stream
);
477 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
479 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
480 IMFMediaStream_Release(stream
);
484 EnterCriticalSection(&reader
->cs
);
486 for (i
= 0; i
< reader
->stream_count
; ++i
)
488 if (id
== reader
->streams
[i
].id
)
490 if (!reader
->streams
[i
].stream
)
492 reader
->streams
[i
].stream
= stream
;
493 IMFMediaStream_AddRef(reader
->streams
[i
].stream
);
494 if (FAILED(hr
= IMFMediaStream_BeginGetEvent(stream
, &reader
->stream_events_callback
,
495 (IUnknown
*)stream
)))
497 WARN("Failed to subscribe to stream events, hr %#x.\n", hr
);
500 if (reader
->streams
[i
].requests
)
501 if (FAILED(source_reader_request_sample(reader
, &reader
->streams
[i
])))
502 WakeAllConditionVariable(&reader
->sample_event
);
508 if (i
== reader
->stream_count
)
509 WARN("Stream with id %#x was not present in presentation descriptor.\n", id
);
511 LeaveCriticalSection(&reader
->cs
);
513 IMFMediaStream_Release(stream
);
518 static HRESULT
source_reader_source_state_handler(struct source_reader
*reader
, MediaEventType event_type
)
520 EnterCriticalSection(&reader
->cs
);
524 case MESourceStarted
:
525 reader
->source_state
= SOURCE_STATE_STARTED
;
526 reader
->flags
&= ~SOURCE_READER_SEEKING
;
528 case MESourceStopped
:
529 reader
->source_state
= SOURCE_STATE_STOPPED
;
530 reader
->flags
&= ~SOURCE_READER_SEEKING
;
533 reader
->flags
&= ~SOURCE_READER_SEEKING
;
536 WARN("Unhandled event %d.\n", event_type
);
539 LeaveCriticalSection(&reader
->cs
);
541 WakeAllConditionVariable(&reader
->state_event
);
546 static HRESULT WINAPI
source_reader_source_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
548 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
549 MediaEventType event_type
;
550 IMFMediaSource
*source
;
551 IMFMediaEvent
*event
;
554 TRACE("%p, %p.\n", iface
, result
);
556 source
= (IMFMediaSource
*)IMFAsyncResult_GetStateNoAddRef(result
);
558 if (FAILED(hr
= IMFMediaSource_EndGetEvent(source
, result
, &event
)))
561 IMFMediaEvent_GetType(event
, &event_type
);
563 TRACE("Got event %u.\n", event_type
);
568 hr
= source_reader_new_stream_handler(reader
, event
);
570 case MESourceStarted
:
572 case MESourceStopped
:
574 hr
= source_reader_source_state_handler(reader
, event_type
);
576 case MEBufferingStarted
:
577 case MEBufferingStopped
:
581 case MESourceCharacteristicsChanged
:
582 case MESourceMetadataChanged
:
583 case MEContentProtectionMetadata
:
584 case MEDeviceThermalStateChanged
:
585 if (reader
->async_callback
)
586 IMFSourceReaderCallback_OnEvent(reader
->async_callback
, MF_SOURCE_READER_MEDIASOURCE
, event
);
593 WARN("Failed while handling %d event, hr %#x.\n", event_type
, hr
);
595 IMFMediaEvent_Release(event
);
597 IMFMediaSource_BeginGetEvent(source
, iface
, (IUnknown
*)source
);
602 static const IMFAsyncCallbackVtbl source_events_callback_vtbl
=
604 source_reader_callback_QueryInterface
,
605 source_reader_source_events_callback_AddRef
,
606 source_reader_source_events_callback_Release
,
607 source_reader_callback_GetParameters
,
608 source_reader_source_events_callback_Invoke
,
611 static ULONG WINAPI
source_reader_stream_events_callback_AddRef(IMFAsyncCallback
*iface
)
613 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
614 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
617 static ULONG WINAPI
source_reader_stream_events_callback_Release(IMFAsyncCallback
*iface
)
619 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
620 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
623 static HRESULT
source_reader_pull_stream_samples(struct source_reader
*reader
, struct media_stream
*stream
)
625 MFT_OUTPUT_STREAM_INFO stream_info
= { 0 };
626 MFT_OUTPUT_DATA_BUFFER out_buffer
;
627 unsigned int buffer_size
;
628 IMFMediaBuffer
*buffer
;
633 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(stream
->decoder
.transform
, 0, &stream_info
)))
635 WARN("Failed to get output stream info, hr %#x.\n", hr
);
641 memset(&out_buffer
, 0, sizeof(out_buffer
));
643 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
)))
645 if (FAILED(hr
= MFCreateSample(&out_buffer
.pSample
)))
648 buffer_size
= max(stream_info
.cbSize
, stream
->decoder
.min_buffer_size
);
650 if (FAILED(hr
= MFCreateAlignedMemoryBuffer(buffer_size
, stream_info
.cbAlignment
, &buffer
)))
652 IMFSample_Release(out_buffer
.pSample
);
656 IMFSample_AddBuffer(out_buffer
.pSample
, buffer
);
657 IMFMediaBuffer_Release(buffer
);
660 if (FAILED(hr
= IMFTransform_ProcessOutput(stream
->decoder
.transform
, 0, 1, &out_buffer
, &status
)))
662 if (out_buffer
.pSample
)
663 IMFSample_Release(out_buffer
.pSample
);
668 if (FAILED(IMFSample_GetSampleTime(out_buffer
.pSample
, ×tamp
)))
669 WARN("Sample time wasn't set.\n");
671 source_reader_queue_response(reader
, stream
, S_OK
/* FIXME */, 0, timestamp
, out_buffer
.pSample
);
672 if (out_buffer
.pSample
)
673 IMFSample_Release(out_buffer
.pSample
);
674 if (out_buffer
.pEvents
)
675 IMFCollection_Release(out_buffer
.pEvents
);
681 static HRESULT
source_reader_process_sample(struct source_reader
*reader
, struct media_stream
*stream
,
687 if (!stream
->decoder
.transform
)
690 if (FAILED(IMFSample_GetSampleTime(sample
, ×tamp
)))
691 WARN("Sample time wasn't set.\n");
693 return source_reader_queue_response(reader
, stream
, S_OK
, 0, timestamp
, sample
);
696 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
698 hr
= source_reader_pull_stream_samples(reader
, stream
);
699 if (hr
== MF_E_TRANSFORM_NEED_MORE_INPUT
)
701 if (FAILED(hr
= IMFTransform_ProcessInput(stream
->decoder
.transform
, 0, sample
, 0)))
703 WARN("Transform failed to process input, hr %#x.\n", hr
);
707 if ((hr
= source_reader_pull_stream_samples(reader
, stream
)) == MF_E_TRANSFORM_NEED_MORE_INPUT
)
711 WARN("Transform failed to process output, hr %#x.\n", hr
);
716 static HRESULT
source_reader_media_sample_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
717 IMFMediaEvent
*event
)
724 TRACE("Got new sample for stream %p.\n", stream
);
726 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFSample
, (void **)&sample
)))
728 WARN("Failed to get sample object, hr %#x.\n", hr
);
732 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
734 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
735 IMFSample_Release(sample
);
739 EnterCriticalSection(&reader
->cs
);
741 for (i
= 0; i
< reader
->stream_count
; ++i
)
743 if (id
== reader
->streams
[i
].id
)
745 /* FIXME: propagate processing errors? */
747 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
748 hr
= source_reader_process_sample(reader
, &reader
->streams
[i
], sample
);
749 if (reader
->streams
[i
].requests
)
750 source_reader_request_sample(reader
, &reader
->streams
[i
]);
756 if (i
== reader
->stream_count
)
757 WARN("Stream with id %#x was not present in presentation descriptor.\n", id
);
759 LeaveCriticalSection(&reader
->cs
);
761 IMFSample_Release(sample
);
766 static HRESULT
source_reader_media_stream_state_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
767 IMFMediaEvent
*event
)
769 MediaEventType event_type
;
776 IMFMediaEvent_GetType(event
, &event_type
);
778 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
780 WARN("Unidentified stream %p, hr %#x.\n", stream
, hr
);
784 EnterCriticalSection(&reader
->cs
);
786 for (i
= 0; i
< reader
->stream_count
; ++i
)
788 struct media_stream
*stream
= &reader
->streams
[i
];
790 if (id
== stream
->id
)
795 stream
->state
= STREAM_STATE_EOS
;
796 stream
->flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
798 if (stream
->decoder
.transform
&& SUCCEEDED(IMFTransform_ProcessMessage(stream
->decoder
.transform
,
799 MFT_MESSAGE_COMMAND_DRAIN
, 0)))
801 if ((hr
= source_reader_pull_stream_samples(reader
, stream
)) != MF_E_TRANSFORM_NEED_MORE_INPUT
)
802 WARN("Failed to pull pending samples, hr %#x.\n", hr
);
805 while (stream
->requests
)
806 source_reader_queue_response(reader
, stream
, S_OK
, MF_SOURCE_READERF_ENDOFSTREAM
, 0, NULL
);
810 case MEStreamStarted
:
811 stream
->state
= STREAM_STATE_READY
;
815 hr
= SUCCEEDED(IMFMediaEvent_GetValue(event
, &value
)) && value
.vt
== VT_I8
? S_OK
: E_UNEXPECTED
;
816 timestamp
= SUCCEEDED(hr
) ? value
.hVal
.QuadPart
: 0;
817 PropVariantClear(&value
);
819 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_STREAMTICK
, timestamp
, NULL
);
830 LeaveCriticalSection(&reader
->cs
);
835 static HRESULT WINAPI
source_reader_stream_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
837 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
838 MediaEventType event_type
;
839 IMFMediaStream
*stream
;
840 IMFMediaEvent
*event
;
843 TRACE("%p, %p.\n", iface
, result
);
845 stream
= (IMFMediaStream
*)IMFAsyncResult_GetStateNoAddRef(result
);
847 if (FAILED(hr
= IMFMediaStream_EndGetEvent(stream
, result
, &event
)))
850 IMFMediaEvent_GetType(event
, &event_type
);
852 TRACE("Got event %u.\n", event_type
);
857 hr
= source_reader_media_sample_handler(reader
, stream
, event
);
860 case MEStreamStarted
:
863 hr
= source_reader_media_stream_state_handler(reader
, stream
, event
);
870 WARN("Failed while handling %d event, hr %#x.\n", event_type
, hr
);
872 IMFMediaEvent_Release(event
);
874 IMFMediaStream_BeginGetEvent(stream
, iface
, (IUnknown
*)stream
);
879 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl
=
881 source_reader_callback_QueryInterface
,
882 source_reader_stream_events_callback_AddRef
,
883 source_reader_stream_events_callback_Release
,
884 source_reader_callback_GetParameters
,
885 source_reader_stream_events_callback_Invoke
,
888 static ULONG WINAPI
source_reader_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
890 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
891 return IMFSourceReader_AddRef(&reader
->IMFSourceReader_iface
);
894 static ULONG WINAPI
source_reader_async_commands_callback_Release(IMFAsyncCallback
*iface
)
896 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
897 return IMFSourceReader_Release(&reader
->IMFSourceReader_iface
);
900 static struct stream_response
* media_stream_detach_response(struct source_reader
*reader
, struct stream_response
*response
)
902 struct media_stream
*stream
;
904 list_remove(&response
->entry
);
906 if (response
->stream_index
< reader
->stream_count
)
908 stream
= &reader
->streams
[response
->stream_index
];
909 if (stream
->responses
)
916 static struct stream_response
*media_stream_pop_response(struct source_reader
*reader
, struct media_stream
*stream
)
918 struct stream_response
*response
;
920 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
922 if ((stream
&& response
->stream_index
!= stream
->index
) || response
->sa_pending
)
925 return media_stream_detach_response(reader
, response
);
931 static struct stream_response
*media_stream_pick_pending_response(struct source_reader
*reader
, unsigned int stream
)
933 struct stream_response
*response
;
935 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
937 if (response
->stream_index
== stream
&& response
->sa_pending
)
944 static void source_reader_release_response(struct stream_response
*response
)
946 if (response
->sample
)
947 IMFSample_Release(response
->sample
);
951 static HRESULT
source_reader_get_stream_selection(const struct source_reader
*reader
, DWORD index
, BOOL
*selected
)
953 IMFStreamDescriptor
*sd
;
955 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, selected
, &sd
)))
956 return MF_E_INVALIDSTREAMNUMBER
;
957 IMFStreamDescriptor_Release(sd
);
962 static HRESULT
source_reader_start_source(struct source_reader
*reader
)
964 BOOL selected
, selection_changed
= FALSE
;
965 PROPVARIANT position
;
969 for (i
= 0; i
< reader
->stream_count
; ++i
)
971 source_reader_get_stream_selection(reader
, i
, &selected
);
973 reader
->streams
[i
].flags
|= STREAM_FLAG_SELECTED
;
975 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SELECTED
;
978 if (reader
->source_state
== SOURCE_STATE_STARTED
)
980 for (i
= 0; i
< reader
->stream_count
; ++i
)
982 selection_changed
= !!(reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
) ^
983 !!(reader
->streams
[i
].flags
& STREAM_FLAG_PRESENTED
);
984 if (selection_changed
)
989 position
.hVal
.QuadPart
= 0;
990 if (reader
->source_state
!= SOURCE_STATE_STARTED
|| selection_changed
)
992 position
.vt
= reader
->source_state
== SOURCE_STATE_STARTED
? VT_EMPTY
: VT_I8
;
994 /* Update cached stream selection if descriptor was accepted. */
995 if (SUCCEEDED(hr
= IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &GUID_NULL
, &position
)))
997 for (i
= 0; i
< reader
->stream_count
; ++i
)
999 if (reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
)
1000 reader
->streams
[i
].flags
|= STREAM_FLAG_PRESENTED
;
1008 static BOOL
source_reader_got_response_for_stream(struct source_reader
*reader
, struct media_stream
*stream
)
1010 struct stream_response
*response
;
1012 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1014 if (response
->stream_index
== stream
->index
&& !response
->sa_pending
)
1021 static BOOL
source_reader_get_read_result(struct source_reader
*reader
, struct media_stream
*stream
, DWORD flags
,
1022 HRESULT
*status
, DWORD
*stream_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1024 struct stream_response
*response
= NULL
;
1025 BOOL request_sample
= FALSE
;
1027 if ((response
= media_stream_pop_response(reader
, stream
)))
1029 *status
= response
->status
;
1030 *stream_index
= stream
->index
;
1031 *stream_flags
= response
->stream_flags
;
1032 *timestamp
= response
->timestamp
;
1033 *sample
= response
->sample
;
1035 IMFSample_AddRef(*sample
);
1037 source_reader_release_response(response
);
1042 *stream_index
= stream
->index
;
1046 if (stream
->state
== STREAM_STATE_EOS
)
1048 *stream_flags
= MF_SOURCE_READERF_ENDOFSTREAM
;
1052 request_sample
= !(flags
& MF_SOURCE_READER_CONTROLF_DRAIN
);
1057 return !request_sample
;
1060 static HRESULT
source_reader_get_next_selected_stream(struct source_reader
*reader
, unsigned int *stream_index
)
1062 unsigned int i
, first_selected
= ~0u, requests
= ~0u;
1063 BOOL selected
, stream_drained
;
1065 for (i
= (reader
->last_read_index
+ 1) % reader
->stream_count
; ; i
= (i
+ 1) % reader
->stream_count
)
1067 stream_drained
= reader
->streams
[i
].state
== STREAM_STATE_EOS
&& !reader
->streams
[i
].responses
;
1068 selected
= SUCCEEDED(source_reader_get_stream_selection(reader
, i
, &selected
)) && selected
;
1072 if (first_selected
== ~0u)
1075 /* Try to balance pending reads. */
1076 if (!stream_drained
&& reader
->streams
[i
].requests
< requests
)
1078 requests
= reader
->streams
[i
].requests
;
1083 if (i
== reader
->last_read_index
)
1087 /* If all selected streams reached EOS, use first selected. */
1088 if (first_selected
!= ~0u)
1090 if (requests
== ~0u)
1091 *stream_index
= first_selected
;
1092 reader
->last_read_index
= *stream_index
;
1095 return first_selected
== ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED
: S_OK
;
1098 static HRESULT
source_reader_get_stream_read_index(struct source_reader
*reader
, unsigned int index
, unsigned int *stream_index
)
1105 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1106 *stream_index
= reader
->first_video_stream_index
;
1108 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1109 *stream_index
= reader
->first_audio_stream_index
;
1111 case MF_SOURCE_READER_ANY_STREAM
:
1112 return source_reader_get_next_selected_stream(reader
, stream_index
);
1114 *stream_index
= index
;
1117 /* Can't read from deselected streams. */
1118 if (SUCCEEDED(hr
= source_reader_get_stream_selection(reader
, *stream_index
, &selected
)) && !selected
)
1119 hr
= MF_E_INVALIDREQUEST
;
1124 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
)
1126 struct stream_response
*ptr
, *next
;
1128 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &reader
->responses
, struct stream_response
, entry
)
1130 if (stream
&& stream
->index
!= ptr
->stream_index
&&
1131 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_VIDEO_STREAM
&&
1132 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_AUDIO_STREAM
&&
1133 ptr
->stream_index
!= MF_SOURCE_READER_ANY_STREAM
)
1137 media_stream_detach_response(reader
, ptr
);
1138 source_reader_release_response(ptr
);
1142 static void source_reader_flush_stream(struct source_reader
*reader
, DWORD stream_index
)
1144 struct media_stream
*stream
= &reader
->streams
[stream_index
];
1146 source_reader_release_responses(reader
, stream
);
1147 if (stream
->decoder
.transform
)
1148 IMFTransform_ProcessMessage(stream
->decoder
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
1149 stream
->requests
= 0;
1152 static HRESULT
source_reader_flush(struct source_reader
*reader
, unsigned int index
)
1154 unsigned int stream_index
;
1157 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1159 for (stream_index
= 0; stream_index
< reader
->stream_count
; ++stream_index
)
1160 source_reader_flush_stream(reader
, stream_index
);
1166 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1167 stream_index
= reader
->first_video_stream_index
;
1169 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1170 stream_index
= reader
->first_audio_stream_index
;
1173 stream_index
= index
;
1176 if (stream_index
< reader
->stream_count
)
1177 source_reader_flush_stream(reader
, stream_index
);
1179 hr
= MF_E_INVALIDSTREAMNUMBER
;
1185 static HRESULT WINAPI
source_reader_async_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1187 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1188 struct media_stream
*stream
, stub_stream
= { .requests
= 1 };
1189 struct source_reader_async_command
*command
;
1190 struct stream_response
*response
;
1191 DWORD stream_index
, stream_flags
;
1192 BOOL report_sample
= FALSE
;
1193 IMFSample
*sample
= NULL
;
1194 LONGLONG timestamp
= 0;
1198 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
1201 command
= impl_from_async_command_IUnknown(state
);
1203 switch (command
->op
)
1205 case SOURCE_READER_ASYNC_READ
:
1206 EnterCriticalSection(&reader
->cs
);
1208 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1210 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, command
->u
.read
.stream_index
, &stream_index
)))
1212 stream
= &reader
->streams
[stream_index
];
1214 if (!(report_sample
= source_reader_get_read_result(reader
, stream
, command
->u
.read
.flags
, &status
,
1215 &stream_index
, &stream_flags
, ×tamp
, &sample
)))
1218 source_reader_request_sample(reader
, stream
);
1219 /* FIXME: set error stream/reader state on request failure */
1224 stub_stream
.index
= command
->u
.read
.stream_index
;
1225 source_reader_queue_response(reader
, &stub_stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
1229 LeaveCriticalSection(&reader
->cs
);
1232 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, status
, stream_index
, stream_flags
,
1236 IMFSample_Release(sample
);
1240 case SOURCE_READER_ASYNC_SEEK
:
1242 EnterCriticalSection(&reader
->cs
);
1243 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &command
->u
.seek
.format
,
1244 &command
->u
.seek
.position
)))
1246 reader
->flags
|= SOURCE_READER_SEEKING
;
1248 LeaveCriticalSection(&reader
->cs
);
1252 case SOURCE_READER_ASYNC_SA_READY
:
1254 EnterCriticalSection(&reader
->cs
);
1255 if ((response
= media_stream_pick_pending_response(reader
, command
->u
.sa
.stream_index
)))
1257 source_reader_set_sa_response(reader
, response
);
1258 source_reader_response_ready(reader
, response
);
1260 LeaveCriticalSection(&reader
->cs
);
1264 case SOURCE_READER_ASYNC_SAMPLE_READY
:
1266 EnterCriticalSection(&reader
->cs
);
1267 response
= media_stream_pop_response(reader
, NULL
);
1268 LeaveCriticalSection(&reader
->cs
);
1272 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, response
->status
, response
->stream_index
,
1273 response
->stream_flags
, response
->timestamp
, response
->sample
);
1274 source_reader_release_response(response
);
1278 case SOURCE_READER_ASYNC_FLUSH
:
1279 EnterCriticalSection(&reader
->cs
);
1280 source_reader_flush(reader
, command
->u
.flush
.stream_index
);
1281 reader
->flags
&= ~SOURCE_READER_FLUSHING
;
1282 LeaveCriticalSection(&reader
->cs
);
1284 IMFSourceReaderCallback_OnFlush(reader
->async_callback
, command
->u
.flush
.stream_index
);
1290 IUnknown_Release(state
);
1295 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl
=
1297 source_reader_callback_QueryInterface
,
1298 source_reader_async_commands_callback_AddRef
,
1299 source_reader_async_commands_callback_Release
,
1300 source_reader_callback_GetParameters
,
1301 source_reader_async_commands_callback_Invoke
,
1304 static HRESULT WINAPI
src_reader_QueryInterface(IMFSourceReader
*iface
, REFIID riid
, void **out
)
1306 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1308 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1310 if(IsEqualGUID(riid
, &IID_IUnknown
) ||
1311 IsEqualGUID(riid
, &IID_IMFSourceReader
))
1313 *out
= &reader
->IMFSourceReader_iface
;
1317 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1319 return E_NOINTERFACE
;
1322 IUnknown_AddRef((IUnknown
*)*out
);
1326 static ULONG WINAPI
src_reader_AddRef(IMFSourceReader
*iface
)
1328 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1329 ULONG refcount
= InterlockedIncrement(&reader
->refcount
);
1331 TRACE("%p, refcount %u.\n", iface
, refcount
);
1336 static ULONG WINAPI
src_reader_Release(IMFSourceReader
*iface
)
1338 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1339 ULONG refcount
= InterlockedDecrement(&reader
->refcount
);
1342 TRACE("%p, refcount %u.\n", iface
, refcount
);
1346 if (reader
->async_callback
)
1347 IMFSourceReaderCallback_Release(reader
->async_callback
);
1348 if (reader
->flags
& SOURCE_READER_SHUTDOWN_ON_RELEASE
)
1349 IMFMediaSource_Shutdown(reader
->source
);
1350 if (reader
->descriptor
)
1351 IMFPresentationDescriptor_Release(reader
->descriptor
);
1352 if (reader
->attributes
)
1353 IMFAttributes_Release(reader
->attributes
);
1354 IMFMediaSource_Release(reader
->source
);
1356 for (i
= 0; i
< reader
->stream_count
; ++i
)
1358 struct media_stream
*stream
= &reader
->streams
[i
];
1361 IMFMediaStream_Release(stream
->stream
);
1362 if (stream
->current
)
1363 IMFMediaType_Release(stream
->current
);
1364 if (stream
->decoder
.transform
)
1365 IMFTransform_Release(stream
->decoder
.transform
);
1366 if (stream
->allocator
)
1367 IMFVideoSampleAllocatorEx_Release(stream
->allocator
);
1369 source_reader_release_responses(reader
, NULL
);
1370 free(reader
->streams
);
1371 MFUnlockWorkQueue(reader
->queue
);
1372 DeleteCriticalSection(&reader
->cs
);
1379 static HRESULT WINAPI
src_reader_GetStreamSelection(IMFSourceReader
*iface
, DWORD index
, BOOL
*selected
)
1381 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1383 TRACE("%p, %#x, %p.\n", iface
, index
, selected
);
1387 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1388 index
= reader
->first_video_stream_index
;
1390 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1391 index
= reader
->first_audio_stream_index
;
1397 return source_reader_get_stream_selection(reader
, index
, selected
);
1400 static HRESULT WINAPI
src_reader_SetStreamSelection(IMFSourceReader
*iface
, DWORD index
, BOOL selection
)
1402 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1404 BOOL selection_changed
= FALSE
, selected
;
1407 TRACE("%p, %#x, %d.\n", iface
, index
, selection
);
1409 selection
= !!selection
;
1411 EnterCriticalSection(&reader
->cs
);
1413 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1415 for (i
= 0; i
< reader
->stream_count
; ++i
)
1417 if (!selection_changed
)
1419 source_reader_get_stream_selection(reader
, i
, &selected
);
1420 selection_changed
= !!(selected
^ selection
);
1424 IMFPresentationDescriptor_SelectStream(reader
->descriptor
, i
);
1426 IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, i
);
1433 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1434 index
= reader
->first_video_stream_index
;
1436 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1437 index
= reader
->first_audio_stream_index
;
1443 source_reader_get_stream_selection(reader
, index
, &selected
);
1444 selection_changed
= !!(selected
^ selection
);
1447 hr
= IMFPresentationDescriptor_SelectStream(reader
->descriptor
, index
);
1449 hr
= IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, index
);
1452 if (selection_changed
)
1453 reader
->last_read_index
= reader
->stream_count
- 1;
1455 LeaveCriticalSection(&reader
->cs
);
1457 return SUCCEEDED(hr
) ? S_OK
: MF_E_INVALIDSTREAMNUMBER
;
1460 static HRESULT
source_reader_get_native_media_type(struct source_reader
*reader
, DWORD index
, DWORD type_index
,
1461 IMFMediaType
**type
)
1463 IMFMediaTypeHandler
*handler
;
1464 IMFStreamDescriptor
*sd
;
1465 IMFMediaType
*src_type
;
1471 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1472 index
= reader
->first_video_stream_index
;
1474 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1475 index
= reader
->first_audio_stream_index
;
1481 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1482 return MF_E_INVALIDSTREAMNUMBER
;
1484 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
1485 IMFStreamDescriptor_Release(sd
);
1489 if (type_index
== MF_SOURCE_READER_CURRENT_TYPE_INDEX
)
1490 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &src_type
);
1492 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, type_index
, &src_type
);
1493 IMFMediaTypeHandler_Release(handler
);
1497 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
1498 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)*type
);
1499 IMFMediaType_Release(src_type
);
1505 static HRESULT WINAPI
src_reader_GetNativeMediaType(IMFSourceReader
*iface
, DWORD index
, DWORD type_index
,
1506 IMFMediaType
**type
)
1508 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1510 TRACE("%p, %#x, %#x, %p.\n", iface
, index
, type_index
, type
);
1512 return source_reader_get_native_media_type(reader
, index
, type_index
, type
);
1515 static HRESULT WINAPI
src_reader_GetCurrentMediaType(IMFSourceReader
*iface
, DWORD index
, IMFMediaType
**type
)
1517 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1520 TRACE("%p, %#x, %p.\n", iface
, index
, type
);
1524 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1525 index
= reader
->first_video_stream_index
;
1527 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1528 index
= reader
->first_audio_stream_index
;
1534 if (index
>= reader
->stream_count
)
1535 return MF_E_INVALIDSTREAMNUMBER
;
1537 if (FAILED(hr
= MFCreateMediaType(type
)))
1540 EnterCriticalSection(&reader
->cs
);
1542 hr
= IMFMediaType_CopyAllItems(reader
->streams
[index
].current
, (IMFAttributes
*)*type
);
1544 LeaveCriticalSection(&reader
->cs
);
1549 static HRESULT
source_reader_get_source_type_handler(struct source_reader
*reader
, DWORD index
,
1550 IMFMediaTypeHandler
**handler
)
1552 IMFStreamDescriptor
*sd
;
1556 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1559 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, handler
);
1560 IMFStreamDescriptor_Release(sd
);
1565 static HRESULT
source_reader_set_compatible_media_type(struct source_reader
*reader
, DWORD index
, IMFMediaType
*type
)
1567 IMFMediaTypeHandler
*type_handler
;
1568 IMFMediaType
*native_type
;
1569 BOOL type_set
= FALSE
;
1574 if (FAILED(hr
= IMFMediaType_IsEqual(type
, reader
->streams
[index
].current
, &flags
)))
1577 if (!(flags
& MF_MEDIATYPE_EQUAL_MAJOR_TYPES
))
1578 return MF_E_INVALIDMEDIATYPE
;
1580 /* No need for a decoder or type change. */
1581 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_DATA
)
1584 if (FAILED(hr
= source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1587 while (!type_set
&& IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler
, i
++, &native_type
) == S_OK
)
1589 static const DWORD compare_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_DATA
;
1591 if (SUCCEEDED(IMFMediaType_IsEqual(native_type
, type
, &flags
)) && (flags
& compare_flags
) == compare_flags
)
1593 if ((type_set
= SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, native_type
))))
1594 IMFMediaType_CopyAllItems(native_type
, (IMFAttributes
*)reader
->streams
[index
].current
);
1597 IMFMediaType_Release(native_type
);
1600 IMFMediaTypeHandler_Release(type_handler
);
1602 return type_set
? S_OK
: S_FALSE
;
1605 static HRESULT
source_reader_setup_sample_allocator(struct source_reader
*reader
, unsigned int index
)
1607 struct media_stream
*stream
= &reader
->streams
[index
];
1608 IMFVideoSampleAllocatorCallback
*callback
;
1612 IMFMediaType_GetMajorType(stream
->current
, &major
);
1613 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
1616 if (!(reader
->flags
& SOURCE_READER_HAS_DEVICE_MANAGER
))
1619 if (!stream
->allocator
)
1621 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&stream
->allocator
)))
1623 WARN("Failed to create sample allocator, hr %#x.\n", hr
);
1628 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream
->allocator
);
1629 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(stream
->allocator
, reader
->device_manager
)))
1631 WARN("Failed to set device manager, hr %#x.\n", hr
);
1635 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream
->allocator
, 2, 8, NULL
, stream
->current
)))
1636 WARN("Failed to initialize sample allocator, hr %#x.\n", hr
);
1638 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream
->allocator
, &IID_IMFVideoSampleAllocatorCallback
, (void **)&callback
)))
1640 if (FAILED(hr
= IMFVideoSampleAllocatorCallback_SetCallback(callback
, &stream
->notify_cb
)))
1641 WARN("Failed to set allocator callback, hr %#x.\n", hr
);
1642 IMFVideoSampleAllocatorCallback_Release(callback
);
1648 static HRESULT
source_reader_configure_decoder(struct source_reader
*reader
, DWORD index
, const CLSID
*clsid
,
1649 IMFMediaType
*input_type
, IMFMediaType
*output_type
)
1651 IMFMediaTypeHandler
*type_handler
;
1652 unsigned int block_alignment
= 0;
1653 IMFTransform
*transform
= NULL
;
1654 IMFMediaType
*type
= NULL
;
1660 if (FAILED(hr
= CoCreateInstance(clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTransform
, (void **)&transform
)))
1662 WARN("Failed to create transform object, hr %#x.\n", hr
);
1666 if (FAILED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0)))
1668 WARN("Failed to set decoder input type, hr %#x.\n", hr
);
1669 IMFTransform_Release(transform
);
1673 /* Find the relevant output type. */
1674 while (IMFTransform_GetOutputAvailableType(transform
, 0, i
++, &type
) == S_OK
)
1678 if (SUCCEEDED(IMFMediaType_IsEqual(type
, output_type
, &flags
)))
1680 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_TYPES
)
1682 if (SUCCEEDED(IMFTransform_SetOutputType(transform
, 0, type
, 0)))
1684 if (SUCCEEDED(source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1686 IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, input_type
);
1687 IMFMediaTypeHandler_Release(type_handler
);
1690 if (FAILED(hr
= IMFMediaType_CopyAllItems(type
, (IMFAttributes
*)reader
->streams
[index
].current
)))
1691 WARN("Failed to copy attributes, hr %#x.\n", hr
);
1692 if (SUCCEEDED(IMFMediaType_GetMajorType(type
, &major
)) && IsEqualGUID(&major
, &MFMediaType_Audio
))
1693 IMFMediaType_GetUINT32(type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
);
1694 IMFMediaType_Release(type
);
1696 if (reader
->streams
[index
].decoder
.transform
)
1697 IMFTransform_Release(reader
->streams
[index
].decoder
.transform
);
1699 reader
->streams
[index
].decoder
.transform
= transform
;
1700 reader
->streams
[index
].decoder
.min_buffer_size
= block_alignment
;
1707 IMFMediaType_Release(type
);
1710 WARN("Failed to find suitable decoder output type.\n");
1712 IMFTransform_Release(transform
);
1714 return MF_E_TOPO_CODEC_NOT_FOUND
;
1717 static HRESULT
source_reader_create_decoder_for_stream(struct source_reader
*reader
, DWORD index
, IMFMediaType
*output_type
)
1719 MFT_REGISTER_TYPE_INFO in_type
, out_type
;
1720 CLSID
*clsids
, mft_clsid
, category
;
1721 unsigned int i
= 0, count
;
1722 IMFMediaType
*input_type
;
1725 /* TODO: should we check if the source type is compressed? */
1727 if (FAILED(hr
= IMFMediaType_GetMajorType(output_type
, &out_type
.guidMajorType
)))
1730 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
))
1732 category
= MFT_CATEGORY_VIDEO_DECODER
;
1734 else if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1736 category
= MFT_CATEGORY_AUDIO_DECODER
;
1740 WARN("Unhandled major type %s.\n", debugstr_guid(&out_type
.guidMajorType
));
1741 return MF_E_TOPO_CODEC_NOT_FOUND
;
1744 if (FAILED(hr
= IMFMediaType_GetGUID(output_type
, &MF_MT_SUBTYPE
, &out_type
.guidSubtype
)))
1747 in_type
.guidMajorType
= out_type
.guidMajorType
;
1749 while (source_reader_get_native_media_type(reader
, index
, i
++, &input_type
) == S_OK
)
1751 if (SUCCEEDED(IMFMediaType_GetGUID(input_type
, &MF_MT_SUBTYPE
, &in_type
.guidSubtype
)))
1754 if (SUCCEEDED(hr
= MFTEnum(category
, 0, &in_type
, &out_type
, NULL
, &clsids
, &count
)) && count
)
1756 mft_clsid
= clsids
[0];
1757 CoTaskMemFree(clsids
);
1759 /* TODO: Should we iterate over all of them? */
1760 if (SUCCEEDED(source_reader_configure_decoder(reader
, index
, &mft_clsid
, input_type
, output_type
)))
1762 IMFMediaType_Release(input_type
);
1769 IMFMediaType_Release(input_type
);
1772 return MF_E_TOPO_CODEC_NOT_FOUND
;
1775 static HRESULT WINAPI
src_reader_SetCurrentMediaType(IMFSourceReader
*iface
, DWORD index
, DWORD
*reserved
,
1778 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1781 TRACE("%p, %#x, %p, %p.\n", iface
, index
, reserved
, type
);
1785 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1786 index
= reader
->first_video_stream_index
;
1788 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1789 index
= reader
->first_audio_stream_index
;
1795 if (index
>= reader
->stream_count
)
1796 return MF_E_INVALIDSTREAMNUMBER
;
1798 /* FIXME: setting the output type while streaming should trigger a flush */
1800 EnterCriticalSection(&reader
->cs
);
1802 hr
= source_reader_set_compatible_media_type(reader
, index
, type
);
1804 hr
= source_reader_create_decoder_for_stream(reader
, index
, type
);
1806 hr
= source_reader_setup_sample_allocator(reader
, index
);
1808 LeaveCriticalSection(&reader
->cs
);
1813 static HRESULT WINAPI
src_reader_SetCurrentPosition(IMFSourceReader
*iface
, REFGUID format
, REFPROPVARIANT position
)
1815 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1816 struct source_reader_async_command
*command
;
1817 unsigned int i
, flags
;
1820 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), position
);
1822 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
1825 if (!(flags
& MFMEDIASOURCE_CAN_SEEK
))
1826 return MF_E_INVALIDREQUEST
;
1828 EnterCriticalSection(&reader
->cs
);
1830 /* Check if we got pending requests. */
1831 for (i
= 0; i
< reader
->stream_count
; ++i
)
1833 if (reader
->streams
[i
].requests
)
1835 hr
= MF_E_INVALIDREQUEST
;
1842 if (reader
->async_callback
)
1844 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK
, &command
)))
1846 command
->u
.seek
.format
= *format
;
1847 PropVariantCopy(&command
->u
.seek
.position
, position
);
1849 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
1850 IUnknown_Release(&command
->IUnknown_iface
);
1855 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, format
, position
)))
1857 reader
->flags
|= SOURCE_READER_SEEKING
;
1858 while (reader
->flags
& SOURCE_READER_SEEKING
)
1860 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
1866 LeaveCriticalSection(&reader
->cs
);
1871 static HRESULT
source_reader_read_sample(struct source_reader
*reader
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
1872 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1874 unsigned int actual_index_tmp
;
1875 struct media_stream
*stream
;
1876 LONGLONG timestamp_tmp
;
1880 if (!stream_flags
|| !sample
)
1886 timestamp
= ×tamp_tmp
;
1889 actual_index
= &actual_index_tmp
;
1891 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1893 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, index
, &stream_index
)))
1895 *actual_index
= stream_index
;
1897 stream
= &reader
->streams
[stream_index
];
1899 if (!source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
1902 while (!source_reader_got_response_for_stream(reader
, stream
) && stream
->state
!= STREAM_STATE_EOS
)
1905 if (FAILED(hr
= source_reader_request_sample(reader
, stream
)))
1906 WARN("Failed to request a sample, hr %#x.\n", hr
);
1907 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
1909 *stream_flags
= MF_SOURCE_READERF_ERROR
;
1913 SleepConditionVariableCS(&reader
->sample_event
, &reader
->cs
, INFINITE
);
1916 source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
1922 *actual_index
= index
;
1923 *stream_flags
= MF_SOURCE_READERF_ERROR
;
1928 TRACE("Stream %u, got sample %p, flags %#x.\n", *actual_index
, *sample
, *stream_flags
);
1933 static HRESULT
source_reader_read_sample_async(struct source_reader
*reader
, unsigned int index
, unsigned int flags
,
1934 unsigned int *actual_index
, unsigned int *stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1936 struct source_reader_async_command
*command
;
1939 if (actual_index
|| stream_flags
|| timestamp
|| sample
)
1940 return E_INVALIDARG
;
1942 if (reader
->flags
& SOURCE_READER_FLUSHING
)
1943 hr
= MF_E_NOTACCEPTING
;
1946 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_READ
, &command
)))
1948 command
->u
.read
.stream_index
= index
;
1949 command
->u
.read
.flags
= flags
;
1951 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
1952 IUnknown_Release(&command
->IUnknown_iface
);
1959 static HRESULT WINAPI
src_reader_ReadSample(IMFSourceReader
*iface
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
1960 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1962 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
1965 TRACE("%p, %#x, %#x, %p, %p, %p, %p\n", iface
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
1967 EnterCriticalSection(&reader
->cs
);
1969 while (reader
->flags
& SOURCE_READER_SEEKING
)
1971 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
1974 if (reader
->async_callback
)
1975 hr
= source_reader_read_sample_async(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
1977 hr
= source_reader_read_sample(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
1979 LeaveCriticalSection(&reader
->cs
);
1984 static HRESULT
source_reader_flush_async(struct source_reader
*reader
, unsigned int index
)
1986 struct source_reader_async_command
*command
;
1987 unsigned int stream_index
;
1990 if (reader
->flags
& SOURCE_READER_FLUSHING
)
1991 return MF_E_INVALIDREQUEST
;
1995 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1996 stream_index
= reader
->first_video_stream_index
;
1998 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1999 stream_index
= reader
->first_audio_stream_index
;
2002 stream_index
= index
;
2005 reader
->flags
|= SOURCE_READER_FLUSHING
;
2007 if (stream_index
!= MF_SOURCE_READER_ALL_STREAMS
&& stream_index
>= reader
->stream_count
)
2008 return MF_E_INVALIDSTREAMNUMBER
;
2010 if (FAILED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH
, &command
)))
2013 command
->u
.flush
.stream_index
= stream_index
;
2015 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2016 IUnknown_Release(&command
->IUnknown_iface
);
2021 static HRESULT WINAPI
src_reader_Flush(IMFSourceReader
*iface
, DWORD index
)
2023 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
2026 TRACE("%p, %#x.\n", iface
, index
);
2028 EnterCriticalSection(&reader
->cs
);
2030 if (reader
->async_callback
)
2031 hr
= source_reader_flush_async(reader
, index
);
2033 hr
= source_reader_flush(reader
, index
);
2035 LeaveCriticalSection(&reader
->cs
);
2040 static HRESULT WINAPI
src_reader_GetServiceForStream(IMFSourceReader
*iface
, DWORD index
, REFGUID service
,
2041 REFIID riid
, void **object
)
2043 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
2044 IUnknown
*obj
= NULL
;
2047 TRACE("%p, %#x, %s, %s, %p\n", iface
, index
, debugstr_guid(service
), debugstr_guid(riid
), object
);
2049 EnterCriticalSection(&reader
->cs
);
2053 case MF_SOURCE_READER_MEDIASOURCE
:
2054 obj
= (IUnknown
*)reader
->source
;
2057 if (index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2058 index
= reader
->first_video_stream_index
;
2059 else if (index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2060 index
= reader
->first_audio_stream_index
;
2062 if (index
>= reader
->stream_count
)
2063 hr
= MF_E_INVALIDSTREAMNUMBER
;
2066 obj
= (IUnknown
*)reader
->streams
[index
].decoder
.transform
;
2067 if (!obj
) hr
= E_NOINTERFACE
;
2073 IUnknown_AddRef(obj
);
2075 LeaveCriticalSection(&reader
->cs
);
2079 if (IsEqualGUID(service
, &GUID_NULL
))
2081 hr
= IUnknown_QueryInterface(obj
, riid
, object
);
2087 hr
= IUnknown_QueryInterface(obj
, &IID_IMFGetService
, (void **)&gs
);
2090 hr
= IMFGetService_GetService(gs
, service
, riid
, object
);
2091 IMFGetService_Release(gs
);
2097 IUnknown_Release(obj
);
2102 static HRESULT WINAPI
src_reader_GetPresentationAttribute(IMFSourceReader
*iface
, DWORD index
,
2103 REFGUID guid
, PROPVARIANT
*value
)
2105 struct source_reader
*reader
= impl_from_IMFSourceReader(iface
);
2106 IMFStreamDescriptor
*sd
;
2110 TRACE("%p, %#x, %s, %p.\n", iface
, index
, debugstr_guid(guid
), value
);
2114 case MF_SOURCE_READER_MEDIASOURCE
:
2115 if (IsEqualGUID(guid
, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS
))
2119 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2123 value
->ulVal
= flags
;
2128 return IMFPresentationDescriptor_GetItem(reader
->descriptor
, guid
, value
);
2131 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2132 index
= reader
->first_video_stream_index
;
2134 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2135 index
= reader
->first_audio_stream_index
;
2141 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
2144 hr
= IMFStreamDescriptor_GetItem(sd
, guid
, value
);
2145 IMFStreamDescriptor_Release(sd
);
2150 static const IMFSourceReaderVtbl srcreader_vtbl
=
2152 src_reader_QueryInterface
,
2155 src_reader_GetStreamSelection
,
2156 src_reader_SetStreamSelection
,
2157 src_reader_GetNativeMediaType
,
2158 src_reader_GetCurrentMediaType
,
2159 src_reader_SetCurrentMediaType
,
2160 src_reader_SetCurrentPosition
,
2161 src_reader_ReadSample
,
2163 src_reader_GetServiceForStream
,
2164 src_reader_GetPresentationAttribute
2167 static DWORD
reader_get_first_stream_index(IMFPresentationDescriptor
*descriptor
, const GUID
*major
)
2169 unsigned int count
, i
;
2174 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
2175 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2177 for (i
= 0; i
< count
; ++i
)
2179 IMFMediaTypeHandler
*handler
;
2180 IMFStreamDescriptor
*sd
;
2182 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
, &selected
, &sd
)))
2184 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2185 IMFStreamDescriptor_Release(sd
);
2188 hr
= IMFMediaTypeHandler_GetMajorType(handler
, &guid
);
2189 IMFMediaTypeHandler_Release(handler
);
2192 WARN("Failed to get stream major type, hr %#x.\n", hr
);
2196 if (IsEqualGUID(&guid
, major
))
2204 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2207 static HRESULT WINAPI
stream_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify
*iface
,
2208 REFIID riid
, void **obj
)
2210 if (IsEqualIID(riid
, &IID_IMFVideoSampleAllocatorNotify
) ||
2211 IsEqualIID(riid
, &IID_IUnknown
))
2214 IMFVideoSampleAllocatorNotify_AddRef(iface
);
2219 return E_NOINTERFACE
;
2222 static ULONG WINAPI
stream_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify
*iface
)
2227 static ULONG WINAPI
stream_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify
*iface
)
2232 static HRESULT WINAPI
stream_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify
*iface
)
2234 struct media_stream
*stream
= impl_stream_from_IMFVideoSampleAllocatorNotify(iface
);
2235 struct source_reader_async_command
*command
;
2237 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SA_READY
, &command
)))
2239 command
->u
.sa
.stream_index
= stream
->index
;
2240 MFPutWorkItem(stream
->reader
->queue
, &stream
->reader
->async_commands_callback
, &command
->IUnknown_iface
);
2241 IUnknown_Release(&command
->IUnknown_iface
);
2247 static const IMFVideoSampleAllocatorNotifyVtbl stream_sample_allocator_cb_vtbl
=
2249 stream_sample_allocator_cb_QueryInterface
,
2250 stream_sample_allocator_cb_AddRef
,
2251 stream_sample_allocator_cb_Release
,
2252 stream_sample_allocator_cb_NotifyRelease
,
2255 static HRESULT
create_source_reader_from_source(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2256 BOOL shutdown_on_release
, REFIID riid
, void **out
)
2258 struct source_reader
*object
;
2262 object
= calloc(1, sizeof(*object
));
2264 return E_OUTOFMEMORY
;
2266 object
->IMFSourceReader_iface
.lpVtbl
= &srcreader_vtbl
;
2267 object
->source_events_callback
.lpVtbl
= &source_events_callback_vtbl
;
2268 object
->stream_events_callback
.lpVtbl
= &stream_events_callback_vtbl
;
2269 object
->async_commands_callback
.lpVtbl
= &async_commands_callback_vtbl
;
2270 object
->refcount
= 1;
2271 list_init(&object
->responses
);
2272 if (shutdown_on_release
)
2273 object
->flags
|= SOURCE_READER_SHUTDOWN_ON_RELEASE
;
2274 object
->source
= source
;
2275 IMFMediaSource_AddRef(object
->source
);
2276 InitializeCriticalSection(&object
->cs
);
2277 InitializeConditionVariable(&object
->sample_event
);
2278 InitializeConditionVariable(&object
->state_event
);
2280 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(object
->source
, &object
->descriptor
)))
2283 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(object
->descriptor
, &object
->stream_count
)))
2286 if (!(object
->streams
= calloc(object
->stream_count
, sizeof(*object
->streams
))))
2292 /* Set initial current media types. */
2293 for (i
= 0; i
< object
->stream_count
; ++i
)
2295 IMFMediaTypeHandler
*handler
;
2296 IMFStreamDescriptor
*sd
;
2297 IMFMediaType
*src_type
;
2300 if (FAILED(hr
= MFCreateMediaType(&object
->streams
[i
].current
)))
2303 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(object
->descriptor
, i
, &selected
, &sd
)))
2306 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &object
->streams
[i
].id
)))
2307 WARN("Failed to get stream identifier, hr %#x.\n", hr
);
2309 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2310 IMFStreamDescriptor_Release(sd
);
2314 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, 0, &src_type
);
2315 IMFMediaTypeHandler_Release(handler
);
2319 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)object
->streams
[i
].current
);
2320 IMFMediaType_Release(src_type
);
2324 object
->streams
[i
].notify_cb
.lpVtbl
= &stream_sample_allocator_cb_vtbl
;
2325 object
->streams
[i
].reader
= object
;
2326 object
->streams
[i
].index
= i
;
2332 /* At least one major type has to be set. */
2333 object
->first_audio_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Audio
);
2334 object
->first_video_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Video
);
2335 object
->last_read_index
= object
->stream_count
- 1;
2337 if (object
->first_audio_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
&&
2338 object
->first_video_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
)
2340 hr
= MF_E_ATTRIBUTENOTFOUND
;
2343 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(object
->source
, &object
->source_events_callback
,
2344 (IUnknown
*)object
->source
)))
2351 object
->attributes
= attributes
;
2352 IMFAttributes_AddRef(object
->attributes
);
2354 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_ASYNC_CALLBACK
, &IID_IMFSourceReaderCallback
,
2355 (void **)&object
->async_callback
);
2356 if (object
->async_callback
)
2357 TRACE("Using async callback %p.\n", object
->async_callback
);
2359 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_D3D_MANAGER
, &IID_IUnknown
, (void **)&object
->device_manager
);
2360 if (object
->device_manager
)
2362 IUnknown
*unk
= NULL
;
2364 if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IMFDXGIDeviceManager
, (void **)&unk
)))
2365 object
->flags
|= SOURCE_READER_DXGI_DEVICE_MANAGER
;
2366 else if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IDirect3DDeviceManager9
, (void **)&unk
)))
2367 object
->flags
|= SOURCE_READER_D3D9_DEVICE_MANAGER
;
2369 if (!(object
->flags
& (SOURCE_READER_HAS_DEVICE_MANAGER
)))
2371 WARN("Unknown device manager.\n");
2372 IUnknown_Release(object
->device_manager
);
2373 object
->device_manager
= NULL
;
2377 IUnknown_Release(unk
);
2381 if (FAILED(hr
= MFLockSharedWorkQueue(L
"", 0, NULL
, &object
->queue
)))
2382 WARN("Failed to acquired shared queue, hr %#x.\n", hr
);
2385 hr
= IMFSourceReader_QueryInterface(&object
->IMFSourceReader_iface
, riid
, out
);
2388 IMFSourceReader_Release(&object
->IMFSourceReader_iface
);
2392 static HRESULT
bytestream_get_url_hint(IMFByteStream
*stream
, WCHAR
const **url
)
2394 static const unsigned char asfmagic
[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c};
2395 static const unsigned char wavmagic
[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '};
2396 static const unsigned char wavmask
[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
2397 static const unsigned char isommagic
[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00};
2398 static const unsigned char mp4_magic
[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', 'S', 'N', 'V',0x00,0x00,0x00,0x00};
2399 static const unsigned char mp42magic
[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00};
2400 static const unsigned char mp4mask
[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00};
2401 static const struct stream_content_url_hint
2403 const unsigned char *magic
;
2405 const unsigned char *mask
;
2409 { asfmagic
, L
".asf" },
2410 { wavmagic
, L
".wav", wavmask
},
2411 { isommagic
, L
".mp4", mp4mask
},
2412 { mp42magic
, L
".mp4", mp4mask
},
2413 { mp4_magic
, L
".mp4", mp4mask
},
2415 unsigned char buffer
[4 * sizeof(unsigned int)], pattern
[4 * sizeof(unsigned int)];
2416 unsigned int i
, j
, length
= 0, caps
= 0;
2417 IMFAttributes
*attributes
;
2423 if (SUCCEEDED(IMFByteStream_QueryInterface(stream
, &IID_IMFAttributes
, (void **)&attributes
)))
2425 IMFAttributes_GetStringLength(attributes
, &MF_BYTESTREAM_CONTENT_TYPE
, &length
);
2426 IMFAttributes_Release(attributes
);
2432 if (FAILED(hr
= IMFByteStream_GetCapabilities(stream
, &caps
)))
2435 if (!(caps
& MFBYTESTREAM_IS_SEEKABLE
))
2438 if (FAILED(hr
= IMFByteStream_GetCurrentPosition(stream
, &position
)))
2441 hr
= IMFByteStream_Read(stream
, buffer
, sizeof(buffer
), &length
);
2442 IMFByteStream_SetCurrentPosition(stream
, position
);
2446 if (length
< sizeof(buffer
))
2449 for (i
= 0; i
< ARRAY_SIZE(url_hints
); ++i
)
2451 memcpy(pattern
, buffer
, sizeof(buffer
));
2452 if (url_hints
[i
].mask
)
2454 unsigned int *mask
= (unsigned int *)url_hints
[i
].mask
;
2455 unsigned int *data
= (unsigned int *)pattern
;
2457 for (j
= 0; j
< sizeof(buffer
) / sizeof(unsigned int); ++j
)
2461 if (!memcmp(pattern
, url_hints
[i
].magic
, sizeof(pattern
)))
2463 *url
= url_hints
[i
].url
;
2469 TRACE("Stream type guessed as %s from %s.\n", debugstr_w(*url
), debugstr_an((char *)buffer
, length
));
2471 WARN("Unrecognized content type %s.\n", debugstr_an((char *)buffer
, length
));
2476 static HRESULT
create_source_reader_from_stream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2477 REFIID riid
, void **out
)
2479 IPropertyStore
*props
= NULL
;
2480 IMFSourceResolver
*resolver
;
2481 MF_OBJECT_TYPE obj_type
;
2482 IMFMediaSource
*source
;
2486 /* If stream does not have content type set, try to guess from starting byte sequence. */
2487 if (FAILED(hr
= bytestream_get_url_hint(stream
, &url
)))
2490 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2494 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2497 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, stream
, url
, MF_RESOLUTION_MEDIASOURCE
, props
,
2498 &obj_type
, (IUnknown
**)&source
);
2499 IMFSourceResolver_Release(resolver
);
2501 IPropertyStore_Release(props
);
2505 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2506 IMFMediaSource_Release(source
);
2510 static HRESULT
create_source_reader_from_url(const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2512 IPropertyStore
*props
= NULL
;
2513 IMFSourceResolver
*resolver
;
2514 IUnknown
*object
= NULL
;
2515 MF_OBJECT_TYPE obj_type
;
2516 IMFMediaSource
*source
;
2519 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2523 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2526 hr
= IMFSourceResolver_CreateObjectFromURL(resolver
, url
, MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
,
2532 case MF_OBJECT_BYTESTREAM
:
2533 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, (IMFByteStream
*)object
, NULL
,
2534 MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
, (IUnknown
**)&source
);
2536 case MF_OBJECT_MEDIASOURCE
:
2537 source
= (IMFMediaSource
*)object
;
2538 IMFMediaSource_AddRef(source
);
2541 WARN("Unknown object type %d.\n", obj_type
);
2544 IUnknown_Release(object
);
2547 IMFSourceResolver_Release(resolver
);
2549 IPropertyStore_Release(props
);
2553 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2554 IMFMediaSource_Release(source
);
2558 static HRESULT
create_source_reader_from_object(IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2560 IMFMediaSource
*source
= NULL
;
2561 IMFByteStream
*stream
= NULL
;
2564 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSource
, (void **)&source
);
2566 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2570 UINT32 disconnect
= 0;
2573 IMFAttributes_GetUINT32(attributes
, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN
, &disconnect
);
2574 hr
= create_source_reader_from_source(source
, attributes
, !disconnect
, riid
, out
);
2577 hr
= create_source_reader_from_stream(stream
, attributes
, riid
, out
);
2580 IMFMediaSource_Release(source
);
2582 IMFByteStream_Release(stream
);
2587 /***********************************************************************
2588 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2590 HRESULT WINAPI
MFCreateSourceReaderFromByteStream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2591 IMFSourceReader
**reader
)
2593 TRACE("%p, %p, %p.\n", stream
, attributes
, reader
);
2595 return create_source_reader_from_object((IUnknown
*)stream
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2598 /***********************************************************************
2599 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2601 HRESULT WINAPI
MFCreateSourceReaderFromMediaSource(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2602 IMFSourceReader
**reader
)
2604 TRACE("%p, %p, %p.\n", source
, attributes
, reader
);
2606 return create_source_reader_from_object((IUnknown
*)source
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2609 /***********************************************************************
2610 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2612 HRESULT WINAPI
MFCreateSourceReaderFromURL(const WCHAR
*url
, IMFAttributes
*attributes
, IMFSourceReader
**reader
)
2614 TRACE("%s, %p, %p.\n", debugstr_w(url
), attributes
, reader
);
2616 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2619 static HRESULT WINAPI
readwrite_factory_QueryInterface(IMFReadWriteClassFactory
*iface
, REFIID riid
, void **out
)
2621 if (IsEqualIID(riid
, &IID_IMFReadWriteClassFactory
) ||
2622 IsEqualIID(riid
, &IID_IUnknown
))
2625 IMFReadWriteClassFactory_AddRef(iface
);
2629 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2631 return E_NOINTERFACE
;
2634 static ULONG WINAPI
readwrite_factory_AddRef(IMFReadWriteClassFactory
*iface
)
2639 static ULONG WINAPI
readwrite_factory_Release(IMFReadWriteClassFactory
*iface
)
2644 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2645 const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2647 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid
), debugstr_w(url
), attributes
, debugstr_guid(riid
), out
);
2649 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2651 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, out
);
2654 FIXME("Unsupported %s.\n", debugstr_guid(clsid
));
2659 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2660 IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2664 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid
), unk
, attributes
, debugstr_guid(riid
), out
);
2666 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2668 return create_source_reader_from_object(unk
, attributes
, riid
, out
);
2670 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2672 IMFByteStream
*stream
= NULL
;
2673 IMFMediaSink
*sink
= NULL
;
2675 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2677 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSink
, (void **)&sink
);
2680 hr
= create_sink_writer_from_stream(stream
, attributes
, riid
, out
);
2682 hr
= create_sink_writer_from_sink(sink
, attributes
, riid
, out
);
2685 IMFMediaSink_Release(sink
);
2687 IMFByteStream_Release(stream
);
2693 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2699 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl
=
2701 readwrite_factory_QueryInterface
,
2702 readwrite_factory_AddRef
,
2703 readwrite_factory_Release
,
2704 readwrite_factory_CreateInstanceFromURL
,
2705 readwrite_factory_CreateInstanceFromObject
,
2708 static IMFReadWriteClassFactory readwrite_factory
= { &readwrite_factory_vtbl
};
2710 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **out
)
2712 TRACE("%s, %p.\n", debugstr_guid(riid
), out
);
2714 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2715 IsEqualGUID(riid
, &IID_IUnknown
))
2717 IClassFactory_AddRef(iface
);
2722 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2724 return E_NOINTERFACE
;
2727 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2732 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2737 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **out
)
2739 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), out
);
2744 return CLASS_E_NOAGGREGATION
;
2746 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory
, riid
, out
);
2749 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2751 FIXME("%d.\n", dolock
);
2755 static const IClassFactoryVtbl classfactoryvtbl
=
2757 classfactory_QueryInterface
,
2758 classfactory_AddRef
,
2759 classfactory_Release
,
2760 classfactory_CreateInstance
,
2761 classfactory_LockServer
,
2764 static IClassFactory classfactory
= { &classfactoryvtbl
};
2766 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
2768 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
2770 if (IsEqualGUID(clsid
, &CLSID_MFReadWriteClassFactory
))
2771 return IClassFactory_QueryInterface(&classfactory
, riid
, out
);
2773 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2775 return CLASS_E_CLASSNOTAVAILABLE
;