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
;
84 IMFMediaStream
*stream
;
85 IMFMediaType
*current
;
86 struct list transforms
;
87 IMFVideoSampleAllocatorEx
*allocator
;
88 IMFTransform
*transform_service
;
91 enum media_stream_state state
;
93 unsigned int requests
;
94 unsigned int responses
;
95 LONGLONG last_sample_ts
;
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
,
107 struct source_reader_async_command
109 IUnknown IUnknown_iface
;
111 enum source_reader_async_op op
;
117 unsigned int stream_index
;
122 PROPVARIANT position
;
126 unsigned int stream_index
;
130 unsigned int stream_index
;
134 unsigned int stream_index
;
139 enum source_reader_flags
141 SOURCE_READER_FLUSHING
= 0x1,
142 SOURCE_READER_SEEKING
= 0x2,
143 SOURCE_READER_SHUTDOWN_ON_RELEASE
= 0x4,
144 SOURCE_READER_D3D9_DEVICE_MANAGER
= 0x8,
145 SOURCE_READER_DXGI_DEVICE_MANAGER
= 0x10,
146 SOURCE_READER_HAS_DEVICE_MANAGER
= SOURCE_READER_D3D9_DEVICE_MANAGER
| SOURCE_READER_DXGI_DEVICE_MANAGER
,
151 IMFSourceReaderEx IMFSourceReaderEx_iface
;
152 IMFAsyncCallback source_events_callback
;
153 IMFAsyncCallback stream_events_callback
;
154 IMFAsyncCallback async_commands_callback
;
156 LONG public_refcount
;
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
;
167 enum media_source_state source_state
;
168 struct media_stream
*streams
;
169 struct list responses
;
171 CONDITION_VARIABLE sample_event
;
172 CONDITION_VARIABLE state_event
;
173 CONDITION_VARIABLE stop_event
;
176 static inline struct source_reader
*impl_from_IMFSourceReaderEx(IMFSourceReaderEx
*iface
)
178 return CONTAINING_RECORD(iface
, struct source_reader
, IMFSourceReaderEx_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 void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
);
203 static ULONG
source_reader_addref(struct source_reader
*reader
)
205 return InterlockedIncrement(&reader
->refcount
);
208 static void transform_entry_destroy(struct transform_entry
*entry
)
210 IMFTransform_Release(entry
->transform
);
214 static void media_stream_destroy(struct media_stream
*stream
)
216 struct transform_entry
*entry
, *next
;
218 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &stream
->transforms
, struct transform_entry
, entry
)
220 list_remove(&entry
->entry
);
221 transform_entry_destroy(entry
);
225 IMFMediaStream_Release(stream
->stream
);
227 IMFMediaType_Release(stream
->current
);
228 if (stream
->allocator
)
229 IMFVideoSampleAllocatorEx_Release(stream
->allocator
);
232 static ULONG
source_reader_release(struct source_reader
*reader
)
234 ULONG refcount
= InterlockedDecrement(&reader
->refcount
);
239 if (reader
->device_manager
)
240 IUnknown_Release(reader
->device_manager
);
241 if (reader
->async_callback
)
242 IMFSourceReaderCallback_Release(reader
->async_callback
);
243 if (reader
->descriptor
)
244 IMFPresentationDescriptor_Release(reader
->descriptor
);
245 if (reader
->attributes
)
246 IMFAttributes_Release(reader
->attributes
);
247 IMFMediaSource_Release(reader
->source
);
249 for (i
= 0; i
< reader
->stream_count
; ++i
)
251 struct media_stream
*stream
= &reader
->streams
[i
];
252 media_stream_destroy(stream
);
254 source_reader_release_responses(reader
, NULL
);
255 free(reader
->streams
);
256 MFUnlockWorkQueue(reader
->queue
);
257 DeleteCriticalSection(&reader
->cs
);
264 static HRESULT WINAPI
source_reader_async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
266 if (IsEqualIID(riid
, &IID_IUnknown
))
269 IUnknown_AddRef(iface
);
273 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
275 return E_NOINTERFACE
;
278 static ULONG WINAPI
source_reader_async_command_AddRef(IUnknown
*iface
)
280 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
281 return InterlockedIncrement(&command
->refcount
);
284 static ULONG WINAPI
source_reader_async_command_Release(IUnknown
*iface
)
286 struct source_reader_async_command
*command
= impl_from_async_command_IUnknown(iface
);
287 ULONG refcount
= InterlockedIncrement(&command
->refcount
);
291 if (command
->op
== SOURCE_READER_ASYNC_SEEK
)
292 PropVariantClear(&command
->u
.seek
.position
);
299 static const IUnknownVtbl source_reader_async_command_vtbl
=
301 source_reader_async_command_QueryInterface
,
302 source_reader_async_command_AddRef
,
303 source_reader_async_command_Release
,
306 static HRESULT
source_reader_create_async_op(enum source_reader_async_op op
, struct source_reader_async_command
**ret
)
308 struct source_reader_async_command
*command
;
310 if (!(command
= calloc(1, sizeof(*command
))))
311 return E_OUTOFMEMORY
;
313 command
->IUnknown_iface
.lpVtbl
= &source_reader_async_command_vtbl
;
321 static HRESULT
media_event_get_object(IMFMediaEvent
*event
, REFIID riid
, void **obj
)
326 PropVariantInit(&value
);
327 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
329 WARN("Failed to get event value, hr %#lx.\n", hr
);
333 if (value
.vt
!= VT_UNKNOWN
|| !value
.punkVal
)
335 WARN("Unexpected value type %d.\n", value
.vt
);
336 PropVariantClear(&value
);
340 hr
= IUnknown_QueryInterface(value
.punkVal
, riid
, obj
);
341 PropVariantClear(&value
);
344 WARN("Unexpected object type.\n");
351 static HRESULT
media_stream_get_id(IMFMediaStream
*stream
, DWORD
*id
)
353 IMFStreamDescriptor
*sd
;
356 if (SUCCEEDED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
358 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, id
);
359 IMFStreamDescriptor_Release(sd
);
365 static HRESULT WINAPI
source_reader_callback_QueryInterface(IMFAsyncCallback
*iface
,
366 REFIID riid
, void **obj
)
368 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
370 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
371 IsEqualIID(riid
, &IID_IUnknown
))
374 IMFAsyncCallback_AddRef(iface
);
378 WARN("Unsupported %s.\n", debugstr_guid(riid
));
380 return E_NOINTERFACE
;
383 static ULONG WINAPI
source_reader_source_events_callback_AddRef(IMFAsyncCallback
*iface
)
385 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
386 return source_reader_addref(reader
);
389 static ULONG WINAPI
source_reader_source_events_callback_Release(IMFAsyncCallback
*iface
)
391 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
392 return source_reader_release(reader
);
395 static HRESULT WINAPI
source_reader_callback_GetParameters(IMFAsyncCallback
*iface
,
396 DWORD
*flags
, DWORD
*queue
)
401 static void source_reader_response_ready(struct source_reader
*reader
, struct stream_response
*response
)
403 struct source_reader_async_command
*command
;
404 struct media_stream
*stream
= &reader
->streams
[response
->stream_index
];
407 if (!stream
->requests
)
410 if (reader
->async_callback
)
412 if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY
, &command
)))
414 command
->u
.sample
.stream_index
= stream
->index
;
415 if (FAILED(hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
)))
416 WARN("Failed to submit async result, hr %#lx.\n", hr
);
417 IUnknown_Release(&command
->IUnknown_iface
);
421 WakeAllConditionVariable(&reader
->sample_event
);
426 static void source_reader_copy_sample_buffer(IMFSample
*src
, IMFSample
*dst
)
428 IMFMediaBuffer
*buffer
;
433 IMFSample_CopyAllItems(src
, (IMFAttributes
*)dst
);
435 IMFSample_SetSampleDuration(dst
, 0);
436 IMFSample_SetSampleTime(dst
, 0);
437 IMFSample_SetSampleFlags(dst
, 0);
439 if (SUCCEEDED(IMFSample_GetSampleDuration(src
, &time
)))
440 IMFSample_SetSampleDuration(dst
, time
);
442 if (SUCCEEDED(IMFSample_GetSampleTime(src
, &time
)))
443 IMFSample_SetSampleTime(dst
, time
);
445 if (SUCCEEDED(IMFSample_GetSampleFlags(src
, &flags
)))
446 IMFSample_SetSampleFlags(dst
, flags
);
448 if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src
, NULL
)))
450 if (SUCCEEDED(IMFSample_GetBufferByIndex(dst
, 0, &buffer
)))
452 if (FAILED(hr
= IMFSample_CopyToBuffer(src
, buffer
)))
453 WARN("Failed to copy a buffer, hr %#lx.\n", hr
);
454 IMFMediaBuffer_Release(buffer
);
459 static HRESULT
source_reader_queue_response(struct source_reader
*reader
, struct media_stream
*stream
, HRESULT status
,
460 DWORD stream_flags
, LONGLONG timestamp
, IMFSample
*sample
)
462 struct stream_response
*response
;
464 if (!(response
= calloc(1, sizeof(*response
))))
465 return E_OUTOFMEMORY
;
467 response
->status
= status
;
468 response
->stream_index
= stream
->index
;
469 response
->stream_flags
= stream_flags
;
470 response
->timestamp
= timestamp
;
471 response
->sample
= sample
;
472 if (response
->sample
)
473 IMFSample_AddRef(response
->sample
);
475 list_add_tail(&reader
->responses
, &response
->entry
);
478 source_reader_response_ready(reader
, response
);
480 stream
->last_sample_ts
= timestamp
;
485 static HRESULT
source_reader_queue_sample(struct source_reader
*reader
, struct media_stream
*stream
,
488 LONGLONG timestamp
= 0;
490 if (FAILED(IMFSample_GetSampleTime(sample
, ×tamp
)))
491 WARN("Sample time wasn't set.\n");
493 return source_reader_queue_response(reader
, stream
, S_OK
, 0, timestamp
, sample
);
496 static HRESULT
source_reader_request_sample(struct source_reader
*reader
, struct media_stream
*stream
)
500 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
502 if (FAILED(hr
= IMFMediaStream_RequestSample(stream
->stream
, NULL
)))
503 WARN("Sample request failed, hr %#lx.\n", hr
);
506 stream
->flags
|= STREAM_FLAG_SAMPLE_REQUESTED
;
513 static HRESULT
source_reader_new_stream_handler(struct source_reader
*reader
, IMFMediaEvent
*event
)
515 IMFMediaStream
*stream
;
520 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFMediaStream
, (void **)&stream
)))
522 WARN("Failed to get stream object, hr %#lx.\n", hr
);
526 TRACE("Got new stream %p.\n", stream
);
528 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
530 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
531 IMFMediaStream_Release(stream
);
535 EnterCriticalSection(&reader
->cs
);
537 for (i
= 0; i
< reader
->stream_count
; ++i
)
539 if (id
== reader
->streams
[i
].id
)
541 if (!reader
->streams
[i
].stream
)
543 reader
->streams
[i
].stream
= stream
;
544 IMFMediaStream_AddRef(reader
->streams
[i
].stream
);
545 if (FAILED(hr
= IMFMediaStream_BeginGetEvent(stream
, &reader
->stream_events_callback
,
546 (IUnknown
*)stream
)))
548 WARN("Failed to subscribe to stream events, hr %#lx.\n", hr
);
551 if (reader
->streams
[i
].requests
)
552 if (FAILED(source_reader_request_sample(reader
, &reader
->streams
[i
])))
553 WakeAllConditionVariable(&reader
->sample_event
);
559 if (i
== reader
->stream_count
)
560 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id
);
562 LeaveCriticalSection(&reader
->cs
);
564 IMFMediaStream_Release(stream
);
569 static HRESULT
source_reader_source_state_handler(struct source_reader
*reader
, MediaEventType event_type
)
571 EnterCriticalSection(&reader
->cs
);
575 case MESourceStarted
:
576 reader
->source_state
= SOURCE_STATE_STARTED
;
577 reader
->flags
&= ~SOURCE_READER_SEEKING
;
579 case MESourceStopped
:
580 reader
->source_state
= SOURCE_STATE_STOPPED
;
581 reader
->flags
&= ~SOURCE_READER_SEEKING
;
584 reader
->flags
&= ~SOURCE_READER_SEEKING
;
587 WARN("Unhandled event %ld.\n", event_type
);
590 LeaveCriticalSection(&reader
->cs
);
592 WakeAllConditionVariable(&reader
->state_event
);
593 if (event_type
== MESourceStopped
)
594 WakeAllConditionVariable(&reader
->stop_event
);
599 static HRESULT WINAPI
source_reader_source_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
601 struct source_reader
*reader
= impl_from_source_callback_IMFAsyncCallback(iface
);
602 MediaEventType event_type
;
603 IMFMediaSource
*source
;
604 IMFMediaEvent
*event
;
607 TRACE("%p, %p.\n", iface
, result
);
609 source
= (IMFMediaSource
*)IMFAsyncResult_GetStateNoAddRef(result
);
611 if (FAILED(hr
= IMFMediaSource_EndGetEvent(source
, result
, &event
)))
614 IMFMediaEvent_GetType(event
, &event_type
);
616 TRACE("Got event %lu.\n", event_type
);
621 hr
= source_reader_new_stream_handler(reader
, event
);
623 case MESourceStarted
:
625 case MESourceStopped
:
627 hr
= source_reader_source_state_handler(reader
, event_type
);
629 case MEBufferingStarted
:
630 case MEBufferingStopped
:
634 case MESourceCharacteristicsChanged
:
635 case MESourceMetadataChanged
:
636 case MEContentProtectionMetadata
:
637 case MEDeviceThermalStateChanged
:
638 if (reader
->async_callback
)
639 IMFSourceReaderCallback_OnEvent(reader
->async_callback
, MF_SOURCE_READER_MEDIASOURCE
, event
);
646 WARN("Failed while handling %ld event, hr %#lx.\n", event_type
, hr
);
648 IMFMediaEvent_Release(event
);
650 if (event_type
!= MESourceStopped
)
651 IMFMediaSource_BeginGetEvent(source
, iface
, (IUnknown
*)source
);
656 static const IMFAsyncCallbackVtbl source_events_callback_vtbl
=
658 source_reader_callback_QueryInterface
,
659 source_reader_source_events_callback_AddRef
,
660 source_reader_source_events_callback_Release
,
661 source_reader_callback_GetParameters
,
662 source_reader_source_events_callback_Invoke
,
665 static ULONG WINAPI
source_reader_stream_events_callback_AddRef(IMFAsyncCallback
*iface
)
667 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
668 return source_reader_addref(reader
);
671 static ULONG WINAPI
source_reader_stream_events_callback_Release(IMFAsyncCallback
*iface
)
673 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
674 return source_reader_release(reader
);
677 static HRESULT
source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO
*info
, IMFSample
**out
)
679 IMFMediaBuffer
*buffer
;
684 if (FAILED(hr
= MFCreateSample(&sample
)))
686 if (SUCCEEDED(hr
= MFCreateAlignedMemoryBuffer(info
->cbSize
, info
->cbAlignment
, &buffer
)))
688 if (SUCCEEDED(hr
= IMFSample_AddBuffer(sample
, buffer
)))
691 IMFSample_AddRef(sample
);
693 IMFMediaBuffer_Release(buffer
);
696 IMFSample_Release(sample
);
700 static void media_type_try_copy_attr(IMFMediaType
*dst
, IMFMediaType
*src
, const GUID
*attr
, HRESULT
*hr
)
704 PropVariantInit(&value
);
705 if (SUCCEEDED(*hr
) && FAILED(IMFMediaType_GetItem(dst
, attr
, NULL
))
706 && SUCCEEDED(IMFMediaType_GetItem(src
, attr
, &value
)))
707 *hr
= IMFMediaType_SetItem(dst
, attr
, &value
);
708 PropVariantClear(&value
);
711 /* update a media type with additional attributes reported by upstream element */
712 /* also present in mf/topology_loader.c pipeline */
713 static HRESULT
update_media_type_from_upstream(IMFMediaType
*media_type
, IMFMediaType
*upstream_type
)
717 /* propagate common video attributes */
718 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FRAME_SIZE
, &hr
);
719 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FRAME_RATE
, &hr
);
720 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_DEFAULT_STRIDE
, &hr
);
721 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_ROTATION
, &hr
);
722 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_FIXED_SIZE_SAMPLES
, &hr
);
723 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_PIXEL_ASPECT_RATIO
, &hr
);
724 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, &hr
);
725 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
, &hr
);
727 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_CHROMA_SITING
, &hr
);
728 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_INTERLACE_MODE
, &hr
);
729 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_TRANSFER_FUNCTION
, &hr
);
730 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_PRIMARIES
, &hr
);
731 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_YUV_MATRIX
, &hr
);
732 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_LIGHTING
, &hr
);
733 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_VIDEO_NOMINAL_RANGE
, &hr
);
735 /* propagate common audio attributes */
736 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_NUM_CHANNELS
, &hr
);
737 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &hr
);
738 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_BITS_PER_SAMPLE
, &hr
);
739 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_SAMPLES_PER_SECOND
, &hr
);
740 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
, &hr
);
741 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_CHANNEL_MASK
, &hr
);
742 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_SAMPLES_PER_BLOCK
, &hr
);
743 media_type_try_copy_attr(media_type
, upstream_type
, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE
, &hr
);
748 static HRESULT
source_reader_pull_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
749 struct transform_entry
*entry
);
750 static HRESULT
source_reader_push_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
751 struct transform_entry
*entry
, IMFSample
*sample
)
757 if (FAILED(hr
= source_reader_pull_transform_samples(reader
, stream
, entry
))
758 && hr
!= MF_E_TRANSFORM_NEED_MORE_INPUT
)
760 if (SUCCEEDED(hr
= IMFTransform_ProcessInput(entry
->transform
, 0, sample
, 0)))
761 return source_reader_pull_transform_samples(reader
, stream
, entry
);
763 while (hr
== MF_E_NOTACCEPTING
);
768 static HRESULT
source_reader_pull_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
769 struct transform_entry
*entry
)
771 MFT_OUTPUT_STREAM_INFO stream_info
= {0};
772 struct transform_entry
*next
= NULL
;
777 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
778 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
780 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(entry
->transform
, 0, &stream_info
)))
782 stream_info
.cbSize
= max(stream_info
.cbSize
, entry
->min_buffer_size
);
784 while (SUCCEEDED(hr
))
786 MFT_OUTPUT_DATA_BUFFER out_buffer
= {0};
788 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
))
789 && FAILED(hr
= source_reader_allocate_stream_sample(&stream_info
, &out_buffer
.pSample
)))
792 if (SUCCEEDED(hr
= IMFTransform_ProcessOutput(entry
->transform
, 0, 1, &out_buffer
, &status
)))
795 hr
= source_reader_push_transform_samples(reader
, stream
, next
, out_buffer
.pSample
);
797 hr
= source_reader_queue_sample(reader
, stream
, out_buffer
.pSample
);
800 if (out_buffer
.pSample
)
801 IMFSample_Release(out_buffer
.pSample
);
802 if (out_buffer
.pEvents
)
803 IMFCollection_Release(out_buffer
.pEvents
);
809 static HRESULT
source_reader_drain_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
810 struct transform_entry
*entry
)
812 struct transform_entry
*next
= NULL
;
816 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
817 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
819 if (FAILED(hr
= IMFTransform_ProcessMessage(entry
->transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
820 WARN("Failed to drain transform %p, hr %#lx\n", entry
->transform
, hr
);
821 if (FAILED(hr
= source_reader_pull_transform_samples(reader
, stream
, entry
))
822 && hr
!= MF_E_TRANSFORM_NEED_MORE_INPUT
)
823 WARN("Failed to pull pending samples, hr %#lx.\n", hr
);
825 return next
? source_reader_drain_transform_samples(reader
, stream
, next
) : S_OK
;
828 static HRESULT
source_reader_flush_transform_samples(struct source_reader
*reader
, struct media_stream
*stream
,
829 struct transform_entry
*entry
)
831 struct transform_entry
*next
= NULL
;
835 if ((ptr
= list_next(&stream
->transforms
, &entry
->entry
)))
836 next
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
838 if (FAILED(hr
= IMFTransform_ProcessMessage(entry
->transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0)))
839 WARN("Failed to flush transform %p, hr %#lx\n", entry
->transform
, hr
);
841 return next
? source_reader_flush_transform_samples(reader
, stream
, next
) : S_OK
;
844 static HRESULT
source_reader_process_sample(struct source_reader
*reader
, struct media_stream
*stream
,
847 struct transform_entry
*entry
;
851 if (!(ptr
= list_head(&stream
->transforms
)))
852 return source_reader_queue_sample(reader
, stream
, sample
);
853 entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
855 /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
856 if (SUCCEEDED(hr
= source_reader_push_transform_samples(reader
, stream
, entry
, sample
))
857 || hr
== MF_E_TRANSFORM_NEED_MORE_INPUT
)
858 hr
= stream
->requests
? source_reader_request_sample(reader
, stream
) : S_OK
;
860 WARN("Transform failed to process output, hr %#lx.\n", hr
);
865 static HRESULT
source_reader_media_sample_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
866 IMFMediaEvent
*event
)
873 TRACE("Got new sample for stream %p.\n", stream
);
875 if (FAILED(hr
= media_event_get_object(event
, &IID_IMFSample
, (void **)&sample
)))
877 WARN("Failed to get sample object, hr %#lx.\n", hr
);
881 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
883 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
884 IMFSample_Release(sample
);
888 EnterCriticalSection(&reader
->cs
);
890 for (i
= 0; i
< reader
->stream_count
; ++i
)
892 if (id
== reader
->streams
[i
].id
)
894 /* FIXME: propagate processing errors? */
895 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
896 hr
= source_reader_process_sample(reader
, &reader
->streams
[i
], sample
);
901 if (i
== reader
->stream_count
)
902 WARN("Stream with id %#lx was not present in presentation descriptor.\n", id
);
904 LeaveCriticalSection(&reader
->cs
);
906 IMFSample_Release(sample
);
911 static HRESULT
source_reader_media_stream_state_handler(struct source_reader
*reader
, IMFMediaStream
*stream
,
912 IMFMediaEvent
*event
)
914 MediaEventType event_type
;
921 IMFMediaEvent_GetType(event
, &event_type
);
923 if (FAILED(hr
= media_stream_get_id(stream
, &id
)))
925 WARN("Unidentified stream %p, hr %#lx.\n", stream
, hr
);
929 EnterCriticalSection(&reader
->cs
);
931 for (i
= 0; i
< reader
->stream_count
; ++i
)
933 struct media_stream
*stream
= &reader
->streams
[i
];
935 if (id
== stream
->id
)
943 stream
->state
= STREAM_STATE_EOS
;
944 stream
->flags
&= ~STREAM_FLAG_SAMPLE_REQUESTED
;
946 if ((ptr
= list_head(&stream
->transforms
)))
948 struct transform_entry
*entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
949 if (FAILED(hr
= source_reader_drain_transform_samples(reader
, stream
, entry
)))
950 WARN("Failed to drain pending samples, hr %#lx.\n", hr
);
953 while (stream
->requests
)
954 source_reader_queue_response(reader
, stream
, S_OK
, MF_SOURCE_READERF_ENDOFSTREAM
, 0, NULL
);
959 case MEStreamStarted
:
960 stream
->state
= STREAM_STATE_READY
;
962 case MEStreamStopped
:
963 stream
->flags
|= STREAM_FLAG_STOPPED
;
967 hr
= SUCCEEDED(IMFMediaEvent_GetValue(event
, &value
)) && value
.vt
== VT_I8
? S_OK
: E_UNEXPECTED
;
968 timestamp
= SUCCEEDED(hr
) ? value
.hVal
.QuadPart
: 0;
969 PropVariantClear(&value
);
971 source_reader_queue_response(reader
, stream
, hr
, MF_SOURCE_READERF_STREAMTICK
, timestamp
, NULL
);
982 LeaveCriticalSection(&reader
->cs
);
984 if (event_type
== MEStreamStopped
)
985 WakeAllConditionVariable(&reader
->stop_event
);
990 static HRESULT WINAPI
source_reader_stream_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
992 struct source_reader
*reader
= impl_from_stream_callback_IMFAsyncCallback(iface
);
993 MediaEventType event_type
;
994 IMFMediaStream
*stream
;
995 IMFMediaEvent
*event
;
998 TRACE("%p, %p.\n", iface
, result
);
1000 stream
= (IMFMediaStream
*)IMFAsyncResult_GetStateNoAddRef(result
);
1002 if (FAILED(hr
= IMFMediaStream_EndGetEvent(stream
, result
, &event
)))
1005 IMFMediaEvent_GetType(event
, &event_type
);
1007 TRACE("Got event %lu.\n", event_type
);
1012 hr
= source_reader_media_sample_handler(reader
, stream
, event
);
1014 case MEStreamSeeked
:
1015 case MEStreamStarted
:
1016 case MEStreamStopped
:
1019 hr
= source_reader_media_stream_state_handler(reader
, stream
, event
);
1026 WARN("Failed while handling %ld event, hr %#lx.\n", event_type
, hr
);
1028 IMFMediaEvent_Release(event
);
1030 if (event_type
!= MEStreamStopped
)
1031 IMFMediaStream_BeginGetEvent(stream
, iface
, (IUnknown
*)stream
);
1036 static const IMFAsyncCallbackVtbl stream_events_callback_vtbl
=
1038 source_reader_callback_QueryInterface
,
1039 source_reader_stream_events_callback_AddRef
,
1040 source_reader_stream_events_callback_Release
,
1041 source_reader_callback_GetParameters
,
1042 source_reader_stream_events_callback_Invoke
,
1045 static ULONG WINAPI
source_reader_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
1047 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1048 return source_reader_addref(reader
);
1051 static ULONG WINAPI
source_reader_async_commands_callback_Release(IMFAsyncCallback
*iface
)
1053 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1054 return source_reader_release(reader
);
1057 static struct stream_response
* media_stream_detach_response(struct source_reader
*reader
, struct stream_response
*response
)
1059 struct media_stream
*stream
;
1061 list_remove(&response
->entry
);
1063 if (response
->stream_index
< reader
->stream_count
)
1065 stream
= &reader
->streams
[response
->stream_index
];
1066 if (stream
->responses
)
1067 --stream
->responses
;
1073 static struct stream_response
*media_stream_pop_response(struct source_reader
*reader
, struct media_stream
*stream
)
1075 struct stream_response
*response
;
1079 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1081 if (stream
&& response
->stream_index
!= stream
->index
)
1084 if (!stream
) stream
= &reader
->streams
[response
->stream_index
];
1086 if (response
->sample
&& stream
->allocator
)
1088 /* Return allocation error to the caller, while keeping original response sample in for later. */
1089 if (SUCCEEDED(hr
= IMFVideoSampleAllocatorEx_AllocateSample(stream
->allocator
, &sample
)))
1091 source_reader_copy_sample_buffer(response
->sample
, sample
);
1092 IMFSample_Release(response
->sample
);
1093 response
->sample
= sample
;
1097 if (!(response
= calloc(1, sizeof(*response
))))
1100 response
->status
= hr
;
1101 response
->stream_flags
= MF_SOURCE_READERF_ERROR
;
1106 return media_stream_detach_response(reader
, response
);
1112 static void source_reader_release_response(struct stream_response
*response
)
1114 if (response
->sample
)
1115 IMFSample_Release(response
->sample
);
1119 static HRESULT
source_reader_get_stream_selection(const struct source_reader
*reader
, DWORD index
, BOOL
*selected
)
1121 IMFStreamDescriptor
*sd
;
1123 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, selected
, &sd
)))
1124 return MF_E_INVALIDSTREAMNUMBER
;
1125 IMFStreamDescriptor_Release(sd
);
1130 static HRESULT
source_reader_start_source(struct source_reader
*reader
)
1132 BOOL selected
, selection_changed
= FALSE
;
1133 PROPVARIANT position
;
1137 for (i
= 0; i
< reader
->stream_count
; ++i
)
1139 source_reader_get_stream_selection(reader
, i
, &selected
);
1141 reader
->streams
[i
].flags
|= STREAM_FLAG_SELECTED
;
1143 reader
->streams
[i
].flags
&= ~STREAM_FLAG_SELECTED
;
1146 if (reader
->source_state
== SOURCE_STATE_STARTED
)
1148 for (i
= 0; i
< reader
->stream_count
; ++i
)
1150 selection_changed
= !!(reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
) ^
1151 !!(reader
->streams
[i
].flags
& STREAM_FLAG_PRESENTED
);
1152 if (selection_changed
)
1157 position
.hVal
.QuadPart
= 0;
1158 if (reader
->source_state
!= SOURCE_STATE_STARTED
|| selection_changed
)
1160 position
.vt
= reader
->source_state
== SOURCE_STATE_STARTED
? VT_EMPTY
: VT_I8
;
1162 /* Update cached stream selection if descriptor was accepted. */
1163 if (SUCCEEDED(hr
= IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &GUID_NULL
, &position
)))
1165 for (i
= 0; i
< reader
->stream_count
; ++i
)
1167 if (reader
->streams
[i
].flags
& STREAM_FLAG_SELECTED
)
1168 reader
->streams
[i
].flags
|= STREAM_FLAG_PRESENTED
;
1176 static BOOL
source_reader_got_response_for_stream(struct source_reader
*reader
, struct media_stream
*stream
)
1178 struct stream_response
*response
;
1180 LIST_FOR_EACH_ENTRY(response
, &reader
->responses
, struct stream_response
, entry
)
1182 if (response
->stream_index
== stream
->index
)
1189 static BOOL
source_reader_get_read_result(struct source_reader
*reader
, struct media_stream
*stream
, DWORD flags
,
1190 HRESULT
*status
, DWORD
*stream_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
1192 struct stream_response
*response
= NULL
;
1193 BOOL request_sample
= FALSE
;
1195 if ((response
= media_stream_pop_response(reader
, stream
)))
1197 *status
= response
->status
;
1198 *stream_index
= stream
->index
;
1199 *stream_flags
= response
->stream_flags
;
1200 *timestamp
= response
->timestamp
;
1201 *sample
= response
->sample
;
1203 IMFSample_AddRef(*sample
);
1205 source_reader_release_response(response
);
1210 *stream_index
= stream
->index
;
1214 if (stream
->state
== STREAM_STATE_EOS
)
1216 *stream_flags
= MF_SOURCE_READERF_ENDOFSTREAM
;
1220 request_sample
= !(flags
& MF_SOURCE_READER_CONTROLF_DRAIN
);
1225 return !request_sample
;
1228 static HRESULT
source_reader_get_next_selected_stream(struct source_reader
*reader
, DWORD
*stream_index
)
1230 unsigned int i
, first_selected
= ~0u;
1231 BOOL selected
, stream_drained
;
1232 LONGLONG min_ts
= MAXLONGLONG
;
1234 for (i
= 0; i
< reader
->stream_count
; ++i
)
1236 stream_drained
= reader
->streams
[i
].state
== STREAM_STATE_EOS
&& !reader
->streams
[i
].responses
;
1237 selected
= SUCCEEDED(source_reader_get_stream_selection(reader
, i
, &selected
)) && selected
;
1241 if (first_selected
== ~0u)
1244 /* Pick the stream whose last sample had the lowest timestamp. */
1245 if (!stream_drained
&& reader
->streams
[i
].last_sample_ts
< min_ts
)
1247 min_ts
= reader
->streams
[i
].last_sample_ts
;
1253 /* If all selected streams reached EOS, use first selected. */
1254 if (first_selected
!= ~0u)
1256 if (min_ts
== MAXLONGLONG
)
1257 *stream_index
= first_selected
;
1260 return first_selected
== ~0u ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED
: S_OK
;
1263 static HRESULT
source_reader_get_stream_read_index(struct source_reader
*reader
, unsigned int index
, DWORD
*stream_index
)
1270 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1271 *stream_index
= reader
->first_video_stream_index
;
1273 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1274 *stream_index
= reader
->first_audio_stream_index
;
1276 case MF_SOURCE_READER_ANY_STREAM
:
1277 return source_reader_get_next_selected_stream(reader
, stream_index
);
1279 *stream_index
= index
;
1282 /* Can't read from deselected streams. */
1283 if (SUCCEEDED(hr
= source_reader_get_stream_selection(reader
, *stream_index
, &selected
)) && !selected
)
1284 hr
= MF_E_INVALIDREQUEST
;
1289 static void source_reader_release_responses(struct source_reader
*reader
, struct media_stream
*stream
)
1291 struct stream_response
*ptr
, *next
;
1293 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &reader
->responses
, struct stream_response
, entry
)
1295 if (stream
&& stream
->index
!= ptr
->stream_index
&&
1296 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_VIDEO_STREAM
&&
1297 ptr
->stream_index
!= MF_SOURCE_READER_FIRST_AUDIO_STREAM
&&
1298 ptr
->stream_index
!= MF_SOURCE_READER_ANY_STREAM
)
1302 media_stream_detach_response(reader
, ptr
);
1303 source_reader_release_response(ptr
);
1307 static void source_reader_flush_stream(struct source_reader
*reader
, DWORD stream_index
)
1309 struct media_stream
*stream
= &reader
->streams
[stream_index
];
1313 source_reader_release_responses(reader
, stream
);
1315 if ((ptr
= list_head(&stream
->transforms
)))
1317 struct transform_entry
*entry
= LIST_ENTRY(ptr
, struct transform_entry
, entry
);
1318 if (FAILED(hr
= source_reader_flush_transform_samples(reader
, stream
, entry
)))
1319 WARN("Failed to drain pending samples, hr %#lx.\n", hr
);
1322 stream
->requests
= 0;
1325 static HRESULT
source_reader_flush(struct source_reader
*reader
, unsigned int index
)
1327 unsigned int stream_index
;
1330 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1332 for (stream_index
= 0; stream_index
< reader
->stream_count
; ++stream_index
)
1333 source_reader_flush_stream(reader
, stream_index
);
1339 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1340 stream_index
= reader
->first_video_stream_index
;
1342 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1343 stream_index
= reader
->first_audio_stream_index
;
1346 stream_index
= index
;
1349 if (stream_index
< reader
->stream_count
)
1350 source_reader_flush_stream(reader
, stream_index
);
1352 hr
= MF_E_INVALIDSTREAMNUMBER
;
1358 static HRESULT WINAPI
source_reader_async_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1360 struct source_reader
*reader
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
1361 struct media_stream
*stream
, stub_stream
= { .requests
= 1 };
1362 struct source_reader_async_command
*command
;
1363 struct stream_response
*response
;
1364 DWORD stream_index
, stream_flags
;
1365 BOOL report_sample
= FALSE
;
1366 IMFSample
*sample
= NULL
;
1367 LONGLONG timestamp
= 0;
1371 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
1374 command
= impl_from_async_command_IUnknown(state
);
1376 switch (command
->op
)
1378 case SOURCE_READER_ASYNC_READ
:
1379 EnterCriticalSection(&reader
->cs
);
1381 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
1383 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, command
->u
.read
.stream_index
, &stream_index
)))
1385 stream
= &reader
->streams
[stream_index
];
1387 if (!(report_sample
= source_reader_get_read_result(reader
, stream
, command
->u
.read
.flags
, &status
,
1388 &stream_index
, &stream_flags
, ×tamp
, &sample
)))
1391 source_reader_request_sample(reader
, stream
);
1392 /* FIXME: set error stream/reader state on request failure */
1397 stub_stream
.index
= command
->u
.read
.stream_index
;
1398 source_reader_queue_response(reader
, &stub_stream
, hr
, MF_SOURCE_READERF_ERROR
, 0, NULL
);
1402 LeaveCriticalSection(&reader
->cs
);
1405 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, status
, stream_index
, stream_flags
,
1409 IMFSample_Release(sample
);
1413 case SOURCE_READER_ASYNC_SEEK
:
1415 EnterCriticalSection(&reader
->cs
);
1416 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, &command
->u
.seek
.format
,
1417 &command
->u
.seek
.position
)))
1419 reader
->flags
|= SOURCE_READER_SEEKING
;
1421 LeaveCriticalSection(&reader
->cs
);
1425 case SOURCE_READER_ASYNC_SAMPLE_READY
:
1427 EnterCriticalSection(&reader
->cs
);
1428 response
= media_stream_pop_response(reader
, NULL
);
1429 LeaveCriticalSection(&reader
->cs
);
1433 IMFSourceReaderCallback_OnReadSample(reader
->async_callback
, response
->status
, response
->stream_index
,
1434 response
->stream_flags
, response
->timestamp
, response
->sample
);
1435 source_reader_release_response(response
);
1439 case SOURCE_READER_ASYNC_FLUSH
:
1440 EnterCriticalSection(&reader
->cs
);
1441 source_reader_flush(reader
, command
->u
.flush
.stream_index
);
1442 reader
->flags
&= ~SOURCE_READER_FLUSHING
;
1443 LeaveCriticalSection(&reader
->cs
);
1445 IMFSourceReaderCallback_OnFlush(reader
->async_callback
, command
->u
.flush
.stream_index
);
1451 IUnknown_Release(state
);
1456 static const IMFAsyncCallbackVtbl async_commands_callback_vtbl
=
1458 source_reader_callback_QueryInterface
,
1459 source_reader_async_commands_callback_AddRef
,
1460 source_reader_async_commands_callback_Release
,
1461 source_reader_callback_GetParameters
,
1462 source_reader_async_commands_callback_Invoke
,
1465 static HRESULT WINAPI
src_reader_QueryInterface(IMFSourceReaderEx
*iface
, REFIID riid
, void **out
)
1467 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1469 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1471 if (IsEqualGUID(riid
, &IID_IUnknown
)
1472 || IsEqualGUID(riid
, &IID_IMFSourceReader
)
1473 || IsEqualGUID(riid
, &IID_IMFSourceReaderEx
))
1475 *out
= &reader
->IMFSourceReaderEx_iface
;
1479 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1481 return E_NOINTERFACE
;
1484 IUnknown_AddRef((IUnknown
*)*out
);
1488 static ULONG WINAPI
src_reader_AddRef(IMFSourceReaderEx
*iface
)
1490 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1491 ULONG refcount
= InterlockedIncrement(&reader
->public_refcount
);
1493 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1498 static BOOL
source_reader_is_source_stopped(const struct source_reader
*reader
)
1502 if (reader
->source_state
!= SOURCE_STATE_STOPPED
)
1505 for (i
= 0; i
< reader
->stream_count
; ++i
)
1507 if (reader
->streams
[i
].stream
&& !(reader
->streams
[i
].flags
& STREAM_FLAG_STOPPED
))
1514 static ULONG WINAPI
src_reader_Release(IMFSourceReaderEx
*iface
)
1516 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1517 ULONG refcount
= InterlockedDecrement(&reader
->public_refcount
);
1520 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1524 if (reader
->flags
& SOURCE_READER_SHUTDOWN_ON_RELEASE
)
1525 IMFMediaSource_Shutdown(reader
->source
);
1526 else if (SUCCEEDED(IMFMediaSource_Stop(reader
->source
)))
1528 EnterCriticalSection(&reader
->cs
);
1530 while (!source_reader_is_source_stopped(reader
))
1532 SleepConditionVariableCS(&reader
->stop_event
, &reader
->cs
, INFINITE
);
1535 LeaveCriticalSection(&reader
->cs
);
1538 for (i
= 0; i
< reader
->stream_count
; ++i
)
1540 struct media_stream
*stream
= &reader
->streams
[i
];
1541 IMFVideoSampleAllocatorCallback
*callback
;
1543 if (!stream
->allocator
)
1546 if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream
->allocator
, &IID_IMFVideoSampleAllocatorCallback
,
1547 (void **)&callback
)))
1549 IMFVideoSampleAllocatorCallback_SetCallback(callback
, NULL
);
1550 IMFVideoSampleAllocatorCallback_Release(callback
);
1554 source_reader_release(reader
);
1560 static HRESULT WINAPI
src_reader_GetStreamSelection(IMFSourceReaderEx
*iface
, DWORD index
, BOOL
*selected
)
1562 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1564 TRACE("%p, %#lx, %p.\n", iface
, index
, selected
);
1568 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1569 index
= reader
->first_video_stream_index
;
1571 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1572 index
= reader
->first_audio_stream_index
;
1578 return source_reader_get_stream_selection(reader
, index
, selected
);
1581 static HRESULT WINAPI
src_reader_SetStreamSelection(IMFSourceReaderEx
*iface
, DWORD index
, BOOL selection
)
1583 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1585 BOOL selection_changed
= FALSE
, selected
;
1588 TRACE("%p, %#lx, %d.\n", iface
, index
, selection
);
1590 selection
= !!selection
;
1592 EnterCriticalSection(&reader
->cs
);
1594 if (index
== MF_SOURCE_READER_ALL_STREAMS
)
1596 for (i
= 0; i
< reader
->stream_count
; ++i
)
1598 if (!selection_changed
)
1600 source_reader_get_stream_selection(reader
, i
, &selected
);
1601 selection_changed
= !!(selected
^ selection
);
1605 IMFPresentationDescriptor_SelectStream(reader
->descriptor
, i
);
1607 IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, i
);
1614 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1615 index
= reader
->first_video_stream_index
;
1617 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1618 index
= reader
->first_audio_stream_index
;
1624 source_reader_get_stream_selection(reader
, index
, &selected
);
1625 selection_changed
= !!(selected
^ selection
);
1628 hr
= IMFPresentationDescriptor_SelectStream(reader
->descriptor
, index
);
1630 hr
= IMFPresentationDescriptor_DeselectStream(reader
->descriptor
, index
);
1633 if (selection_changed
)
1635 for (i
= 0; i
< reader
->stream_count
; ++i
)
1637 reader
->streams
[i
].last_sample_ts
= 0;
1641 LeaveCriticalSection(&reader
->cs
);
1643 return SUCCEEDED(hr
) ? S_OK
: MF_E_INVALIDSTREAMNUMBER
;
1646 static HRESULT
source_reader_get_native_media_type(struct source_reader
*reader
, DWORD index
, DWORD type_index
,
1647 IMFMediaType
**type
)
1649 IMFMediaTypeHandler
*handler
;
1650 IMFStreamDescriptor
*sd
;
1651 IMFMediaType
*src_type
;
1657 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1658 index
= reader
->first_video_stream_index
;
1660 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1661 index
= reader
->first_audio_stream_index
;
1667 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1668 return MF_E_INVALIDSTREAMNUMBER
;
1670 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
1671 IMFStreamDescriptor_Release(sd
);
1675 if (type_index
== MF_SOURCE_READER_CURRENT_TYPE_INDEX
)
1676 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, &src_type
);
1678 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, type_index
, &src_type
);
1679 IMFMediaTypeHandler_Release(handler
);
1683 if (SUCCEEDED(hr
= MFCreateMediaType(type
)))
1684 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)*type
);
1685 IMFMediaType_Release(src_type
);
1691 static HRESULT WINAPI
src_reader_GetNativeMediaType(IMFSourceReaderEx
*iface
, DWORD index
, DWORD type_index
,
1692 IMFMediaType
**type
)
1694 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1696 TRACE("%p, %#lx, %#lx, %p.\n", iface
, index
, type_index
, type
);
1698 return source_reader_get_native_media_type(reader
, index
, type_index
, type
);
1701 static HRESULT WINAPI
src_reader_GetCurrentMediaType(IMFSourceReaderEx
*iface
, DWORD index
, IMFMediaType
**type
)
1703 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
1706 TRACE("%p, %#lx, %p.\n", iface
, index
, type
);
1710 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
1711 index
= reader
->first_video_stream_index
;
1713 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
1714 index
= reader
->first_audio_stream_index
;
1720 if (index
>= reader
->stream_count
)
1721 return MF_E_INVALIDSTREAMNUMBER
;
1723 if (FAILED(hr
= MFCreateMediaType(type
)))
1726 EnterCriticalSection(&reader
->cs
);
1728 hr
= IMFMediaType_CopyAllItems(reader
->streams
[index
].current
, (IMFAttributes
*)*type
);
1730 LeaveCriticalSection(&reader
->cs
);
1735 static HRESULT
source_reader_get_source_type_handler(struct source_reader
*reader
, DWORD index
,
1736 IMFMediaTypeHandler
**handler
)
1738 IMFStreamDescriptor
*sd
;
1742 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
1745 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, handler
);
1746 IMFStreamDescriptor_Release(sd
);
1751 static HRESULT
source_reader_set_compatible_media_type(struct source_reader
*reader
, DWORD index
, IMFMediaType
*type
)
1753 struct media_stream
*stream
= &reader
->streams
[index
];
1754 struct transform_entry
*entry
, *next
;
1755 IMFMediaTypeHandler
*type_handler
;
1756 IMFMediaType
*native_type
;
1757 BOOL type_set
= FALSE
;
1762 if (FAILED(hr
= IMFMediaType_IsEqual(type
, stream
->current
, &flags
)))
1765 if (!(flags
& MF_MEDIATYPE_EQUAL_MAJOR_TYPES
))
1766 return MF_E_INVALIDMEDIATYPE
;
1768 /* No need for a decoder or type change. */
1769 if (flags
& MF_MEDIATYPE_EQUAL_FORMAT_DATA
)
1772 if (stream
->transform_service
)
1774 IMFTransform_Release(stream
->transform_service
);
1775 stream
->transform_service
= NULL
;
1777 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &stream
->transforms
, struct transform_entry
, entry
)
1779 list_remove(&entry
->entry
);
1780 transform_entry_destroy(entry
);
1783 if (FAILED(hr
= source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
1786 while (!type_set
&& IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler
, i
++, &native_type
) == S_OK
)
1788 static const DWORD compare_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_DATA
;
1790 if (SUCCEEDED(IMFMediaType_IsEqual(native_type
, type
, &flags
)) && (flags
& compare_flags
) == compare_flags
)
1792 if ((type_set
= SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, native_type
))))
1793 IMFMediaType_CopyAllItems(native_type
, (IMFAttributes
*)stream
->current
);
1796 IMFMediaType_Release(native_type
);
1799 IMFMediaTypeHandler_Release(type_handler
);
1801 return type_set
? S_OK
: S_FALSE
;
1804 static HRESULT
source_reader_create_sample_allocator_attributes(const struct source_reader
*reader
,
1805 IMFAttributes
**attributes
)
1807 UINT32 shared
= 0, shared_without_mutex
= 0;
1810 if (FAILED(hr
= MFCreateAttributes(attributes
, 1)))
1813 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED
, &shared
);
1814 IMFAttributes_GetUINT32(reader
->attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, &shared_without_mutex
);
1816 if (shared_without_mutex
)
1817 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX
, TRUE
);
1819 hr
= IMFAttributes_SetUINT32(*attributes
, &MF_SA_D3D11_SHARED
, TRUE
);
1824 static HRESULT
source_reader_setup_sample_allocator(struct source_reader
*reader
, unsigned int index
)
1826 struct media_stream
*stream
= &reader
->streams
[index
];
1827 IMFAttributes
*attributes
= NULL
;
1831 IMFMediaType_GetMajorType(stream
->current
, &major
);
1832 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
1835 if (!(reader
->flags
& SOURCE_READER_HAS_DEVICE_MANAGER
))
1838 if (!stream
->allocator
)
1840 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&stream
->allocator
)))
1842 WARN("Failed to create sample allocator, hr %#lx.\n", hr
);
1847 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream
->allocator
);
1848 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(stream
->allocator
, reader
->device_manager
)))
1850 WARN("Failed to set device manager, hr %#lx.\n", hr
);
1854 if (FAILED(hr
= source_reader_create_sample_allocator_attributes(reader
, &attributes
)))
1855 WARN("Failed to create allocator attributes, hr %#lx.\n", hr
);
1857 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream
->allocator
, 2, 8,
1858 attributes
, stream
->current
)))
1860 WARN("Failed to initialize sample allocator, hr %#lx.\n", hr
);
1864 IMFAttributes_Release(attributes
);
1869 static BOOL
source_reader_allow_video_processor(struct source_reader
*reader
, BOOL
*advanced
)
1874 if (!reader
->attributes
)
1877 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING
, &value
)))
1879 if (SUCCEEDED(IMFAttributes_GetUINT32(reader
->attributes
, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING
, &value
)))
1880 return value
|| *advanced
;
1885 static HRESULT
source_reader_create_transform(struct source_reader
*reader
, BOOL decoder
, BOOL allow_processor
,
1886 IMFMediaType
*input_type
, IMFMediaType
*output_type
, struct transform_entry
**out
)
1888 MFT_REGISTER_TYPE_INFO in_type
, out_type
;
1889 struct transform_entry
*entry
;
1890 GUID
*classes
, category
;
1891 IMFTransform
*transform
;
1895 if (FAILED(hr
= IMFMediaType_GetMajorType(input_type
, &in_type
.guidMajorType
))
1896 || FAILED(hr
= IMFMediaType_GetGUID(input_type
, &MF_MT_SUBTYPE
, &in_type
.guidSubtype
)))
1898 if (FAILED(hr
= IMFMediaType_GetMajorType(output_type
, &out_type
.guidMajorType
))
1899 || FAILED(hr
= IMFMediaType_GetGUID(output_type
, &MF_MT_SUBTYPE
, &out_type
.guidSubtype
)))
1902 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Video
))
1903 category
= decoder
? MFT_CATEGORY_VIDEO_DECODER
: MFT_CATEGORY_VIDEO_PROCESSOR
;
1904 else if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1905 category
= decoder
? MFT_CATEGORY_AUDIO_DECODER
: MFT_CATEGORY_AUDIO_EFFECT
;
1907 return MF_E_TOPO_CODEC_NOT_FOUND
;
1909 if (!(entry
= calloc(1, sizeof(*entry
))))
1910 return E_OUTOFMEMORY
;
1911 list_init(&entry
->entry
);
1912 entry
->category
= category
;
1914 if (IsEqualGUID(&out_type
.guidMajorType
, &MFMediaType_Audio
))
1915 IMFMediaType_GetUINT32(output_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
,
1916 &entry
->min_buffer_size
);
1919 if (SUCCEEDED(hr
= MFTEnum(category
, 0, &in_type
, allow_processor
? NULL
: &out_type
, NULL
, &classes
, &count
)))
1922 return MF_E_TOPO_CODEC_NOT_FOUND
;
1924 for (i
= 0; i
< count
; i
++)
1926 IMFMediaType
*media_type
;
1928 if (FAILED(hr
= CoCreateInstance(&classes
[i
], NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTransform
, (void **)&transform
)))
1930 if (SUCCEEDED(hr
= IMFTransform_SetInputType(transform
, 0, input_type
, 0))
1931 && SUCCEEDED(hr
= IMFTransform_GetInputCurrentType(transform
, 0, &media_type
)))
1933 if (SUCCEEDED(hr
= update_media_type_from_upstream(output_type
, media_type
))
1934 && FAILED(hr
= IMFTransform_SetOutputType(transform
, 0, output_type
, 0)) && allow_processor
1935 && SUCCEEDED(hr
= IMFTransform_GetOutputAvailableType(transform
, 0, 0, &media_type
)))
1937 struct transform_entry
*converter
;
1939 if (SUCCEEDED(hr
= IMFTransform_SetOutputType(transform
, 0, media_type
, 0))
1940 && SUCCEEDED(hr
= update_media_type_from_upstream(output_type
, media_type
))
1941 && SUCCEEDED(hr
= source_reader_create_transform(reader
, FALSE
, FALSE
, media_type
, output_type
, &converter
)))
1942 list_add_tail(&entry
->entry
, &converter
->entry
);
1944 IMFMediaType_Release(media_type
);
1949 entry
->transform
= transform
;
1955 IMFTransform_Release(transform
);
1958 CoTaskMemFree(classes
);
1965 static HRESULT
source_reader_create_decoder_for_stream(struct source_reader
*reader
, DWORD index
, IMFMediaType
*output_type
)
1967 BOOL enable_advanced
, allow_processor
;
1968 struct media_stream
*stream
= &reader
->streams
[index
];
1969 IMFMediaType
*input_type
;
1973 allow_processor
= source_reader_allow_video_processor(reader
, &enable_advanced
);
1975 while (SUCCEEDED(hr
= source_reader_get_native_media_type(reader
, index
, i
++, &input_type
)))
1977 struct transform_entry
*entry
;
1979 /* first, try to append a single processor, then try again with a decoder and a processor */
1980 if ((allow_processor
&& SUCCEEDED(hr
= source_reader_create_transform(reader
, FALSE
, FALSE
, input_type
, output_type
, &entry
)))
1981 || SUCCEEDED(hr
= source_reader_create_transform(reader
, TRUE
, allow_processor
, input_type
, output_type
, &entry
)))
1983 struct list
*ptr
= list_head(&entry
->entry
);
1984 struct transform_entry
*service
= ptr
? LIST_ENTRY(ptr
, struct transform_entry
, entry
) : entry
;
1985 IMFMediaTypeHandler
*type_handler
;
1987 if (enable_advanced
)
1989 /* when advanced video processing is enabled, converters are exposed as stream transform service */
1990 stream
->transform_service
= service
->transform
;
1991 IMFTransform_AddRef(stream
->transform_service
);
1995 /* when advanced video processing is disabled, only decoders are exposed as stream transform service */
1996 if (IsEqualGUID(&entry
->category
, &MFT_CATEGORY_AUDIO_DECODER
)
1997 || IsEqualGUID(&entry
->category
, &MFT_CATEGORY_VIDEO_DECODER
))
1999 stream
->transform_service
= entry
->transform
;
2000 IMFTransform_AddRef(stream
->transform_service
);
2004 /* move any additional transforms that have been created */
2005 list_move_head(&stream
->transforms
, &entry
->entry
);
2006 list_add_head(&stream
->transforms
, &entry
->entry
);
2008 if (SUCCEEDED(source_reader_get_source_type_handler(reader
, index
, &type_handler
)))
2010 if (FAILED(hr
= IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, input_type
)))
2011 WARN("Failed to set current input media type, hr %#lx\n", hr
);
2012 IMFMediaTypeHandler_Release(type_handler
);
2015 if (FAILED(hr
= IMFTransform_GetOutputCurrentType(service
->transform
, 0, &output_type
)))
2016 WARN("Failed to get decoder output media type, hr %#lx\n", hr
);
2019 IMFMediaType_CopyAllItems(output_type
, (IMFAttributes
*)stream
->current
);
2020 IMFMediaType_Release(output_type
);
2023 IMFMediaType_Release(input_type
);
2027 IMFMediaType_Release(input_type
);
2030 return MF_E_TOPO_CODEC_NOT_FOUND
;
2033 static HRESULT WINAPI
src_reader_SetCurrentMediaType(IMFSourceReaderEx
*iface
, DWORD index
, DWORD
*reserved
,
2036 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2039 TRACE("%p, %#lx, %p, %p.\n", iface
, index
, reserved
, type
);
2043 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2044 index
= reader
->first_video_stream_index
;
2046 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2047 index
= reader
->first_audio_stream_index
;
2053 if (index
>= reader
->stream_count
)
2054 return MF_E_INVALIDSTREAMNUMBER
;
2056 /* FIXME: setting the output type while streaming should trigger a flush */
2058 EnterCriticalSection(&reader
->cs
);
2060 hr
= source_reader_set_compatible_media_type(reader
, index
, type
);
2062 hr
= source_reader_create_decoder_for_stream(reader
, index
, type
);
2064 hr
= source_reader_setup_sample_allocator(reader
, index
);
2066 LeaveCriticalSection(&reader
->cs
);
2071 static HRESULT WINAPI
src_reader_SetCurrentPosition(IMFSourceReaderEx
*iface
, REFGUID format
, REFPROPVARIANT position
)
2073 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2074 struct source_reader_async_command
*command
;
2079 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), position
);
2081 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2084 if (!(flags
& MFMEDIASOURCE_CAN_SEEK
))
2085 return MF_E_INVALIDREQUEST
;
2087 EnterCriticalSection(&reader
->cs
);
2089 /* Check if we got pending requests. */
2090 for (i
= 0; i
< reader
->stream_count
; ++i
)
2092 if (reader
->streams
[i
].requests
)
2094 hr
= MF_E_INVALIDREQUEST
;
2101 for (i
= 0; i
< reader
->stream_count
; ++i
)
2103 reader
->streams
[i
].last_sample_ts
= 0;
2106 if (reader
->async_callback
)
2108 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK
, &command
)))
2110 command
->u
.seek
.format
= *format
;
2111 PropVariantCopy(&command
->u
.seek
.position
, position
);
2113 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2114 IUnknown_Release(&command
->IUnknown_iface
);
2119 if (SUCCEEDED(IMFMediaSource_Start(reader
->source
, reader
->descriptor
, format
, position
)))
2121 reader
->flags
|= SOURCE_READER_SEEKING
;
2122 while (reader
->flags
& SOURCE_READER_SEEKING
)
2124 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2130 LeaveCriticalSection(&reader
->cs
);
2135 static HRESULT
source_reader_read_sample(struct source_reader
*reader
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
2136 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2138 struct media_stream
*stream
;
2139 DWORD actual_index_tmp
;
2140 LONGLONG timestamp_tmp
;
2144 if (!stream_flags
|| !sample
)
2150 timestamp
= ×tamp_tmp
;
2153 actual_index
= &actual_index_tmp
;
2155 if (SUCCEEDED(hr
= source_reader_start_source(reader
)))
2157 if (SUCCEEDED(hr
= source_reader_get_stream_read_index(reader
, index
, &stream_index
)))
2159 *actual_index
= stream_index
;
2161 stream
= &reader
->streams
[stream_index
];
2163 if (!source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
2166 while (!source_reader_got_response_for_stream(reader
, stream
) && stream
->state
!= STREAM_STATE_EOS
)
2169 if (FAILED(hr
= source_reader_request_sample(reader
, stream
)))
2170 WARN("Failed to request a sample, hr %#lx.\n", hr
);
2171 if (stream
->stream
&& !(stream
->flags
& STREAM_FLAG_SAMPLE_REQUESTED
))
2173 *stream_flags
= MF_SOURCE_READERF_ERROR
;
2177 SleepConditionVariableCS(&reader
->sample_event
, &reader
->cs
, INFINITE
);
2180 source_reader_get_read_result(reader
, stream
, flags
, &hr
, actual_index
, stream_flags
,
2186 *actual_index
= index
;
2187 *stream_flags
= MF_SOURCE_READERF_ERROR
;
2192 TRACE("Stream %lu, got sample %p, flags %#lx.\n", *actual_index
, *sample
, *stream_flags
);
2197 static HRESULT
source_reader_read_sample_async(struct source_reader
*reader
, unsigned int index
, unsigned int flags
,
2198 DWORD
*actual_index
, DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2200 struct source_reader_async_command
*command
;
2203 if (actual_index
|| stream_flags
|| timestamp
|| sample
)
2204 return E_INVALIDARG
;
2206 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2207 hr
= MF_E_NOTACCEPTING
;
2210 if (SUCCEEDED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_READ
, &command
)))
2212 command
->u
.read
.stream_index
= index
;
2213 command
->u
.read
.flags
= flags
;
2215 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2216 IUnknown_Release(&command
->IUnknown_iface
);
2223 static HRESULT WINAPI
src_reader_ReadSample(IMFSourceReaderEx
*iface
, DWORD index
, DWORD flags
, DWORD
*actual_index
,
2224 DWORD
*stream_flags
, LONGLONG
*timestamp
, IMFSample
**sample
)
2226 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2229 TRACE("%p, %#lx, %#lx, %p, %p, %p, %p\n", iface
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2231 EnterCriticalSection(&reader
->cs
);
2233 while (reader
->flags
& SOURCE_READER_SEEKING
)
2235 SleepConditionVariableCS(&reader
->state_event
, &reader
->cs
, INFINITE
);
2238 if (reader
->async_callback
)
2239 hr
= source_reader_read_sample_async(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2241 hr
= source_reader_read_sample(reader
, index
, flags
, actual_index
, stream_flags
, timestamp
, sample
);
2243 LeaveCriticalSection(&reader
->cs
);
2248 static HRESULT
source_reader_flush_async(struct source_reader
*reader
, unsigned int index
)
2250 struct source_reader_async_command
*command
;
2251 unsigned int stream_index
;
2254 if (reader
->flags
& SOURCE_READER_FLUSHING
)
2255 return MF_E_INVALIDREQUEST
;
2259 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2260 stream_index
= reader
->first_video_stream_index
;
2262 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2263 stream_index
= reader
->first_audio_stream_index
;
2266 stream_index
= index
;
2269 reader
->flags
|= SOURCE_READER_FLUSHING
;
2271 if (stream_index
!= MF_SOURCE_READER_ALL_STREAMS
&& stream_index
>= reader
->stream_count
)
2272 return MF_E_INVALIDSTREAMNUMBER
;
2274 if (FAILED(hr
= source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH
, &command
)))
2277 command
->u
.flush
.stream_index
= stream_index
;
2279 hr
= MFPutWorkItem(reader
->queue
, &reader
->async_commands_callback
, &command
->IUnknown_iface
);
2280 IUnknown_Release(&command
->IUnknown_iface
);
2285 static HRESULT WINAPI
src_reader_Flush(IMFSourceReaderEx
*iface
, DWORD index
)
2287 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2290 TRACE("%p, %#lx.\n", iface
, index
);
2292 EnterCriticalSection(&reader
->cs
);
2294 if (reader
->async_callback
)
2295 hr
= source_reader_flush_async(reader
, index
);
2297 hr
= source_reader_flush(reader
, index
);
2299 LeaveCriticalSection(&reader
->cs
);
2304 static HRESULT WINAPI
src_reader_GetServiceForStream(IMFSourceReaderEx
*iface
, DWORD index
, REFGUID service
,
2305 REFIID riid
, void **object
)
2307 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2308 struct media_stream
*stream
= &reader
->streams
[index
];
2309 IUnknown
*obj
= NULL
;
2312 TRACE("%p, %#lx, %s, %s, %p\n", iface
, index
, debugstr_guid(service
), debugstr_guid(riid
), object
);
2314 EnterCriticalSection(&reader
->cs
);
2318 case MF_SOURCE_READER_MEDIASOURCE
:
2319 obj
= (IUnknown
*)reader
->source
;
2322 if (index
== MF_SOURCE_READER_FIRST_VIDEO_STREAM
)
2323 index
= reader
->first_video_stream_index
;
2324 else if (index
== MF_SOURCE_READER_FIRST_AUDIO_STREAM
)
2325 index
= reader
->first_audio_stream_index
;
2327 if (index
>= reader
->stream_count
)
2328 hr
= MF_E_INVALIDSTREAMNUMBER
;
2329 else if (!(obj
= (IUnknown
*)stream
->transform_service
))
2335 IUnknown_AddRef(obj
);
2337 LeaveCriticalSection(&reader
->cs
);
2341 if (IsEqualGUID(service
, &GUID_NULL
))
2343 hr
= IUnknown_QueryInterface(obj
, riid
, object
);
2349 hr
= IUnknown_QueryInterface(obj
, &IID_IMFGetService
, (void **)&gs
);
2352 hr
= IMFGetService_GetService(gs
, service
, riid
, object
);
2353 IMFGetService_Release(gs
);
2359 IUnknown_Release(obj
);
2364 static HRESULT WINAPI
src_reader_GetPresentationAttribute(IMFSourceReaderEx
*iface
, DWORD index
,
2365 REFGUID guid
, PROPVARIANT
*value
)
2367 struct source_reader
*reader
= impl_from_IMFSourceReaderEx(iface
);
2368 IMFStreamDescriptor
*sd
;
2372 TRACE("%p, %#lx, %s, %p.\n", iface
, index
, debugstr_guid(guid
), value
);
2376 case MF_SOURCE_READER_MEDIASOURCE
:
2377 if (IsEqualGUID(guid
, &MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS
))
2381 if (FAILED(hr
= IMFMediaSource_GetCharacteristics(reader
->source
, &flags
)))
2385 value
->ulVal
= flags
;
2390 return IMFPresentationDescriptor_GetItem(reader
->descriptor
, guid
, value
);
2393 case MF_SOURCE_READER_FIRST_VIDEO_STREAM
:
2394 index
= reader
->first_video_stream_index
;
2396 case MF_SOURCE_READER_FIRST_AUDIO_STREAM
:
2397 index
= reader
->first_audio_stream_index
;
2403 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader
->descriptor
, index
, &selected
, &sd
)))
2406 hr
= IMFStreamDescriptor_GetItem(sd
, guid
, value
);
2407 IMFStreamDescriptor_Release(sd
);
2412 static HRESULT WINAPI
src_reader_SetNativeMediaType(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2413 IMFMediaType
*media_type
, DWORD
*stream_flags
)
2415 FIXME("%p, %#lx, %p, %p.\n", iface
, stream_index
, media_type
, stream_flags
);
2420 static HRESULT WINAPI
src_reader_AddTransformForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2421 IUnknown
*transform
)
2423 FIXME("%p, %#lx, %p.\n", iface
, stream_index
, transform
);
2428 static HRESULT WINAPI
src_reader_RemoveAllTransformsForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
)
2430 FIXME("%p, %#lx.\n", iface
, stream_index
);
2435 static HRESULT WINAPI
src_reader_GetTransformForStream(IMFSourceReaderEx
*iface
, DWORD stream_index
,
2436 DWORD transform_index
, GUID
*category
, IMFTransform
**transform
)
2438 FIXME("%p, %#lx, %#lx, %p, %p.\n", iface
, stream_index
, transform_index
, category
, transform
);
2443 static const IMFSourceReaderExVtbl srcreader_vtbl
=
2445 src_reader_QueryInterface
,
2448 src_reader_GetStreamSelection
,
2449 src_reader_SetStreamSelection
,
2450 src_reader_GetNativeMediaType
,
2451 src_reader_GetCurrentMediaType
,
2452 src_reader_SetCurrentMediaType
,
2453 src_reader_SetCurrentPosition
,
2454 src_reader_ReadSample
,
2456 src_reader_GetServiceForStream
,
2457 src_reader_GetPresentationAttribute
,
2458 src_reader_SetNativeMediaType
,
2459 src_reader_AddTransformForStream
,
2460 src_reader_RemoveAllTransformsForStream
,
2461 src_reader_GetTransformForStream
,
2464 static DWORD
reader_get_first_stream_index(IMFPresentationDescriptor
*descriptor
, const GUID
*major
)
2471 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
2472 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2474 for (i
= 0; i
< count
; ++i
)
2476 IMFMediaTypeHandler
*handler
;
2477 IMFStreamDescriptor
*sd
;
2479 if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
, &selected
, &sd
)))
2481 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2482 IMFStreamDescriptor_Release(sd
);
2485 hr
= IMFMediaTypeHandler_GetMajorType(handler
, &guid
);
2486 IMFMediaTypeHandler_Release(handler
);
2489 WARN("Failed to get stream major type, hr %#lx.\n", hr
);
2493 if (IsEqualGUID(&guid
, major
))
2501 return MF_SOURCE_READER_INVALID_STREAM_INDEX
;
2504 static HRESULT
create_source_reader_from_source(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2505 BOOL shutdown_on_release
, REFIID riid
, void **out
)
2507 struct source_reader
*object
;
2511 object
= calloc(1, sizeof(*object
));
2513 return E_OUTOFMEMORY
;
2515 object
->IMFSourceReaderEx_iface
.lpVtbl
= &srcreader_vtbl
;
2516 object
->source_events_callback
.lpVtbl
= &source_events_callback_vtbl
;
2517 object
->stream_events_callback
.lpVtbl
= &stream_events_callback_vtbl
;
2518 object
->async_commands_callback
.lpVtbl
= &async_commands_callback_vtbl
;
2519 object
->public_refcount
= 1;
2520 object
->refcount
= 1;
2521 list_init(&object
->responses
);
2522 if (shutdown_on_release
)
2523 object
->flags
|= SOURCE_READER_SHUTDOWN_ON_RELEASE
;
2524 object
->source
= source
;
2525 IMFMediaSource_AddRef(object
->source
);
2526 InitializeCriticalSection(&object
->cs
);
2527 InitializeConditionVariable(&object
->sample_event
);
2528 InitializeConditionVariable(&object
->state_event
);
2529 InitializeConditionVariable(&object
->stop_event
);
2531 if (FAILED(hr
= IMFMediaSource_CreatePresentationDescriptor(object
->source
, &object
->descriptor
)))
2534 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(object
->descriptor
, &object
->stream_count
)))
2537 if (!(object
->streams
= calloc(object
->stream_count
, sizeof(*object
->streams
))))
2543 /* Set initial current media types. */
2544 for (i
= 0; i
< object
->stream_count
; ++i
)
2546 IMFMediaTypeHandler
*handler
;
2547 IMFStreamDescriptor
*sd
;
2548 IMFMediaType
*src_type
;
2551 list_init(&object
->streams
[i
].transforms
);
2553 if (FAILED(hr
= MFCreateMediaType(&object
->streams
[i
].current
)))
2556 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(object
->descriptor
, i
, &selected
, &sd
)))
2559 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &object
->streams
[i
].id
)))
2560 WARN("Failed to get stream identifier, hr %#lx.\n", hr
);
2562 hr
= IMFStreamDescriptor_GetMediaTypeHandler(sd
, &handler
);
2563 IMFStreamDescriptor_Release(sd
);
2567 hr
= IMFMediaTypeHandler_GetMediaTypeByIndex(handler
, 0, &src_type
);
2568 IMFMediaTypeHandler_Release(handler
);
2572 hr
= IMFMediaType_CopyAllItems(src_type
, (IMFAttributes
*)object
->streams
[i
].current
);
2573 IMFMediaType_Release(src_type
);
2577 object
->streams
[i
].reader
= object
;
2578 object
->streams
[i
].index
= i
;
2584 /* At least one major type has to be set. */
2585 object
->first_audio_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Audio
);
2586 object
->first_video_stream_index
= reader_get_first_stream_index(object
->descriptor
, &MFMediaType_Video
);
2588 if (object
->first_audio_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
&&
2589 object
->first_video_stream_index
== MF_SOURCE_READER_INVALID_STREAM_INDEX
)
2591 hr
= MF_E_ATTRIBUTENOTFOUND
;
2594 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(object
->source
, &object
->source_events_callback
,
2595 (IUnknown
*)object
->source
)))
2602 object
->attributes
= attributes
;
2603 IMFAttributes_AddRef(object
->attributes
);
2605 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_ASYNC_CALLBACK
, &IID_IMFSourceReaderCallback
,
2606 (void **)&object
->async_callback
);
2607 if (object
->async_callback
)
2608 TRACE("Using async callback %p.\n", object
->async_callback
);
2610 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_D3D_MANAGER
, &IID_IUnknown
, (void **)&object
->device_manager
);
2611 if (object
->device_manager
)
2613 IUnknown
*unk
= NULL
;
2615 if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IMFDXGIDeviceManager
, (void **)&unk
)))
2616 object
->flags
|= SOURCE_READER_DXGI_DEVICE_MANAGER
;
2617 else if (SUCCEEDED(IUnknown_QueryInterface(object
->device_manager
, &IID_IDirect3DDeviceManager9
, (void **)&unk
)))
2618 object
->flags
|= SOURCE_READER_D3D9_DEVICE_MANAGER
;
2620 if (!(object
->flags
& (SOURCE_READER_HAS_DEVICE_MANAGER
)))
2622 WARN("Unknown device manager.\n");
2623 IUnknown_Release(object
->device_manager
);
2624 object
->device_manager
= NULL
;
2628 IUnknown_Release(unk
);
2632 if (FAILED(hr
= MFLockSharedWorkQueue(L
"", 0, NULL
, &object
->queue
)))
2633 WARN("Failed to acquired shared queue, hr %#lx.\n", hr
);
2636 hr
= IMFSourceReaderEx_QueryInterface(&object
->IMFSourceReaderEx_iface
, riid
, out
);
2639 IMFSourceReaderEx_Release(&object
->IMFSourceReaderEx_iface
);
2643 static HRESULT
create_source_reader_from_stream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2644 REFIID riid
, void **out
)
2646 IPropertyStore
*props
= NULL
;
2647 IMFSourceResolver
*resolver
;
2648 MF_OBJECT_TYPE obj_type
;
2649 IMFMediaSource
*source
;
2652 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2656 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2659 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, stream
, NULL
, MF_RESOLUTION_MEDIASOURCE
2660 | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE
, props
, &obj_type
, (IUnknown
**)&source
);
2661 IMFSourceResolver_Release(resolver
);
2663 IPropertyStore_Release(props
);
2667 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2668 IMFMediaSource_Release(source
);
2672 static HRESULT
create_source_reader_from_url(const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2674 IPropertyStore
*props
= NULL
;
2675 IMFSourceResolver
*resolver
;
2676 IUnknown
*object
= NULL
;
2677 MF_OBJECT_TYPE obj_type
;
2678 IMFMediaSource
*source
;
2681 if (FAILED(hr
= MFCreateSourceResolver(&resolver
)))
2685 IMFAttributes_GetUnknown(attributes
, &MF_SOURCE_READER_MEDIASOURCE_CONFIG
, &IID_IPropertyStore
,
2688 hr
= IMFSourceResolver_CreateObjectFromURL(resolver
, url
, MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
,
2694 case MF_OBJECT_BYTESTREAM
:
2695 hr
= IMFSourceResolver_CreateObjectFromByteStream(resolver
, (IMFByteStream
*)object
, NULL
,
2696 MF_RESOLUTION_MEDIASOURCE
, props
, &obj_type
, (IUnknown
**)&source
);
2698 case MF_OBJECT_MEDIASOURCE
:
2699 source
= (IMFMediaSource
*)object
;
2700 IMFMediaSource_AddRef(source
);
2703 WARN("Unknown object type %d.\n", obj_type
);
2706 IUnknown_Release(object
);
2709 IMFSourceResolver_Release(resolver
);
2711 IPropertyStore_Release(props
);
2715 hr
= create_source_reader_from_source(source
, attributes
, TRUE
, riid
, out
);
2716 IMFMediaSource_Release(source
);
2720 static HRESULT
create_source_reader_from_object(IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2722 IMFMediaSource
*source
= NULL
;
2723 IMFByteStream
*stream
= NULL
;
2726 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSource
, (void **)&source
);
2728 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2732 UINT32 disconnect
= 0;
2735 IMFAttributes_GetUINT32(attributes
, &MF_SOURCE_READER_DISCONNECT_MEDIASOURCE_ON_SHUTDOWN
, &disconnect
);
2736 hr
= create_source_reader_from_source(source
, attributes
, !disconnect
, riid
, out
);
2739 hr
= create_source_reader_from_stream(stream
, attributes
, riid
, out
);
2742 IMFMediaSource_Release(source
);
2744 IMFByteStream_Release(stream
);
2749 /***********************************************************************
2750 * MFCreateSourceReaderFromByteStream (mfreadwrite.@)
2752 HRESULT WINAPI
MFCreateSourceReaderFromByteStream(IMFByteStream
*stream
, IMFAttributes
*attributes
,
2753 IMFSourceReader
**reader
)
2755 TRACE("%p, %p, %p.\n", stream
, attributes
, reader
);
2757 return create_source_reader_from_object((IUnknown
*)stream
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2760 /***********************************************************************
2761 * MFCreateSourceReaderFromMediaSource (mfreadwrite.@)
2763 HRESULT WINAPI
MFCreateSourceReaderFromMediaSource(IMFMediaSource
*source
, IMFAttributes
*attributes
,
2764 IMFSourceReader
**reader
)
2766 TRACE("%p, %p, %p.\n", source
, attributes
, reader
);
2768 return create_source_reader_from_object((IUnknown
*)source
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2771 /***********************************************************************
2772 * MFCreateSourceReaderFromURL (mfreadwrite.@)
2774 HRESULT WINAPI
MFCreateSourceReaderFromURL(const WCHAR
*url
, IMFAttributes
*attributes
, IMFSourceReader
**reader
)
2776 TRACE("%s, %p, %p.\n", debugstr_w(url
), attributes
, reader
);
2778 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, (void **)reader
);
2781 static HRESULT WINAPI
readwrite_factory_QueryInterface(IMFReadWriteClassFactory
*iface
, REFIID riid
, void **out
)
2783 if (IsEqualIID(riid
, &IID_IMFReadWriteClassFactory
) ||
2784 IsEqualIID(riid
, &IID_IUnknown
))
2787 IMFReadWriteClassFactory_AddRef(iface
);
2791 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
2793 return E_NOINTERFACE
;
2796 static ULONG WINAPI
readwrite_factory_AddRef(IMFReadWriteClassFactory
*iface
)
2801 static ULONG WINAPI
readwrite_factory_Release(IMFReadWriteClassFactory
*iface
)
2806 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2807 const WCHAR
*url
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2809 TRACE("%s, %s, %p, %s, %p.\n", debugstr_guid(clsid
), debugstr_w(url
), attributes
, debugstr_guid(riid
), out
);
2811 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2813 return create_source_reader_from_url(url
, attributes
, &IID_IMFSourceReader
, out
);
2815 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2817 return create_sink_writer_from_url(url
, NULL
, attributes
, riid
, out
);
2820 FIXME("Unsupported %s.\n", debugstr_guid(clsid
));
2825 static HRESULT WINAPI
readwrite_factory_CreateInstanceFromObject(IMFReadWriteClassFactory
*iface
, REFCLSID clsid
,
2826 IUnknown
*unk
, IMFAttributes
*attributes
, REFIID riid
, void **out
)
2830 TRACE("%s, %p, %p, %s, %p.\n", debugstr_guid(clsid
), unk
, attributes
, debugstr_guid(riid
), out
);
2832 if (IsEqualGUID(clsid
, &CLSID_MFSourceReader
))
2834 return create_source_reader_from_object(unk
, attributes
, riid
, out
);
2836 else if (IsEqualGUID(clsid
, &CLSID_MFSinkWriter
))
2838 IMFByteStream
*stream
= NULL
;
2839 IMFMediaSink
*sink
= NULL
;
2841 hr
= IUnknown_QueryInterface(unk
, &IID_IMFByteStream
, (void **)&stream
);
2843 hr
= IUnknown_QueryInterface(unk
, &IID_IMFMediaSink
, (void **)&sink
);
2846 hr
= create_sink_writer_from_url(NULL
, stream
, attributes
, riid
, out
);
2848 hr
= create_sink_writer_from_sink(sink
, attributes
, riid
, out
);
2851 IMFMediaSink_Release(sink
);
2853 IMFByteStream_Release(stream
);
2859 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2865 static const IMFReadWriteClassFactoryVtbl readwrite_factory_vtbl
=
2867 readwrite_factory_QueryInterface
,
2868 readwrite_factory_AddRef
,
2869 readwrite_factory_Release
,
2870 readwrite_factory_CreateInstanceFromURL
,
2871 readwrite_factory_CreateInstanceFromObject
,
2874 static IMFReadWriteClassFactory readwrite_factory
= { &readwrite_factory_vtbl
};
2876 static HRESULT WINAPI
classfactory_QueryInterface(IClassFactory
*iface
, REFIID riid
, void **out
)
2878 TRACE("%s, %p.\n", debugstr_guid(riid
), out
);
2880 if (IsEqualGUID(riid
, &IID_IClassFactory
) ||
2881 IsEqualGUID(riid
, &IID_IUnknown
))
2883 IClassFactory_AddRef(iface
);
2888 WARN("interface %s not implemented\n", debugstr_guid(riid
));
2890 return E_NOINTERFACE
;
2893 static ULONG WINAPI
classfactory_AddRef(IClassFactory
*iface
)
2898 static ULONG WINAPI
classfactory_Release(IClassFactory
*iface
)
2903 static HRESULT WINAPI
classfactory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **out
)
2905 TRACE("%p, %s, %p.\n", outer
, debugstr_guid(riid
), out
);
2910 return CLASS_E_NOAGGREGATION
;
2912 return IMFReadWriteClassFactory_QueryInterface(&readwrite_factory
, riid
, out
);
2915 static HRESULT WINAPI
classfactory_LockServer(IClassFactory
*iface
, BOOL dolock
)
2917 FIXME("%d.\n", dolock
);
2921 static const IClassFactoryVtbl classfactoryvtbl
=
2923 classfactory_QueryInterface
,
2924 classfactory_AddRef
,
2925 classfactory_Release
,
2926 classfactory_CreateInstance
,
2927 classfactory_LockServer
,
2930 static IClassFactory classfactory
= { &classfactoryvtbl
};
2932 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
2934 TRACE("%s, %s, %p.\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
2936 if (IsEqualGUID(clsid
, &CLSID_MFReadWriteClassFactory
))
2937 return IClassFactory_QueryInterface(&classfactory
, riid
, out
);
2939 WARN("Unsupported class %s.\n", debugstr_guid(clsid
));
2941 return CLASS_E_CLASSNOTAVAILABLE
;