[PATCH v2 1/2] mfreadwrite: Find a decoder in IMFSourceReader::SetCurrentMediaType.
Derek Lesho
dlesho at codeweavers.com
Wed Mar 18 12:50:11 CDT 2020
Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
---
dlls/mfreadwrite/main.c | 167 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 163 insertions(+), 4 deletions(-)
diff --git a/dlls/mfreadwrite/main.c b/dlls/mfreadwrite/main.c
index 56ec036089..34b394f77d 100644
--- a/dlls/mfreadwrite/main.c
+++ b/dlls/mfreadwrite/main.c
@@ -81,6 +81,7 @@ struct sample
enum media_stream_state
{
STREAM_STATE_READY = 0,
+ STREAM_STATE_PLAYING,
STREAM_STATE_EOS,
};
@@ -94,6 +95,7 @@ struct media_stream
{
IMFMediaStream *stream;
IMFMediaType *current;
+ IMFTransform *decoder;
DWORD id;
CRITICAL_SECTION cs;
CONDITION_VARIABLE sample_event;
@@ -404,6 +406,7 @@ static HRESULT source_reader_media_sample_handler(struct source_reader *reader,
IMFSample_AddRef(pending_sample->sample);
EnterCriticalSection(&reader->streams[i].cs);
+ reader->streams[i].state = STREAM_STATE_PLAYING;
list_add_tail(&reader->streams[i].samples, &pending_sample->entry);
LeaveCriticalSection(&reader->streams[i].cs);
@@ -576,6 +579,8 @@ static ULONG WINAPI src_reader_Release(IMFSourceReader *iface)
IMFMediaStream_Release(stream->stream);
if (stream->current)
IMFMediaType_Release(stream->current);
+ if (stream->decoder)
+ IMFTransform_Release(stream->decoder);
DeleteCriticalSection(&stream->cs);
LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &stream->samples, struct sample, entry)
@@ -755,6 +760,14 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWO
IMFMediaType *type)
{
struct source_reader *reader = impl_from_IMFSourceReader(iface);
+ DWORD equal_flags;
+ GUID major_type, target_subtype, decoder_category;
+ IMFStreamDescriptor *stream_descriptor = NULL;
+ BOOL selected;
+ IMFMediaTypeHandler *stream_type_handler = NULL;
+ IMFMediaType *native_stream_type = NULL, *potential_out_stream_type = NULL;
+ CLSID decoder_id;
+ IMFTransform *decoder = NULL;
HRESULT hr;
TRACE("%p, %#x, %p, %p.\n", iface, index, reserved, type);
@@ -773,15 +786,161 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWO
if (index >= reader->stream_count)
return MF_E_INVALIDSTREAMNUMBER;
-
- /* FIXME: validate passed type and current presentation state. */
+ /* FIXME: validate current presentation state. */
EnterCriticalSection(&reader->cs);
- hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)reader->streams[index].current);
+ if (FAILED(hr = IMFMediaType_IsEqual(type, reader->streams[index].current, &equal_flags)))
+ goto done;
- LeaveCriticalSection(&reader->cs);
+ if (!(equal_flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES))
+ {
+ hr = MF_E_INVALIDMEDIATYPE;
+ goto done;
+ }
+
+ /* Testing reveals that setting the output type while streaming triggers a flush */
+ if (reader->streams[index].state != STREAM_STATE_READY)
+ {
+ if (FAILED(hr = IMFSourceReader_Flush(iface, index)))
+ goto done;
+ }
+
+ if (equal_flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
+ {
+ /* Similar enough not to need to refind a decoder */
+ goto done;
+ }
+
+ if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &stream_descriptor)))
+ goto done;
+
+ if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream_descriptor, &stream_type_handler)))
+ goto done;
+
+ /* first, check if it's a native type */
+ if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(stream_type_handler, type, &native_stream_type)))
+ {
+ if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(stream_type_handler, native_stream_type)))
+ goto done;
+ hr = IMFMediaType_CopyAllItems(native_stream_type, (IMFAttributes *)reader->streams[index].current);
+ goto done;
+
+ IMFMediaType_Release(native_stream_type);
+ }
+
+ /* TODO: should we check if the source type is compressed? */
+
+ if (IsEqualGUID(&major_type, &MFMediaType_Video))
+ {
+ decoder_category = MFT_CATEGORY_VIDEO_DECODER;
+ }
+ else if (IsEqualGUID(&major_type, &MFMediaType_Audio))
+ {
+ decoder_category = MFT_CATEGORY_AUDIO_DECODER;
+ }
+ else
+ {
+ hr = MF_E_TOPO_CODEC_NOT_FOUND;
+ goto done;
+ }
+
+ if (FAILED(hr = IMFMediaType_GetMajorType(type, &major_type)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &target_subtype)))
+ goto done;
+
+ for (unsigned int i = 0; hr != MF_E_NO_MORE_TYPES; i++)
+ {
+ GUID source_subtype;
+ MFT_REGISTER_TYPE_INFO in_type, out_type;
+ CLSID *decoder_ids;
+ ULONG decoder_count;
+
+ if (FAILED(hr = IMFSourceReader_GetNativeMediaType(iface, index, i, &native_stream_type)))
+ continue;
+ if (FAILED(hr = IMFMediaType_GetGUID(native_stream_type, &MF_MT_SUBTYPE, &source_subtype)))
+ goto done;
+
+ in_type.guidMajorType = major_type;
+ in_type.guidSubtype = source_subtype;
+
+ out_type.guidMajorType = major_type;
+ out_type.guidSubtype = target_subtype;
+
+ if (FAILED(hr = MFTEnum(decoder_category, 0, &in_type, &out_type, NULL, &decoder_ids, &decoder_count)) || decoder_count == 0)
+ {
+ IMFMediaType_Release(native_stream_type);
+ native_stream_type = NULL;
+ continue;
+ }
+
+ decoder_id = decoder_ids[0];
+ CoTaskMemFree(decoder_ids);
+
+ if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(stream_type_handler, native_stream_type)))
+ goto done;
+
+ break;
+ }
+
+ if (!native_stream_type)
+ {
+ ERR("Failed to find decoder matching request\n");
+ hr = MF_E_INVALIDREQUEST;
+ goto done;
+ }
+
+ if (FAILED(hr = CoCreateInstance(&decoder_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void**)&decoder)))
+ goto done;
+
+ if (FAILED(hr = IMFTransform_SetInputType(decoder, 0, native_stream_type, 0)))
+ goto done;
+
+ /* find the relevant output type */
+ for (unsigned int i = 0;;i++)
+ {
+ if (FAILED(hr = IMFTransform_GetOutputAvailableType(decoder, 0, i, &potential_out_stream_type)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaType_IsEqual(type, potential_out_stream_type, &equal_flags)))
+ goto done;
+
+ if (equal_flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
+ {
+ if (FAILED(hr = IMFTransform_SetOutputType(decoder, 0, potential_out_stream_type, 0)))
+ goto done;
+
+ if (FAILED(hr = IMFMediaType_CopyAllItems(potential_out_stream_type, (IMFAttributes *)reader->streams[index].current)))
+ goto done;
+
+ break;
+ }
+ IMFMediaType_Release(potential_out_stream_type);
+ potential_out_stream_type = NULL;
+ }
+
+ if (reader->streams[index].decoder)
+ {
+ IMFTransform_Release(reader->streams[index].decoder);
+ }
+ reader->streams[index].decoder = decoder;
+ decoder = NULL;
+
+ done:
+ LeaveCriticalSection(&reader->cs);
+ if (stream_descriptor)
+ IMFStreamDescriptor_Release(stream_descriptor);
+ if (stream_type_handler)
+ IMFMediaTypeHandler_Release(stream_type_handler);
+ if (native_stream_type)
+ IMFMediaType_Release(native_stream_type);
+ if (decoder)
+ IMFTransform_Release(decoder);
+ if (potential_out_stream_type)
+ IMFMediaType_Release(potential_out_stream_type);
return hr;
}
--
2.25.1
More information about the wine-devel
mailing list