3 * Copyright 2014 Austin English
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "mfreadwrite.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
40 #include "mf_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
44 struct stream_response
54 enum media_stream_state
56 STREAM_STATE_READY
= 0,
60 enum media_source_state
62 SOURCE_STATE_STOPPED
= 0,
66 enum media_stream_flags
68 STREAM_FLAG_SAMPLE_REQUESTED
= 0x1, /* Protects from making multiple sample requests. */
69 STREAM_FLAG_SELECTED
= 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
70 STREAM_FLAG_PRESENTED
= 0x4, /* Set if stream was selected last time Start() was called. */
71 STREAM_FLAG_STOPPED
= 0x8, /* Received MEStreamStopped */
74 struct transform_entry
77 IMFTransform
*transform
;
78 unsigned int min_buffer_size
;
85 IMFMediaStream
*stream
;
86 IMFMediaType
*current
;
87 struct list transforms
;
88 IMFVideoSampleAllocatorEx
*allocator
;
89 IMFTransform
*transform_service
;
92 enum media_stream_state state
;
94 unsigned int requests
;
95 unsigned int responses
;
96 LONGLONG last_sample_ts
;
97 struct source_reader
*reader
;
100 enum source_reader_async_op
102 SOURCE_READER_ASYNC_READ
,
103 SOURCE_READER_ASYNC_SEEK
,
104 SOURCE_READER_ASYNC_FLUSH
,
105 SOURCE_READER_ASYNC_SAMPLE_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 IMFSourceReaderEx IMFSourceReaderEx_iface
;
153 IMFAsyncCallback source_events_callback
;
154 IMFAsyncCallback stream_events_callback
;
155 IMFAsyncCallback async_commands_callback
;
157 LONG public_refcount
;
158 IMFMediaSource
*source
;
159 IMFPresentationDescriptor
*descriptor
;
160 IMFSourceReaderCallback
*async_callback
;
161 IMFAttributes
*attributes
;
162 IUnknown
*device_manager
;
163 unsigned int first_audio_stream_index
;
164 unsigned int first_video_stream_index
;
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
;
174 CONDITION_VARIABLE stop_event
;
177 static inline struct source_reader
*impl_from_IMFSourceReaderEx(IMFSourceReaderEx
*iface
)
179 return CONTAINING_RECORD(iface
, struct source_reader
, IMFSourceReaderEx_iface
);
182 static struct source_reader
*impl_from_source_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
184 return CONTAINING_RECORD(iface
, struct source_reader
, source_events_callback
);
187 static struct source_reader
*impl_from_stream_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
189 return CONTAINING_RECORD(iface
, struct source_reader
, stream_events_callback
);
192 static struct source_reader
*impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
194 return CONTAINING_RECORD(iface
, struct source_reader
, async_commands_callback
);
197 static struct source_reader_async_command
*impl_from_async_command_IUnknown(IUnknown
*iface
)
199 return CONTAINING_RECORD(iface
, struct source_reader_async_command
, IUnknown_iface
);
202 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
);
204 static ULONG
source_reader_addref(struct source_reader
*reader
)
206 return InterlockedIncrement(&reader
->refcount
);
209 static void transform_entry_destroy(struct transform_entry
*entry
)
211 IMFTransform_Release(entry
->transform
);
215 static void media_stream_destroy(struct media_stream
*stream
)
217 struct transform_entry
*entry
, *next
;
219 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &stream
->transforms
, struct transform_entry
, entry
)
221 list_remove(&entry
->entry
);
222 transform_entry_destroy(entry
);
226 IMFMediaStream_Release(stream
->stream
);
228 IMFMediaType_Release(stream
->current
);
229 if (stream
->allocator
)
230 IMFVideoSampleAllocatorEx_Release(stream
->allocator
);
233 static ULONG
source_reader_release(struct source_reader
*reader
)
235 ULONG refcount
= InterlockedDecrement(&reader
->refcount
);
240 if (reader
->device_manager
)
241 IUnknown_Release(reader
->device_manager
);
242 if (reader
->async_callback
)
243 IMFSourceReaderCallback_Release(reader
->async_callback
);
244 if (reader
->descriptor
)
245 IMFPresentationDescriptor_Release(reader
->descriptor
);
246 if (reader
->attributes
)
247 IMFAttributes_Release(reader
->attributes
);
248 IMFMediaSource_Release(reader
->source
);
250 for (i
= 0; i
< reader
->stream_count
; ++i
)
252 struct media_stream
*stream
= &reader
->streams
[i
];
253 media_stream_destroy(stream
);
255 source_reader_release_responses(reader
, NULL
);
256 free(reader
->streams
);
257 MFUnlockWorkQueue(reader
->queue
);
258 DeleteCriticalSection(&reader
->cs
);
265 static HRESULT WINAPI
source_reader_async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
267 if (IsEqualIID(riid
, &IID_IUnknown
))
270 IUnknown_AddRef(iface
);
274 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
276 return E_NOINTERFACE
;
279 static ULONG WINAPI
source_reader_async_command_AddRef(IUnknown
*iface
)
281 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
282 return InterlockedIncrement(&command
->refcount
);
285 static ULONG WINAPI
source_reader_async_command_Release(IUnknown
*iface
)
287 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
288 ULONG refcount
= InterlockedIncrement(&command
->refcount
);
292 if (command
->op
== SOURCE_READER_ASYNC_SEEK
)
293 PropVariantClear(&command
->u
.seek
.position
);
300 static const IUnknownVtbl source_reader_async_command_vtbl
=
302 source_reader_async_command_QueryInterface
,
303 source_reader_async_command_AddRef
,
304 source_reader_async_command_Release
,
307 static HRESULT
source_reader_create_async_op(enum source_reader_async_op op
, struct source_reader_async_command
**ret
)
309 struct source_reader_async_command
*command
;
311 if (!(command
= calloc(1, sizeof(*command
))))
312 return E_OUTOFMEMORY
;
314 command
->IUnknown_iface
.lpVtbl
= &source_reader_async_command_vtbl
;
322 static HRESULT
media_event_get_object(IMFMediaEvent
*event
, REFIID riid
, void **obj
)
327 PropVariantInit(&value
);
328 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
330 WARN("Failed to get event value, hr %#lx.\n", hr
);
334 if (value
.vt
!= VT_UNKNOWN
|| !value
.punkVal
)
336 WARN("Unexpected value type %d.\n", value
.vt
);
337 PropVariantClear(&value
);
341 hr
= IUnknown_QueryInterface(value
.punkVal
, riid
, obj
);
342 PropVariantClear(&value
);
345 WARN("Unexpected object type.\n");
352 static HRESULT
media_stream_get_id(IMFMediaStream
*stream
, DWORD
*id
)
354 IMFStreamDescriptor
*sd
;
357 if (SUCCEEDED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
359 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, id
);
360 IMFStreamDescriptor_Release(sd
);
366 static HRESULT WINAPI
source_reader_callback_QueryInterface(IMFAsyncCallback
*iface
,
367 REFIID riid
, void **obj
)
369 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
371 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
372 IsEqualIID(riid
, &IID_IUnknown
))
375 IMFAsyncCallback_AddRef(iface
);
379 WARN("Unsupported %s.\n", debugstr_guid(riid
));
381 return E_NOINTERFACE
;
384 static ULONG WINAPI
source_reader_source_events_callback_AddRef(IMFAsyncCallback
*iface
)
386 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
387 return source_reader_addref(reader
);
390 static ULONG WINAPI
source_reader_source_events_callback_Release(IMFAsyncCallback
*iface
)
392 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
393 return source_reader_release(reader
);
396 static HRESULT WINAPI
source_reader_callback_GetParameters(IMFAsyncCallback
*iface
,
397 DWORD
*flags
, DWORD
*queue
)
402 static void source_reader_response_ready(struct source_reader
*reader
, struct stream_response
*response
)
404 struct source_reader_async_command
*command
;
405 struct media_stream
*stream
= &reader
->streams
[response
->stream_index
];
408 if (!stream
->requests
)
411 if (reader
->async_callback
)
413 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY
, &command
)))
415 command
->u
.sample
.stream_index
= stream
->index
;
416 if (FAILED(hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
)))
417 WARN("Failed to submit async result, hr %#lx.\n", hr
);
418 IUnknown_Release(&command
->IUnknown_iface
);
422 WakeAllConditionVariable(&reader
->sample_event
);
427 static void source_reader_copy_sample_buffer(IMFSample
*src
, IMFSample
*dst
)
429 IMFMediaBuffer
*buffer
;
434 IMFSample_CopyAllItems(src
, (IMFAttributes
*)dst
);
436 IMFSample_SetSampleDuration(dst
, 0);
437 IMFSample_SetSampleTime(dst
, 0);
438 IMFSample_SetSampleFlags(dst
, 0);
440 if (SUCCEEDED(IMFSample_GetSampleDuration(src
, &time
)))
441 IMFSample_SetSampleDuration(dst
, time
);
443 if (SUCCEEDED(IMFSample_GetSampleTime(src
, &time
)))
444 IMFSample_SetSampleTime(dst
, time
);
446 if (SUCCEEDED(IMFSample_GetSampleFlags(src
, &flags
)))
447 IMFSample_SetSampleFlags(dst
, flags
);
449 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src
, NULL
)))
451 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst
, 0, &buffer
)))
453 if (FAILED(hr
= IMFSample_CopyToBuffer(src
, buffer
)))
454 WARN("Failed to copy a buffer, hr %#lx.\n", hr
);
455 IMFMediaBuffer_Release(buffer
);
460 static HRESULT
source_reader_queue_response(struct source_reader
*reader
, struct media_stream
*stream
, HRESULT status
,
461 DWORD stream_flags
, LONGLONG timestamp
, IMFSample
*sample
)
463 struct stream_response
*response
;
465 if (!(response
= calloc(1, sizeof(*response
))))
466 return E_OUTOFMEMORY
;
468 response
->status
= status
;
469 response
->stream_index
= stream
->index
;
470 response
->stream_flags
= stream_flags
;
471 response
->timestamp
= timestamp
;
472 response
->sample
= sample
;
473 if (response
->sample
)
474 IMFSample_AddRef(response
->sample
);
476 list_add_tail(&reader
->responses
, &response
->entry
);
479 source_reader_response_ready(reader
, response
);
481 stream
->last_sample_ts
= timestamp
;
486 static HRESULT
source_reader_queue_sample(struct source_reader
*reader
, struct media_stream
*stream
,
489 LONGLONG timestamp
= 0;
491 if (FAILED(IMFSample_GetSampleTime(sample
, ×tamp
)))
492 WARN("Sample time wasn't set.\n");
494 return source_reader_queue_response(reader
, stream
, S_OK
, 0, timestamp
, sample
);
497 static HRESULT
source_reader_request_sample(struct source_reader
*reader
, struct media_stream
*stream
)
501 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
503 if (FAILED(hr
= IMFMediaStream_RequestSample(stream
->stream
, NULL
)))
504 WARN("Sample request failed, hr %#lx.\n", hr
);
507 stream
->flags
|= STREAM_FLAG_SAMPLE_REQUESTED
;
514 static HRESULT
source_reader_new_stream_handler(struct source_reader
*reader
, IMFMediaEvent
*event
)
516 IMFMediaStream
*stream
;
521 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFMediaStream
, (void **)&stream
)))
523 WARN("Failed to get stream object, hr %#lx.\n", hr
);
527 TRACE("Got new stream %p.\n", stream
);
529 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
531 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
532 IMFMediaStream_Release(stream
);
536 EnterCriticalSection(&reader
->cs
);
538 for (i
= 0; i
< reader
->stream_count
; ++i
)
540 if (id
== reader
->streams
[i
].id
)
542 if (!reader
->streams
[i
].stream
)
544 reader
->streams
[i
].stream
= stream
;
545 IMFMediaStream_AddRef(reader
->streams
[i
].stream
);
546 if (FAILED(hr
= IMFMediaStream_BeginGetEvent(stream
, &reader
->stream_events_callback
,
547 (IUnknown
*)stream
)))
549 WARN("Failed to subscribe to stream events, hr %#lx.\n", hr
);
552 if (reader
->streams
[i
].requests
)
553 if (FAILED(source_reader_request_sample(reader
, &reader
->streams
[i
])))
554 WakeAllConditionVariable(&reader
->sample_event
);
560 if (i
== reader
->stream_count
)
561 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id
);
563 LeaveCriticalSection(&reader
->cs
);
565 IMFMediaStream_Release(stream
);
570 static HRESULT
source_reader_source_state_handler(struct source_reader
*reader
, MediaEventType event_type
)
572 EnterCriticalSection(&reader
->cs
);
576 case MESourceStarted
:
577 reader
->source_state
= SOURCE_STATE_STARTED
;
578 reader
->flags
&= ~SOURCE_READER_SEEKING
;
580 case MESourceStopped
:
581 reader
->source_state
= SOURCE_STATE_STOPPED
;
582 reader
->flags
&= ~SOURCE_READER_SEEKING
;
585 reader
->flags
&= ~SOURCE_READER_SEEKING
;
588 WARN("Unhandled event %ld.\n", event_type
);
591 LeaveCriticalSection(&reader
->cs
);
593 WakeAllConditionVariable(&reader
->state_event
);
594 if (event_type
== MESourceStopped
)
595 WakeAllConditionVariable(&reader
->stop_event
);
600 static HRESULT WINAPI
source_reader_source_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
602 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
603 MediaEventType event_type
;
604 IMFMediaSource
*source
;
605 IMFMediaEvent
*event
;
608 TRACE("%p, %p.\n", iface
, result
);
610 source
= (IMFMediaSource
*)IMFAsyncResult_GetStateNoAddRef(result
);
612 if (FAILED(hr
= IMFMediaSource_EndGetEvent(source
, result
, &event
)))
615 IMFMediaEvent_GetType(event
, &event_type
);
617 TRACE("Got event %lu.\n", event_type
);
622 hr
= source_reader_new_stream_handler(reader
, event
);
624 case MESourceStarted
:
626 case MESourceStopped
:
628 hr
= source_reader_source_state_handler(reader
, event_type
);
630 case MEBufferingStarted
:
631 case MEBufferingStopped
:
635 case MESourceCharacteristicsChanged
:
636 case MESourceMetadataChanged
:
637 case MEContentProtectionMetadata
:
638 case MEDeviceThermalStateChanged
:
639 if (reader
->async_callback
)
640 IMFSourceReaderCallback_OnEvent(reader
->async_callback
, MF_SOURCE_READER_MEDIASOURCE
, event
);
647 WARN("Failed while handling %ld event, hr %#lx.\n", event_type
, hr
);
649 IMFMediaEvent_Release(event
);
651 if (event_type
!= MESourceStopped
)
652 IMFMediaSource_BeginGetEvent(source
, iface
, (IUnknown
*)source
);
657 static const IMFAsyncCallbackVtbl source_events_callback_vtbl
=
659 source_reader_callback_QueryInterface
,
660 source_reader_source_events_callback_AddRef
,
661 source_reader_source_events_callback_Release
,
662 source_reader_callback_GetParameters
,
663 source_reader_source_events_callback_Invoke
,
666 static ULONG WINAPI
source_reader_stream_events_callback_AddRef(IMFAsyncCallback
*iface
)
668 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
669 return source_reader_addref(reader
);
672 static ULONG WINAPI
source_reader_stream_events_callback_Release(IMFAsyncCallback
*iface
)
674 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
675 return source_reader_release(reader
);
678 static HRESULT
source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO
*info
, IMFSample
**out
)
680 IMFMediaBuffer
*buffer
;
685 if (FAILED(hr
= MFCreateSample(&sample
)))
687 if (SUCCEEDED(hr
= MFCreateAlignedMemoryBuffer(info
->cbSize
, info
->cbAlignment
, &buffer
)))
689 if (SUCCEEDED(hr
= IMFSample_AddBuffer(sample
, buffer
)))
692 IMFSample_AddRef(sample
);
694 IMFMediaBuffer_Release(buffer
);
697 IMFSample_Release(sample
);
701 static void media_type_try_copy_attr(IMFMediaType
*dst
, IMFMediaType
*src
, const GUID
*attr
, HRESULT
*hr
)
705 PropVariantInit(&value
);
706 if (SUCCEEDED(*hr
) && FAILED(IMFMediaType_GetItem(dst
, attr
, NULL
))
707 && SUCCEEDED(IMFMediaType_GetItem(src
, attr
, &value
)))
708 *hr
= IMFMediaType_SetItem(dst
, attr
, &value
);
709 PropVariantClear(&value
);
712 /* update a media type with additional attributes reported by upstream element */
713 /* also present in mf/topology_loader.c pipeline */
714 static HRESULT
update_media_type_from_upstream(IMFMediaType
*media_type
, IMFMediaType
*upstream_type
)
718 /* propagate common video attributes */
719 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FRAME_SIZE
, &hr
);
720 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FRAME_RATE
, &hr
);
721 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_DEFAULT_STRIDE
, &hr
);
722 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_ROTATION
, &hr
);
723 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FIXED_SIZE_SAMPLES
, &hr
);
724 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_PIXEL_ASPECT_RATIO
, &hr
);
725 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, &hr
);
726 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
, &hr
);
728 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_CHROMA_SITING
, &hr
);
729 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_INTERLACE_MODE
, &hr
);
730 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_TRANSFER_FUNCTION
, &hr
);
731 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_PRIMARIES
, &hr
);
732 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_YUV_MATRIX
, &hr
);
733 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_LIGHTING
, &hr
);
734 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_NOMINAL_RANGE
, &hr
);
736 /* propagate common audio attributes */
737 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_NUM_CHANNELS
, &hr
);
738 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &hr
);
739 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_BITS_PER_SAMPLE
, &hr
);
740 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_SAMPLES_PER_SECOND
, &hr
);
741 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
, &hr
);
742 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_CHANNEL_MASK
, &hr
);
743 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_SAMPLES_PER_BLOCK
, &hr
);
744 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE
, &hr
);
749 static HRESULT
source_reader_pull_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
750 struct transform_entry
*entry
);
751 static HRESULT
source_reader_push_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
752 struct transform_entry
*entry
, IMFSample
*sample
)
758 if (FAILED(hr
= source_reader_pull_transform_samples(reader
, stream
, entry
))
759 && hr
!= MF_E_TRANSFORM_NEED_MORE_INPUT
)
761 if (SUCCEEDED(hr
= IMFTransform_ProcessInput(entry
->transform
, 0, sample
, 0)))
762 return source_reader_pull_transform_samples(reader
, stream
, entry
);
764 while (hr
== MF_E_NOTACCEPTING
);
769 static HRESULT
source_reader_pull_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
770 struct transform_entry
*entry
)
772 MFT_OUTPUT_STREAM_INFO stream_info
= {0};
773 struct transform_entry
*next
= NULL
;
778 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
779 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
781 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(entry
->transform
, 0, &stream_info
)))
783 stream_info
.cbSize
= max(stream_info
.cbSize
, entry
->min_buffer_size
);
785 while (SUCCEEDED(hr
))
787 MFT_OUTPUT_DATA_BUFFER out_buffer
= {0};
789 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
))
790 && FAILED(hr
= source_reader_allocate_stream_sample(&stream_info
, &out_buffer
.pSample
)))
793 if (SUCCEEDED(hr
= IMFTransform_ProcessOutput(entry
->transform
, 0, 1, &out_buffer
, &status
)))
796 hr
= source_reader_push_transform_samples(reader
, stream
, next
, out_buffer
.pSample
);
798 hr
= source_reader_queue_sample(reader
, stream
, out_buffer
.pSample
);
801 if (out_buffer
.pSample
)
802 IMFSample_Release(out_buffer
.pSample
);
803 if (out_buffer
.pEvents
)
804 IMFCollection_Release(out_buffer
.pEvents
);
810 static HRESULT
source_reader_drain_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
811 struct transform_entry
*entry
)
813 struct transform_entry
*next
= NULL
;
817 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
818 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
820 if (FAILED(hr
= IMFTransform_ProcessMessage(entry
->transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
821 WARN("Failed to drain transform %p, hr %#lx\n", entry
->transform
, hr
);
822 if (FAILED(hr
= source_reader_pull_transform_samples(reader
, stream
, entry
))
823 && hr
!= MF_E_TRANSFORM_NEED_MORE_INPUT
)
824 WARN("Failed to pull pending samples, hr %#lx.\n", hr
);
826 return next
? source_reader_drain_transform_samples(reader
, stream
, next
) : S_OK
;
829 static HRESULT
source_reader_flush_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
830 struct transform_entry
*entry
)
832 struct transform_entry
*next
= NULL
;
836 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
837 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
839 if (FAILED(hr
= IMFTransform_ProcessMessage(entry
->transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0)))
840 WARN("Failed to flush transform %p, hr %#lx\n", entry
->transform
, hr
);
842 return next
? source_reader_flush_transform_samples(reader
, stream
, next
) : S_OK
;
845 static HRESULT
source_reader_process_sample(struct source_reader
*reader
, struct media_stream
*stream
,
848 struct transform_entry
*entry
;
852 if (!(ptr
= list_head(&stream
->transforms
)))
853 return source_reader_queue_sample(reader
, stream
, sample
);
854 entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
856 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
857 if (SUCCEEDED(hr
= source_reader_push_transform_samples(reader
, stream
, entry
, sample
))
858 || hr
== MF_E_TRANSFORM_NEED_MORE_INPUT
)
859 hr
= stream
->requests
? source_reader_request_sample(reader
, stream
) : S_OK
;
861 WARN("Transform failed to process output, hr %#lx.\n", hr
);
866 static HRESULT
source_reader_media_sample_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
867 IMFMediaEvent
*event
)
874 TRACE("Got new sample for stream %p.\n", stream
);
876 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFSample
, (void **)&sample
)))
878 WARN("Failed to get sample object, hr %#lx.\n", hr
);
882 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
884 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
885 IMFSample_Release(sample
);
889 EnterCriticalSection(&reader
->cs
);
891 for (i
= 0; i
< reader
->stream_count
; ++i
)
893 if (id
== reader
->streams
[i
].id
)
895 /* FIXME: propagate processing errors? */
896 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
897 hr
= source_reader_process_sample(reader
, &reader
->streams
[i
], sample
);
902 if (i
== reader
->stream_count
)
903 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id
);
905 LeaveCriticalSection(&reader
->cs
);
907 IMFSample_Release(sample
);
912 static HRESULT
source_reader_media_stream_state_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
913 IMFMediaEvent
*event
)
915 MediaEventType event_type
;
922 IMFMediaEvent_GetType(event
, &event_type
);
924 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
926 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
930 EnterCriticalSection(&reader
->cs
);
932 for (i
= 0; i
< reader
->stream_count
; ++i
)
934 struct media_stream
*stream
= &reader
->streams
[i
];
936 if (id
== stream
->id
)
944 stream
->state
= STREAM_STATE_EOS
;
945 stream
->flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
947 if ((ptr
= list_head(&stream
->transforms
)))
949 struct transform_entry
*entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
950 if (FAILED(hr
= source_reader_drain_transform_samples(reader
, stream
, entry
)))
951 WARN("Failed to drain pending samples, hr %#lx.\n", hr
);
954 while (stream
->requests
)
955 source_reader_queue_response(reader
, stream
, S_OK
, MF_SOURCE_READERF_ENDOFSTREAM
, 0, NULL
);
960 case MEStreamStarted
:
961 stream
->state
= STREAM_STATE_READY
;
963 case MEStreamStopped
:
964 stream
->flags
|= STREAM_FLAG_STOPPED
;
968 hr
= SUCCEEDED(IMFMediaEvent_GetValue(event
, &value
)) && value
.vt
== VT_I8
? S_OK
: E_UNEXPECTED
;
969 timestamp
= SUCCEEDED(hr
) ? value
.hVal
.QuadPart
: 0;
970 PropVariantClear(&value
);
972 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_STREAMTICK
, timestamp
, NULL
);
983 LeaveCriticalSection(&reader
->cs
);
985 if (event_type
== MEStreamStopped
)
986 WakeAllConditionVariable(&reader
->stop_event
);
991 static HRESULT WINAPI
source_reader_stream_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
993 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
994 MediaEventType event_type
;
995 IMFMediaStream
*stream
;
996 IMFMediaEvent
*event
;
999 TRACE("%p, %p.\n", iface
, result
);
1001 stream
= (IMFMediaStream
*)IMFAsyncResult_GetStateNoAddRef(result
);
1003 if (FAILED(hr
= IMFMediaStream_EndGetEvent(stream
, result
, &event
)))
1006 IMFMediaEvent_GetType(event
, &event_type
);
1008 TRACE("Got event %lu.\n", event_type
);
1013 hr
= source_reader_media_sample_handler(reader
, stream
, event
);
1015 case MEStreamSeeked
:
1016 case MEStreamStarted
:
1017 case MEStreamStopped
:
1020 hr
= source_reader_media_stream_state_handler(reader
, stream
, event
);
1027 WARN("Failed while handling %ld event, hr %#lx.\n", event_type
, hr
);
1029 IMFMediaEvent_Release(event
);
1031 if (event_type
!= MEStreamStopped
)
1032 IMFMediaStream_BeginGetEvent(stream
, iface
, (IUnknown
*)stream
);
1037 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl
=
1039 source_reader_callback_QueryInterface
,
1040 source_reader_stream_events_callback_AddRef
,
1041 source_reader_stream_events_callback_Release
,
1042 source_reader_callback_GetParameters
,
1043 source_reader_stream_events_callback_Invoke
,
1046 static ULONG WINAPI
source_reader_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
1048 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1049 return source_reader_addref(reader
);
1052 static ULONG WINAPI
source_reader_async_commands_callback_Release(IMFAsyncCallback
*iface
)
1054 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1055 return source_reader_release(reader
);
1058 static struct stream_response
* media_stream_detach_response(struct source_reader
*reader
, struct stream_response
*response
)
1060 struct media_stream
*stream
;
1062 list_remove(&response
->entry
);
1064 if (response
->stream_index
< reader
->stream_count
)
1066 stream
= &reader
->streams
[response
->stream_index
];
1067 if (stream
->responses
)
1068 --stream
->responses
;
1074 static struct stream_response
*media_stream_pop_response(struct source_reader
*reader
, struct media_stream
*stream
)
1076 struct stream_response
*response
;
1080 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1082 if (stream
&& response
->stream_index
!= stream
->index
)
1085 if (!stream
) stream
= &reader
->streams
[response
->stream_index
];
1087 if (response
->sample
&& stream
->allocator
)
1089 /* Return allocation error to the caller, while keeping original response sample in for later. */
1090 if (SUCCEEDED(hr
= IMFVideoSampleAllocatorEx_AllocateSample(stream
->allocator
, &sample
)))
1092 source_reader_copy_sample_buffer(response
->sample
, sample
);
1093 IMFSample_Release(response
->sample
);
1094 response
->sample
= sample
;
1098 if (!(response
= calloc(1, sizeof(*response
))))
1101 response
->status
= hr
;
1102 response
->stream_flags
= MF_SOURCE_READERF_ERROR
;
1107 return media_stream_detach_response(reader
, response
);
1113 static void source_reader_release_response(struct stream_response
*response
)
1115 if (response
->sample
)
1116 IMFSample_Release(response
->sample
);
1120 static HRESULT
source_reader_get_stream_selection(const struct source_reader
*reader
, DWORD index
, BOOL
*selected
)
1122 IMFStreamDescriptor
*sd
;
1124 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, selected
, &sd
)))
1125 return MF_E_INVALIDSTREAMNUMBER
;
1126 IMFStreamDescriptor_Release(sd
);
1131 static HRESULT
source_reader_start_source(struct source_reader
*reader
)
1133 BOOL selected
, selection_changed
= FALSE
;
1134 PROPVARIANT position
;
1138 for (i
= 0; i
< reader
->stream_count
; ++i
)
1140 source_reader_get_stream_selection(reader
, i
, &selected
);
1142 reader
->streams
[i
].flags
|= STREAM_FLAG_SELECTED
;
1144 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SELECTED
;
1147 if (reader
->source_state
== SOURCE_STATE_STARTED
)
1149 for (i
= 0; i
< reader
->stream_count
; ++i
)
1151 selection_changed
= !!(reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
) ^
1152 !!(reader
->streams
[i
].flags
& STREAM_FLAG_PRESENTED
);
1153 if (selection_changed
)
1158 position
.hVal
.QuadPart
= 0;
1159 if (reader
->source_state
!= SOURCE_STATE_STARTED
|| selection_changed
)
1161 position
.vt
= reader
->source_state
== SOURCE_STATE_STARTED
? VT_EMPTY
: VT_I8
;
1163 /* Update cached stream selection if descriptor was accepted. */
1164 if (SUCCEEDED(hr
= IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &GUID_NULL
, &position
)))
1166 for (i
= 0; i
< reader
->stream_count
; ++i
)
1168 if (reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
)
1169 reader
->streams
[i
].flags
|= STREAM_FLAG_PRESENTED
;
1177 static BOOL
source_reader_got_response_for_stream(struct source_reader
*reader
, struct media_stream
*stream
)
1179 struct stream_response
*response
;
1181 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1183 if (response
->stream_index
== stream
->index
)
1190 static BOOL
source_reader_get_read_result(struct source_reader
*reader
, struct media_stream
*stream
, DWORD flags
,
1191 HRESULT
*status
, DWORD
*stream_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1193 struct stream_response
*response
= NULL
;
1194 BOOL request_sample
= FALSE
;
1196 if ((response
= media_stream_pop_response(reader
, stream
)))
1198 *status
= response
->status
;
1199 *stream_index
= stream
->index
;
1200 *stream_flags
= response
->stream_flags
;
1201 *timestamp
= response
->timestamp
;
1202 *sample
= response
->sample
;
1204 IMFSample_AddRef(*sample
);
1206 source_reader_release_response(response
);
1211 *stream_index
= stream
->index
;
1215 if (stream
->state
== STREAM_STATE_EOS
)
1217 *stream_flags
= MF_SOURCE_READERF_ENDOFSTREAM
;
1221 request_sample
= !(flags
& MF_SOURCE_READER_CONTROLF_DRAIN
);
1226 return !request_sample
;
1229 static HRESULT
source_reader_get_next_selected_stream(struct source_reader
*reader
, DWORD
*stream_index
)
1231 unsigned int i
, first_selected
= ~0u;
1232 BOOL selected
, stream_drained
;
1233 LONGLONG min_ts
= MAXLONGLONG
;
1235 for (i
= 0; i
< reader
->stream_count
; ++i
)
1237 stream_drained
= reader
->streams
[i
].state
== STREAM_STATE_EOS
&& !reader
->streams
[i
].responses
;
1238 selected
= SUCCEEDED(source_reader_get_stream_selection(reader
, i
, &selected
)) && selected
;
1242 if (first_selected
== ~0u)
1245 /* Pick the stream whose last sample had the lowest timestamp. */
1246 if (!stream_drained
&& reader
->streams
[i
].last_sample_ts
< min_ts
)
1248 min_ts
= reader
->streams
[i
].last_sample_ts
;
1254 /* If all selected streams reached EOS, use first selected. */
1255 if (first_selected
!= ~0u)
1257 if (min_ts
== MAXLONGLONG
)
1258 *stream_index
= first_selected
;
1261 return first_selected
== ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED
: S_OK
;
1264 static HRESULT
source_reader_get_stream_read_index(struct source_reader
*reader
, unsigned int index
, DWORD
*stream_index
)
1271 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1272 *stream_index
= reader
->first_video_stream_index
;
1274 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1275 *stream_index
= reader
->first_audio_stream_index
;
1277 case MF_SOURCE_READER_ANY_STREAM
:
1278 return source_reader_get_next_selected_stream(reader
, stream_index
);
1280 *stream_index
= index
;
1283 /* Can't read from deselected streams. */
1284 if (SUCCEEDED(hr
= source_reader_get_stream_selection(reader
, *stream_index
, &selected
)) && !selected
)
1285 hr
= MF_E_INVALIDREQUEST
;
1290 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
)
1292 struct stream_response
*ptr
, *next
;
1294 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &reader
->responses
, struct stream_response
, entry
)
1296 if (stream
&& stream
->index
!= ptr
->stream_index
&&
1297 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_VIDEO_STREAM
&&
1298 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_AUDIO_STREAM
&&
1299 ptr
->stream_index
!= MF_SOURCE_READER_ANY_STREAM
)
1303 media_stream_detach_response(reader
, ptr
);
1304 source_reader_release_response(ptr
);
1308 static void source_reader_flush_stream(struct source_reader
*reader
, DWORD stream_index
)
1310 struct media_stream
*stream
= &reader
->streams
[stream_index
];
1314 source_reader_release_responses(reader
, stream
);
1316 if ((ptr
= list_head(&stream
->transforms
)))
1318 struct transform_entry
*entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
1319 if (FAILED(hr
= source_reader_flush_transform_samples(reader
, stream
, entry
)))
1320 WARN("Failed to drain pending samples, hr %#lx.\n", hr
);
1323 stream
->requests
= 0;
1326 static HRESULT
source_reader_flush(struct source_reader
*reader
, unsigned int index
)
1328 unsigned int stream_index
;
1331 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1333 for (stream_index
= 0; stream_index
< reader
->stream_count
; ++stream_index
)
1334 source_reader_flush_stream(reader
, stream_index
);
1340 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1341 stream_index
= reader
->first_video_stream_index
;
1343 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1344 stream_index
= reader
->first_audio_stream_index
;
1347 stream_index
= index
;
1350 if (stream_index
< reader
->stream_count
)
1351 source_reader_flush_stream(reader
, stream_index
);
1353 hr
= MF_E_INVALIDSTREAMNUMBER
;
1359 static HRESULT WINAPI
source_reader_async_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1361 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1362 struct media_stream
*stream
, stub_stream
= { .requests
= 1 };
1363 struct source_reader_async_command
*command
;
1364 struct stream_response
*response
;
1365 DWORD stream_index
, stream_flags
;
1366 BOOL report_sample
= FALSE
;
1367 IMFSample
*sample
= NULL
;
1368 LONGLONG timestamp
= 0;
1372 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
1375 command
= impl_from_async_command_IUnknown(state
);
1377 switch (command
->op
)
1379 case SOURCE_READER_ASYNC_READ
:
1380 EnterCriticalSection(&reader
->cs
);
1382 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1384 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, command
->u
.read
.stream_index
, &stream_index
)))
1386 stream
= &reader
->streams
[stream_index
];
1388 if (!(report_sample
= source_reader_get_read_result(reader
, stream
, command
->u
.read
.flags
, &status
,
1389 &stream_index
, &stream_flags
, ×tamp
, &sample
)))
1392 source_reader_request_sample(reader
, stream
);
1393 /* FIXME: set error stream/reader state on request failure */
1398 stub_stream
.index
= command
->u
.read
.stream_index
;
1399 source_reader_queue_response(reader
, &stub_stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
1403 LeaveCriticalSection(&reader
->cs
);
1406 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, status
, stream_index
, stream_flags
,
1410 IMFSample_Release(sample
);
1414 case SOURCE_READER_ASYNC_SEEK
:
1416 EnterCriticalSection(&reader
->cs
);
1417 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &command
->u
.seek
.format
,
1418 &command
->u
.seek
.position
)))
1420 reader
->flags
|= SOURCE_READER_SEEKING
;
1422 LeaveCriticalSection(&reader
->cs
);
1426 case SOURCE_READER_ASYNC_SAMPLE_READY
:
1428 EnterCriticalSection(&reader
->cs
);
1429 response
= media_stream_pop_response(reader
, NULL
);
1430 LeaveCriticalSection(&reader
->cs
);
1434 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, response
->status
, response
->stream_index
,
1435 response
->stream_flags
, response
->timestamp
, response
->sample
);
1436 source_reader_release_response(response
);
1440 case SOURCE_READER_ASYNC_FLUSH
:
1441 EnterCriticalSection(&reader
->cs
);
1442 source_reader_flush(reader
, command
->u
.flush
.stream_index
);
1443 reader
->flags
&= ~SOURCE_READER_FLUSHING
;
1444 LeaveCriticalSection(&reader
->cs
);
1446 IMFSourceReaderCallback_OnFlush(reader
->async_callback
, command
->u
.flush
.stream_index
);
1452 IUnknown_Release(state
);
1457 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl
=
1459 source_reader_callback_QueryInterface
,
1460 source_reader_async_commands_callback_AddRef
,
1461 source_reader_async_commands_callback_Release
,
1462 source_reader_callback_GetParameters
,
1463 source_reader_async_commands_callback_Invoke
,
1466 static HRESULT WINAPI
src_reader_QueryInterface(IMFSourceReaderEx
*iface
, REFIID riid
, void **out
)
1468 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1470 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1472 if (IsEqualGUID(riid
, &IID_IUnknown
)
1473 || IsEqualGUID(riid
, &IID_IMFSourceReader
)
1474 || IsEqualGUID(riid
, &IID_IMFSourceReaderEx
))
1476 *out
= &reader
->IMFSourceReaderEx_iface
;
1480 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1482 return E_NOINTERFACE
;
1485 IUnknown_AddRef((IUnknown
*)*out
);
1489 static ULONG WINAPI
src_reader_AddRef(IMFSourceReaderEx
*iface
)
1491 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1492 ULONG refcount
= InterlockedIncrement(&reader
->public_refcount
);
1494 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1499 static BOOL
source_reader_is_source_stopped(const struct source_reader
*reader
)
1503 if (reader
->source_state
!= SOURCE_STATE_STOPPED
)
1506 for (i
= 0; i
< reader
->stream_count
; ++i
)
1508 if (reader
->streams
[i
].stream
&& !(reader
->streams
[i
].flags
& STREAM_FLAG_STOPPED
))
1515 static ULONG WINAPI
src_reader_Release(IMFSourceReaderEx
*iface
)
1517 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1518 ULONG refcount
= InterlockedDecrement(&reader
->public_refcount
);
1521 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1525 if (reader
->flags
& SOURCE_READER_SHUTDOWN_ON_RELEASE
)
1526 IMFMediaSource_Shutdown(reader
->source
);
1527 else if (SUCCEEDED(IMFMediaSource_Stop(reader
->source
)))
1529 EnterCriticalSection(&reader
->cs
);
1531 while (!source_reader_is_source_stopped(reader
))
1533 SleepConditionVariableCS(&reader
->stop_event
, &reader
->cs
, INFINITE
);
1536 LeaveCriticalSection(&reader
->cs
);
1539 for (i
= 0; i
< reader
->stream_count
; ++i
)
1541 struct media_stream
*stream
= &reader
->streams
[i
];
1542 IMFVideoSampleAllocatorCallback
*callback
;
1544 if (!stream
->allocator
)
1547 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream
->allocator
, &IID_IMFVideoSampleAllocatorCallback
,
1548 (void **)&callback
)))
1550 IMFVideoSampleAllocatorCallback_SetCallback(callback
, NULL
);
1551 IMFVideoSampleAllocatorCallback_Release(callback
);
1555 source_reader_release(reader
);
1561 static HRESULT WINAPI
src_reader_GetStreamSelection(IMFSourceReaderEx
*iface
, DWORD index
, BOOL
*selected
)
1563 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1565 TRACE("%p, %#lx, %p.\n", iface
, index
, selected
);
1569 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1570 index
= reader
->first_video_stream_index
;
1572 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1573 index
= reader
->first_audio_stream_index
;
1579 return source_reader_get_stream_selection(reader
, index
, selected
);
1582 static HRESULT WINAPI
src_reader_SetStreamSelection(IMFSourceReaderEx
*iface
, DWORD index
, BOOL selection
)
1584 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1586 BOOL selection_changed
= FALSE
, selected
;
1589 TRACE("%p, %#lx, %d.\n", iface
, index
, selection
);
1591 selection
= !!selection
;
1593 EnterCriticalSection(&reader
->cs
);
1595 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1597 for (i
= 0; i
< reader
->stream_count
; ++i
)
1599 if (!selection_changed
)
1601 source_reader_get_stream_selection(reader
, i
, &selected
);
1602 selection_changed
= !!(selected
^ selection
);
1606 IMFPresentationDescriptor_SelectStream(reader
->descriptor
, i
);
1608 IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, i
);
1615 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1616 index
= reader
->first_video_stream_index
;
1618 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1619 index
= reader
->first_audio_stream_index
;
1625 source_reader_get_stream_selection(reader
, index
, &selected
);
1626 selection_changed
= !!(selected
^ selection
);
1629 hr
= IMFPresentationDescriptor_SelectStream(reader
->descriptor
, index
);
1631 hr
= IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, index
);
1634 if (selection_changed
)
1636 for (i
= 0; i
< reader
->stream_count
; ++i
)
1638 reader
->streams
[i
].last_sample_ts
= 0;
1642 LeaveCriticalSection(&reader
->cs
);
1644 return SUCCEEDED(hr
) ? S_OK
: MF_E_INVALIDSTREAMNUMBER
;
1647 static HRESULT
source_reader_get_native_media_type(struct source_reader
*reader
, DWORD index
, DWORD type_index
,
1648 IMFMediaType
**type
)
1650 IMFMediaTypeHandler
*handler
;
1651 IMFStreamDescriptor
*sd
;
1652 IMFMediaType
*src_type
;
1658 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1659 index
= reader
->first_video_stream_index
;
1661 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1662 index
= reader
->first_audio_stream_index
;
1668 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1669 return MF_E_INVALIDSTREAMNUMBER
;
1671 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
1672 IMFStreamDescriptor_Release(sd
);
1676 if (type_index
== MF_SOURCE_READER_CURRENT_TYPE_INDEX
)
1677 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &src_type
);
1679 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, type_index
, &src_type
);
1680 IMFMediaTypeHandler_Release(handler
);
1684 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
1685 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)*type
);
1686 IMFMediaType_Release(src_type
);
1692 static HRESULT WINAPI
src_reader_GetNativeMediaType(IMFSourceReaderEx
*iface
, DWORD index
, DWORD type_index
,
1693 IMFMediaType
**type
)
1695 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1697 TRACE("%p, %#lx, %#lx, %p.\n", iface
, index
, type_index
, type
);
1699 return source_reader_get_native_media_type(reader
, index
, type_index
, type
);
1702 static HRESULT WINAPI
src_reader_GetCurrentMediaType(IMFSourceReaderEx
*iface
, DWORD index
, IMFMediaType
**type
)
1704 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1707 TRACE("%p, %#lx, %p.\n", iface
, index
, type
);
1711 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1712 index
= reader
->first_video_stream_index
;
1714 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1715 index
= reader
->first_audio_stream_index
;
1721 if (index
>= reader
->stream_count
)
1722 return MF_E_INVALIDSTREAMNUMBER
;
1724 if (FAILED(hr
= MFCreateMediaType(type
)))
1727 EnterCriticalSection(&reader
->cs
);
1729 hr
= IMFMediaType_CopyAllItems(reader
->streams
[index
].current
, (IMFAttributes
*)*type
);
1731 LeaveCriticalSection(&reader
->cs
);
1736 static HRESULT
source_reader_get_source_type_handler(struct source_reader
*reader
, DWORD index
,
1737 IMFMediaTypeHandler
**handler
)
1739 IMFStreamDescriptor
*sd
;
1743 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1746 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, handler
);
1747 IMFStreamDescriptor_Release(sd
);
1752 static HRESULT
source_reader_set_compatible_media_type(struct source_reader
*reader
, DWORD index
, IMFMediaType
*type
)
1754 struct media_stream
*stream
= &reader
->streams
[index
];
1755 struct transform_entry
*entry
, *next
;
1756 IMFMediaTypeHandler
*type_handler
;
1757 IMFMediaType
*native_type
;
1758 BOOL type_set
= FALSE
;
1763 if (FAILED(hr
= IMFMediaType_IsEqual(type
, stream
->current
, &flags
)))
1766 if (!(flags
& MF_MEDIATYPE_EQUAL_MAJOR_TYPES
))
1767 return MF_E_INVALIDMEDIATYPE
;
1769 /* No need for a decoder or type change. */
1770 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_DATA
)
1773 if (stream
->transform_service
)
1775 IMFTransform_Release(stream
->transform_service
);
1776 stream
->transform_service
= NULL
;
1778 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &stream
->transforms
, struct transform_entry
, entry
)
1780 list_remove(&entry
->entry
);
1781 transform_entry_destroy(entry
);
1784 if (FAILED(hr
= source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1787 while (!type_set
&& IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler
, i
++, &native_type
) == S_OK
)
1789 static const DWORD compare_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_DATA
;
1791 if (SUCCEEDED(IMFMediaType_IsEqual(native_type
, type
, &flags
)) && (flags
& compare_flags
) == compare_flags
)
1793 if ((type_set
= SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, native_type
))))
1794 IMFMediaType_CopyAllItems(native_type
, (IMFAttributes
*)stream
->current
);
1797 IMFMediaType_Release(native_type
);
1800 IMFMediaTypeHandler_Release(type_handler
);
1802 return type_set
? S_OK
: S_FALSE
;
1805 static HRESULT
source_reader_create_sample_allocator_attributes(const struct source_reader
*reader
,
1806 IMFAttributes
**attributes
)
1808 UINT32 shared
= 0, shared_without_mutex
= 0;
1811 if (FAILED(hr
= MFCreateAttributes(attributes
, 1)))
1814 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED
, &shared
);
1815 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, &shared_without_mutex
);
1817 if (shared_without_mutex
)
1818 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, TRUE
);
1820 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED
, TRUE
);
1825 static HRESULT
source_reader_setup_sample_allocator(struct source_reader
*reader
, unsigned int index
)
1827 struct media_stream
*stream
= &reader
->streams
[index
];
1828 IMFAttributes
*attributes
= NULL
;
1832 IMFMediaType_GetMajorType(stream
->current
, &major
);
1833 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
1836 if (!(reader
->flags
& SOURCE_READER_HAS_DEVICE_MANAGER
))
1839 if (!stream
->allocator
)
1841 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&stream
->allocator
)))
1843 WARN("Failed to create sample allocator, hr %#lx.\n", hr
);
1848 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream
->allocator
);
1849 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(stream
->allocator
, reader
->device_manager
)))
1851 WARN("Failed to set device manager, hr %#lx.\n", hr
);
1855 if (FAILED(hr
= source_reader_create_sample_allocator_attributes(reader
, &attributes
)))
1856 WARN("Failed to create allocator attributes, hr %#lx.\n", hr
);
1858 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream
->allocator
, 2, 8,
1859 attributes
, stream
->current
)))
1861 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr
);
1865 IMFAttributes_Release(attributes
);
1870 static BOOL
source_reader_allow_video_processor(struct source_reader
*reader
, BOOL
*advanced
)
1875 if (!reader
->attributes
)
1878 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING
, &value
)))
1880 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING
, &value
)))
1881 return value
|| *advanced
;
1886 static HRESULT
source_reader_create_transform(struct source_reader
*reader
, BOOL decoder
, BOOL allow_processor
,
1887 IMFMediaType
*input_type
, IMFMediaType
*output_type
, struct transform_entry
**out
)
1889 MFT_REGISTER_TYPE_INFO in_type
, out_type
;
1890 struct transform_entry
*entry
;
1891 GUID
*classes
, category
;
1892 IMFTransform
*transform
;
1896 if (FAILED(hr
= IMFMediaType_GetMajorType(input_type
, &in_type
.guidMajorType
))
1897 || FAILED(hr
= IMFMediaType_GetGUID(input_type
, &MF_MT_SUBTYPE
, &in_type
.guidSubtype
)))
1899 if (FAILED(hr
= IMFMediaType_GetMajorType(output_type
, &out_type
.guidMajorType
))
1900 || FAILED(hr
= IMFMediaType_GetGUID(output_type
, &MF_MT_SUBTYPE
, &out_type
.guidSubtype
)))
1903 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
))
1904 category
= decoder
? MFT_CATEGORY_VIDEO_DECODER
: MFT_CATEGORY_VIDEO_PROCESSOR
;
1905 else if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1906 category
= decoder
? MFT_CATEGORY_AUDIO_DECODER
: MFT_CATEGORY_AUDIO_EFFECT
;
1908 return MF_E_TOPO_CODEC_NOT_FOUND
;
1910 if (!(entry
= calloc(1, sizeof(*entry
))))
1911 return E_OUTOFMEMORY
;
1912 list_init(&entry
->entry
);
1913 entry
->category
= category
;
1915 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1916 IMFMediaType_GetUINT32(output_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
,
1917 &entry
->min_buffer_size
);
1920 if (SUCCEEDED(hr
= MFTEnum(category
, 0, &in_type
, allow_processor
? NULL
: &out_type
, NULL
, &classes
, &count
)))
1923 return MF_E_TOPO_CODEC_NOT_FOUND
;
1925 for (i
= 0; i
< count
; i
++)
1927 IMFMediaType
*media_type
;
1929 if (FAILED(hr
= CoCreateInstance(&classes
[i
], NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTransform
, (void **)&transform
)))
1931 if (SUCCEEDED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0))
1932 && SUCCEEDED(hr
= IMFTransform_GetInputCurrentType(transform
, 0, &media_type
)))
1934 if (SUCCEEDED(hr
= update_media_type_from_upstream(output_type
, media_type
))
1935 && FAILED(hr
= IMFTransform_SetOutputType(transform
, 0, output_type
, 0)) && allow_processor
1936 && SUCCEEDED(hr
= IMFTransform_GetOutputAvailableType(transform
, 0, 0, &media_type
)))
1938 struct transform_entry
*converter
;
1940 if (SUCCEEDED(hr
= IMFTransform_SetOutputType(transform
, 0, media_type
, 0))
1941 && SUCCEEDED(hr
= update_media_type_from_upstream(output_type
, media_type
))
1942 && SUCCEEDED(hr
= source_reader_create_transform(reader
, FALSE
, FALSE
, media_type
, output_type
, &converter
)))
1943 list_add_tail(&entry
->entry
, &converter
->entry
);
1945 IMFMediaType_Release(media_type
);
1950 entry
->transform
= transform
;
1956 IMFTransform_Release(transform
);
1959 CoTaskMemFree(classes
);
1966 static HRESULT
source_reader_create_decoder_for_stream(struct source_reader
*reader
, DWORD index
, IMFMediaType
*output_type
)
1968 BOOL enable_advanced
, allow_processor
;
1969 struct media_stream
*stream
= &reader
->streams
[index
];
1970 IMFMediaType
*input_type
;
1974 allow_processor
= source_reader_allow_video_processor(reader
, &enable_advanced
);
1976 while (SUCCEEDED(hr
= source_reader_get_native_media_type(reader
, index
, i
++, &input_type
)))
1978 struct transform_entry
*entry
;
1980 /* first, try to append a single processor, then try again with a decoder and a processor */
1981 if ((allow_processor
&& SUCCEEDED(hr
= source_reader_create_transform(reader
, FALSE
, FALSE
, input_type
, output_type
, &entry
)))
1982 || SUCCEEDED(hr
= source_reader_create_transform(reader
, TRUE
, allow_processor
, input_type
, output_type
, &entry
)))
1984 struct list
*ptr
= list_head(&entry
->entry
);
1985 struct transform_entry
*service
= ptr
? LIST_ENTRY(ptr
, struct transform_entry
, entry
) : entry
;
1986 IMFMediaTypeHandler
*type_handler
;
1988 if (enable_advanced
)
1990 /* when advanced video processing is enabled, converters are exposed as stream transform service */
1991 stream
->transform_service
= service
->transform
;
1992 IMFTransform_AddRef(stream
->transform_service
);
1996 /* when advanced video processing is disabled, only decoders are exposed as stream transform service */
1997 if (IsEqualGUID(&entry
->category
, &MFT_CATEGORY_AUDIO_DECODER
)
1998 || IsEqualGUID(&entry
->category
, &MFT_CATEGORY_VIDEO_DECODER
))
2000 stream
->transform_service
= entry
->transform
;
2001 IMFTransform_AddRef(stream
->transform_service
);
2003 /* converters are hidden from the stream transforms */
2004 if (service
!= entry
)
2005 service
->hidden
= TRUE
;
2009 /* converters are hidden from the stream transforms */
2010 entry
->hidden
= TRUE
;
2014 /* move any additional transforms that have been created */
2015 list_move_head(&stream
->transforms
, &entry
->entry
);
2016 list_add_head(&stream
->transforms
, &entry
->entry
);
2018 if (SUCCEEDED(source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
2020 if (FAILED(hr
= IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, input_type
)))
2021 WARN("Failed to set current input media type, hr %#lx\n", hr
);
2022 IMFMediaTypeHandler_Release(type_handler
);
2025 if (FAILED(hr
= IMFTransform_GetOutputCurrentType(service
->transform
, 0, &output_type
)))
2026 WARN("Failed to get decoder output media type, hr %#lx\n", hr
);
2029 IMFMediaType_CopyAllItems(output_type
, (IMFAttributes
*)stream
->current
);
2030 IMFMediaType_Release(output_type
);
2033 IMFMediaType_Release(input_type
);
2037 IMFMediaType_Release(input_type
);
2040 return MF_E_TOPO_CODEC_NOT_FOUND
;
2043 static HRESULT WINAPI
src_reader_SetCurrentMediaType(IMFSourceReaderEx
*iface
, DWORD index
, DWORD
*reserved
,
2046 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2049 TRACE("%p, %#lx, %p, %p.\n", iface
, index
, reserved
, type
);
2053 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2054 index
= reader
->first_video_stream_index
;
2056 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2057 index
= reader
->first_audio_stream_index
;
2063 if (index
>= reader
->stream_count
)
2064 return MF_E_INVALIDSTREAMNUMBER
;
2066 /* FIXME: setting the output type while streaming should trigger a flush */
2068 EnterCriticalSection(&reader
->cs
);
2070 hr
= source_reader_set_compatible_media_type(reader
, index
, type
);
2072 hr
= source_reader_create_decoder_for_stream(reader
, index
, type
);
2074 hr
= source_reader_setup_sample_allocator(reader
, index
);
2076 LeaveCriticalSection(&reader
->cs
);
2081 static HRESULT WINAPI
src_reader_SetCurrentPosition(IMFSourceReaderEx
*iface
, REFGUID format
, REFPROPVARIANT position
)
2083 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2084 struct source_reader_async_command
*command
;
2089 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), position
);
2091 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2094 if (!(flags
& MFMEDIASOURCE_CAN_SEEK
))
2095 return MF_E_INVALIDREQUEST
;
2097 EnterCriticalSection(&reader
->cs
);
2099 /* Check if we got pending requests. */
2100 for (i
= 0; i
< reader
->stream_count
; ++i
)
2102 if (reader
->streams
[i
].requests
)
2104 hr
= MF_E_INVALIDREQUEST
;
2111 for (i
= 0; i
< reader
->stream_count
; ++i
)
2113 reader
->streams
[i
].last_sample_ts
= 0;
2116 if (reader
->async_callback
)
2118 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK
, &command
)))
2120 command
->u
.seek
.format
= *format
;
2121 PropVariantCopy(&command
->u
.seek
.position
, position
);
2123 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2124 IUnknown_Release(&command
->IUnknown_iface
);
2129 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, format
, position
)))
2131 reader
->flags
|= SOURCE_READER_SEEKING
;
2132 while (reader
->flags
& SOURCE_READER_SEEKING
)
2134 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2140 LeaveCriticalSection(&reader
->cs
);
2145 static HRESULT
source_reader_read_sample(struct source_reader
*reader
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
2146 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2148 struct media_stream
*stream
;
2149 DWORD actual_index_tmp
;
2150 LONGLONG timestamp_tmp
;
2154 if (!stream_flags
|| !sample
)
2160 timestamp
= ×tamp_tmp
;
2163 actual_index
= &actual_index_tmp
;
2165 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
2167 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, index
, &stream_index
)))
2169 *actual_index
= stream_index
;
2171 stream
= &reader
->streams
[stream_index
];
2173 if (!source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
2176 while (!source_reader_got_response_for_stream(reader
, stream
) && stream
->state
!= STREAM_STATE_EOS
)
2179 if (FAILED(hr
= source_reader_request_sample(reader
, stream
)))
2180 WARN("Failed to request a sample, hr %#lx.\n", hr
);
2181 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
2183 *stream_flags
= MF_SOURCE_READERF_ERROR
;
2187 SleepConditionVariableCS(&reader
->sample_event
, &reader
->cs
, INFINITE
);
2190 source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
2196 *actual_index
= index
;
2197 *stream_flags
= MF_SOURCE_READERF_ERROR
;
2202 TRACE("Stream %lu, got sample %p, flags %#lx.\n", *actual_index
, *sample
, *stream_flags
);
2207 static HRESULT
source_reader_read_sample_async(struct source_reader
*reader
, unsigned int index
, unsigned int flags
,
2208 DWORD
*actual_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2210 struct source_reader_async_command
*command
;
2213 if (actual_index
|| stream_flags
|| timestamp
|| sample
)
2214 return E_INVALIDARG
;
2216 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2217 hr
= MF_E_NOTACCEPTING
;
2220 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_READ
, &command
)))
2222 command
->u
.read
.stream_index
= index
;
2223 command
->u
.read
.flags
= flags
;
2225 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2226 IUnknown_Release(&command
->IUnknown_iface
);
2233 static HRESULT WINAPI
src_reader_ReadSample(IMFSourceReaderEx
*iface
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
2234 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2236 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2239 TRACE("%p, %#lx, %#lx, %p, %p, %p, %p\n", iface
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2241 EnterCriticalSection(&reader
->cs
);
2243 while (reader
->flags
& SOURCE_READER_SEEKING
)
2245 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2248 if (reader
->async_callback
)
2249 hr
= source_reader_read_sample_async(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2251 hr
= source_reader_read_sample(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2253 LeaveCriticalSection(&reader
->cs
);
2258 static HRESULT
source_reader_flush_async(struct source_reader
*reader
, unsigned int index
)
2260 struct source_reader_async_command
*command
;
2261 unsigned int stream_index
;
2264 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2265 return MF_E_INVALIDREQUEST
;
2269 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2270 stream_index
= reader
->first_video_stream_index
;
2272 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2273 stream_index
= reader
->first_audio_stream_index
;
2276 stream_index
= index
;
2279 reader
->flags
|= SOURCE_READER_FLUSHING
;
2281 if (stream_index
!= MF_SOURCE_READER_ALL_STREAMS
&& stream_index
>= reader
->stream_count
)
2282 return MF_E_INVALIDSTREAMNUMBER
;
2284 if (FAILED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH
, &command
)))
2287 command
->u
.flush
.stream_index
= stream_index
;
2289 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2290 IUnknown_Release(&command
->IUnknown_iface
);
2295 static HRESULT WINAPI
src_reader_Flush(IMFSourceReaderEx
*iface
, DWORD index
)
2297 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2300 TRACE("%p, %#lx.\n", iface
, index
);
2302 EnterCriticalSection(&reader
->cs
);
2304 if (reader
->async_callback
)
2305 hr
= source_reader_flush_async(reader
, index
);
2307 hr
= source_reader_flush(reader
, index
);
2309 LeaveCriticalSection(&reader
->cs
);
2314 static HRESULT WINAPI
src_reader_GetServiceForStream(IMFSourceReaderEx
*iface
, DWORD index
, REFGUID service
,
2315 REFIID riid
, void **object
)
2317 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2318 struct media_stream
*stream
= &reader
->streams
[index
];
2319 IUnknown
*obj
= NULL
;
2322 TRACE("%p, %#lx, %s, %s, %p\n", iface
, index
, debugstr_guid(service
), debugstr_guid(riid
), object
);
2324 EnterCriticalSection(&reader
->cs
);
2328 case MF_SOURCE_READER_MEDIASOURCE
:
2329 obj
= (IUnknown
*)reader
->source
;
2332 if (index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2333 index
= reader
->first_video_stream_index
;
2334 else if (index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2335 index
= reader
->first_audio_stream_index
;
2337 if (index
>= reader
->stream_count
)
2338 hr
= MF_E_INVALIDSTREAMNUMBER
;
2339 else if (!(obj
= (IUnknown
*)stream
->transform_service
))
2345 IUnknown_AddRef(obj
);
2347 LeaveCriticalSection(&reader
->cs
);
2351 if (IsEqualGUID(service
, &GUID_NULL
))
2353 hr
= IUnknown_QueryInterface(obj
, riid
, object
);
2359 hr
= IUnknown_QueryInterface(obj
, &IID_IMFGetService
, (void **)&gs
);
2362 hr
= IMFGetService_GetService(gs
, service
, riid
, object
);
2363 IMFGetService_Release(gs
);
2369 IUnknown_Release(obj
);
2374 static HRESULT WINAPI
src_reader_GetPresentationAttribute(IMFSourceReaderEx
*iface
, DWORD index
,
2375 REFGUID guid
, PROPVARIANT
*value
)
2377 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2378 IMFStreamDescriptor
*sd
;
2382 TRACE("%p, %#lx, %s, %p.\n", iface
, index
, debugstr_guid(guid
), value
);
2386 case MF_SOURCE_READER_MEDIASOURCE
:
2387 if (IsEqualGUID(guid
, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS
))
2391 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2395 value
->ulVal
= flags
;
2400 return IMFPresentationDescriptor_GetItem(reader
->descriptor
, guid
, value
);
2403 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2404 index
= reader
->first_video_stream_index
;
2406 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2407 index
= reader
->first_audio_stream_index
;
2413 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
2416 hr
= IMFStreamDescriptor_GetItem(sd
, guid
, value
);
2417 IMFStreamDescriptor_Release(sd
);
2422 static HRESULT WINAPI
src_reader_SetNativeMediaType(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2423 IMFMediaType
*media_type
, DWORD
*stream_flags
)
2425 FIXME("%p, %#lx, %p, %p.\n", iface
, stream_index
, media_type
, stream_flags
);
2430 static HRESULT WINAPI
src_reader_AddTransformForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2431 IUnknown
*transform
)
2433 FIXME("%p, %#lx, %p.\n", iface
, stream_index
, transform
);
2438 static HRESULT WINAPI
src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
)
2440 FIXME("%p, %#lx.\n", iface
, stream_index
);
2445 static struct transform_entry
*get_transform_at_index(struct media_stream
*stream
, UINT index
)
2447 struct transform_entry
*entry
;
2449 LIST_FOR_EACH_ENTRY(entry
, &stream
->transforms
, struct transform_entry
, entry
)
2450 if (!entry
->hidden
&& !index
--)
2456 static HRESULT WINAPI
src_reader_GetTransformForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2457 DWORD transform_index
, GUID
*category
, IMFTransform
**transform
)
2459 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2460 struct transform_entry
*entry
;
2463 TRACE("%p, %#lx, %#lx, %p, %p.\n", iface
, stream_index
, transform_index
, category
, transform
);
2465 EnterCriticalSection(&reader
->cs
);
2467 if (stream_index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2468 stream_index
= reader
->first_video_stream_index
;
2469 else if (stream_index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2470 stream_index
= reader
->first_audio_stream_index
;
2472 if (stream_index
>= reader
->stream_count
)
2473 hr
= MF_E_INVALIDSTREAMNUMBER
;
2474 else if (!(entry
= get_transform_at_index(&reader
->streams
[stream_index
], transform_index
)))
2475 hr
= MF_E_INVALIDINDEX
;
2478 *category
= entry
->category
;
2479 *transform
= entry
->transform
;
2480 IMFTransform_AddRef(*transform
);
2484 LeaveCriticalSection(&reader
->cs
);
2489 static const IMFSourceReaderExVtbl srcreader_vtbl
=
2491 src_reader_QueryInterface
,
2494 src_reader_GetStreamSelection
,
2495 src_reader_SetStreamSelection
,
2496 src_reader_GetNativeMediaType
,
2497 src_reader_GetCurrentMediaType
,
2498 src_reader_SetCurrentMediaType
,
2499 src_reader_SetCurrentPosition
,
2500 src_reader_ReadSample
,
2502 src_reader_GetServiceForStream
,
2503 src_reader_GetPresentationAttribute
,
2504 src_reader_SetNativeMediaType
,
2505 src_reader_AddTransformForStream
,
2506 src_reader_RemoveAllTransformsForStream
,
2507 src_reader_GetTransformForStream
,
2510 static DWORD
reader_get_first_stream_index(IMFPresentationDescriptor
*descriptor
, const GUID
*major
)
2517 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
2518 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2520 for (i
= 0; i
< count
; ++i
)
2522 IMFMediaTypeHandler
*handler
;
2523 IMFStreamDescriptor
*sd
;
2525 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
, &selected
, &sd
)))
2527 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2528 IMFStreamDescriptor_Release(sd
);
2531 hr
= IMFMediaTypeHandler_GetMajorType(handler
, &guid
);
2532 IMFMediaTypeHandler_Release(handler
);
2535 WARN("Failed to get stream major type, hr %#lx.\n", hr
);
2539 if (IsEqualGUID(&guid
, major
))
2547 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2550 static HRESULT
create_source_reader_from_source(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2551 BOOL shutdown_on_release
, REFIID riid
, void **out
)
2553 struct source_reader
*object
;
2557 object
= calloc(1, sizeof(*object
));
2559 return E_OUTOFMEMORY
;
2561 object
->IMFSourceReaderEx_iface
.lpVtbl
= &srcreader_vtbl
;
2562 object
->source_events_callback
.lpVtbl
= &source_events_callback_vtbl
;
2563 object
->stream_events_callback
.lpVtbl
= &stream_events_callback_vtbl
;
2564 object
->async_commands_callback
.lpVtbl
= &async_commands_callback_vtbl
;
2565 object
->public_refcount
= 1;
2566 object
->refcount
= 1;
2567 list_init(&object
->responses
);
2568 if (shutdown_on_release
)
2569 object
->flags
|= SOURCE_READER_SHUTDOWN_ON_RELEASE
;
2570 object
->source
= source
;
2571 IMFMediaSource_AddRef(object
->source
);
2572 InitializeCriticalSection(&object
->cs
);
2573 InitializeConditionVariable(&object
->sample_event
);
2574 InitializeConditionVariable(&object
->state_event
);
2575 InitializeConditionVariable(&object
->stop_event
);
2577 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(object
->source
, &object
->descriptor
)))
2580 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(object
->descriptor
, &object
->stream_count
)))
2583 if (!(object
->streams
= calloc(object
->stream_count
, sizeof(*object
->streams
))))
2589 /* Set initial current media types. */
2590 for (i
= 0; i
< object
->stream_count
; ++i
)
2592 IMFMediaTypeHandler
*handler
;
2593 IMFStreamDescriptor
*sd
;
2594 IMFMediaType
*src_type
;
2597 list_init(&object
->streams
[i
].transforms
);
2599 if (FAILED(hr
= MFCreateMediaType(&object
->streams
[i
].current
)))
2602 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(object
->descriptor
, i
, &selected
, &sd
)))
2605 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &object
->streams
[i
].id
)))
2606 WARN("Failed to get stream identifier, hr %#lx.\n", hr
);
2608 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2609 IMFStreamDescriptor_Release(sd
);
2613 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, 0, &src_type
);
2614 IMFMediaTypeHandler_Release(handler
);
2618 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)object
->streams
[i
].current
);
2619 IMFMediaType_Release(src_type
);
2623 object
->streams
[i
].reader
= object
;
2624 object
->streams
[i
].index
= i
;
2630 /* At least one major type has to be set. */
2631 object
->first_audio_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Audio
);
2632 object
->first_video_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Video
);
2634 if (object
->first_audio_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
&&
2635 object
->first_video_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
)
2637 hr
= MF_E_ATTRIBUTENOTFOUND
;
2640 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(object
->source
, &object
->source_events_callback
,
2641 (IUnknown
*)object
->source
)))
2648 object
->attributes
= attributes
;
2649 IMFAttributes_AddRef(object
->attributes
);
2651 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_ASYNC_CALLBACK
, &IID_IMFSourceReaderCallback
,
2652 (void **)&object
->async_callback
);
2653 if (object
->async_callback
)
2654 TRACE("Using async callback %p.\n", object
->async_callback
);
2656 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_D3D_MANAGER
, &IID_IUnknown
, (void **)&object
->device_manager
);
2657 if (object
->device_manager
)
2659 IUnknown
*unk
= NULL
;
2661 if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IMFDXGIDeviceManager
, (void **)&unk
)))
2662 object
->flags
|= SOURCE_READER_DXGI_DEVICE_MANAGER
;
2663 else if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IDirect3DDeviceManager9
, (void **)&unk
)))
2664 object
->flags
|= SOURCE_READER_D3D9_DEVICE_MANAGER
;
2666 if (!(object
->flags
& (SOURCE_READER_HAS_DEVICE_MANAGER
)))
2668 WARN("Unknown device manager.\n");
2669 IUnknown_Release(object
->device_manager
);
2670 object
->device_manager
= NULL
;
2674 IUnknown_Release(unk
);
2678 if (FAILED(hr
= MFLockSharedWorkQueue(L
"", 0, NULL
, &object
->queue
)))
2679 WARN("Failed to acquired shared queue, hr %#lx.\n", hr
);
2682 hr
= IMFSourceReaderEx_QueryInterface(&object
->IMFSourceReaderEx_iface
, riid
, out
);
2685 IMFSourceReaderEx_Release(&object
->IMFSourceReaderEx_iface
);
2689 static HRESULT
create_source_reader_from_stream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2690 REFIID riid
, void **out
)
2692 IPropertyStore
*props
= NULL
;
2693 IMFSourceResolver
*resolver
;
2694 MF_OBJECT_TYPE obj_type
;
2695 IMFMediaSource
*source
;
2698 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2702 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2705 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, stream
, NULL
, MF_RESOLUTION_MEDIASOURCE
2706 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE
, props
, &obj_type
, (IUnknown
**)&source
);
2707 IMFSourceResolver_Release(resolver
);
2709 IPropertyStore_Release(props
);
2713 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2714 IMFMediaSource_Release(source
);
2718 static HRESULT
create_source_reader_from_url(const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2720 IPropertyStore
*props
= NULL
;
2721 IMFSourceResolver
*resolver
;
2722 IUnknown
*object
= NULL
;
2723 MF_OBJECT_TYPE obj_type
;
2724 IMFMediaSource
*source
;
2727 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2731 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2734 hr
= IMFSourceResolver_CreateObjectFromURL(resolver
, url
, MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
,
2740 case MF_OBJECT_BYTESTREAM
:
2741 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, (IMFByteStream
*)object
, NULL
,
2742 MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
, (IUnknown
**)&source
);
2744 case MF_OBJECT_MEDIASOURCE
:
2745 source
= (IMFMediaSource
*)object
;
2746 IMFMediaSource_AddRef(source
);
2749 WARN("Unknown object type %d.\n", obj_type
);
2752 IUnknown_Release(object
);
2755 IMFSourceResolver_Release(resolver
);
2757 IPropertyStore_Release(props
);
2761 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2762 IMFMediaSource_Release(source
);
2766 static HRESULT
create_source_reader_from_object(IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2768 IMFMediaSource
*source
= NULL
;
2769 IMFByteStream
*stream
= NULL
;
2772 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSource
, (void **)&source
);
2774 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2778 UINT32 disconnect
= 0;
2781 IMFAttributes_GetUINT32(attributes
, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN
, &disconnect
);
2782 hr
= create_source_reader_from_source(source
, attributes
, !disconnect
, riid
, out
);
2785 hr
= create_source_reader_from_stream(stream
, attributes
, riid
, out
);
2788 IMFMediaSource_Release(source
);
2790 IMFByteStream_Release(stream
);
2795 /***********************************************************************
2796 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2798 HRESULT WINAPI
MFCreateSourceReaderFromByteStream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2799 IMFSourceReader
**reader
)
2801 TRACE("%p, %p, %p.\n", stream
, attributes
, reader
);
2803 return create_source_reader_from_object((IUnknown
*)stream
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2806 /***********************************************************************
2807 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2809 HRESULT WINAPI
MFCreateSourceReaderFromMediaSource(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2810 IMFSourceReader
**reader
)
2812 TRACE("%p, %p, %p.\n", source
, attributes
, reader
);
2814 return create_source_reader_from_object((IUnknown
*)source
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2817 /***********************************************************************
2818 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2820 HRESULT WINAPI
MFCreateSourceReaderFromURL(const WCHAR
*url
, IMFAttributes
*attributes
, IMFSourceReader
**reader
)
2822 TRACE("%s, %p, %p.\n", debugstr_w(url
), attributes
, reader
);
2824 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2827 static HRESULT WINAPI
readwrite_factory_QueryInterface(IMFReadWriteClassFactory
*iface
, REFIID riid
, void **out
)
2829 if (IsEqualIID(riid
, &IID_IMFReadWriteClassFactory
) ||
2830 IsEqualIID(riid
, &IID_IUnknown
))
2833 IMFReadWriteClassFactory_AddRef(iface
);
2837 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2839 return E_NOINTERFACE
;
2842 static ULONG WINAPI
readwrite_factory_AddRef(IMFReadWriteClassFactory
*iface
)
2847 static ULONG WINAPI
readwrite_factory_Release(IMFReadWriteClassFactory
*iface
)
2852 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2853 const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2855 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid
), debugstr_w(url
), attributes
, debugstr_guid(riid
), out
);
2857 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2859 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, out
);
2861 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2863 return create_sink_writer_from_url(url
, NULL
, attributes
, riid
, out
);
2866 FIXME("Unsupported %s.\n", debugstr_guid(clsid
));
2871 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2872 IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2876 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid
), unk
, attributes
, debugstr_guid(riid
), out
);
2878 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2880 return create_source_reader_from_object(unk
, attributes
, riid
, out
);
2882 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2884 IMFByteStream
*stream
= NULL
;
2885 IMFMediaSink
*sink
= NULL
;
2887 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2889 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSink
, (void **)&sink
);
2892 hr
= create_sink_writer_from_url(NULL
, stream
, attributes
, riid
, out
);
2894 hr
= create_sink_writer_from_sink(sink
, attributes
, riid
, out
);
2897 IMFMediaSink_Release(sink
);
2899 IMFByteStream_Release(stream
);
2905 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2911 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl
=
2913 readwrite_factory_QueryInterface
,
2914 readwrite_factory_AddRef
,
2915 readwrite_factory_Release
,
2916 readwrite_factory_CreateInstanceFromURL
,
2917 readwrite_factory_CreateInstanceFromObject
,
2920 static IMFReadWriteClassFactory readwrite_factory
= { &readwrite_factory_vtbl
};
2922 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **out
)
2924 TRACE("%s, %p.\n", debugstr_guid(riid
), out
);
2926 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2927 IsEqualGUID(riid
, &IID_IUnknown
))
2929 IClassFactory_AddRef(iface
);
2934 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2936 return E_NOINTERFACE
;
2939 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2944 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2949 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **out
)
2951 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), out
);
2956 return CLASS_E_NOAGGREGATION
;
2958 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory
, riid
, out
);
2961 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2963 FIXME("%d.\n", dolock
);
2967 static const IClassFactoryVtbl classfactoryvtbl
=
2969 classfactory_QueryInterface
,
2970 classfactory_AddRef
,
2971 classfactory_Release
,
2972 classfactory_CreateInstance
,
2973 classfactory_LockServer
,
2976 static IClassFactory classfactory
= { &classfactoryvtbl
};
2978 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
2980 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
2982 if (IsEqualGUID(clsid
, &CLSID_MFReadWriteClassFactory
))
2983 return IClassFactory_QueryInterface(&classfactory
, riid
, out
);
2985 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2987 return CLASS_E_CLASSNOTAVAILABLE
;