mfreadwrite: Configure stream decoder on SetCurrentMediaType() if necessary.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Derek Lesho <dlesho@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
1ece841d93
commit
ecf70b83e2
|
@ -94,6 +94,7 @@ struct media_stream
|
||||||
{
|
{
|
||||||
IMFMediaStream *stream;
|
IMFMediaStream *stream;
|
||||||
IMFMediaType *current;
|
IMFMediaType *current;
|
||||||
|
IMFTransform *decoder;
|
||||||
DWORD id;
|
DWORD id;
|
||||||
CRITICAL_SECTION cs;
|
CRITICAL_SECTION cs;
|
||||||
CONDITION_VARIABLE sample_event;
|
CONDITION_VARIABLE sample_event;
|
||||||
|
@ -576,6 +577,8 @@ static ULONG WINAPI src_reader_Release(IMFSourceReader *iface)
|
||||||
IMFMediaStream_Release(stream->stream);
|
IMFMediaStream_Release(stream->stream);
|
||||||
if (stream->current)
|
if (stream->current)
|
||||||
IMFMediaType_Release(stream->current);
|
IMFMediaType_Release(stream->current);
|
||||||
|
if (stream->decoder)
|
||||||
|
IMFTransform_Release(stream->decoder);
|
||||||
DeleteCriticalSection(&stream->cs);
|
DeleteCriticalSection(&stream->cs);
|
||||||
|
|
||||||
LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &stream->samples, struct sample, entry)
|
LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &stream->samples, struct sample, entry)
|
||||||
|
@ -669,18 +672,15 @@ static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReader *iface, DWOR
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReader *iface, DWORD index, DWORD type_index,
|
static HRESULT source_reader_get_native_media_type(struct source_reader *reader, DWORD index, DWORD type_index,
|
||||||
IMFMediaType **type)
|
IMFMediaType **type)
|
||||||
{
|
{
|
||||||
struct source_reader *reader = impl_from_IMFSourceReader(iface);
|
|
||||||
IMFMediaTypeHandler *handler;
|
IMFMediaTypeHandler *handler;
|
||||||
IMFStreamDescriptor *sd;
|
IMFStreamDescriptor *sd;
|
||||||
IMFMediaType *src_type;
|
IMFMediaType *src_type;
|
||||||
BOOL selected;
|
BOOL selected;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("%p, %#x, %#x, %p.\n", iface, index, type_index, type);
|
|
||||||
|
|
||||||
switch (index)
|
switch (index)
|
||||||
{
|
{
|
||||||
case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
|
case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
|
||||||
|
@ -717,6 +717,16 @@ static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReader *iface, DWOR
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI src_reader_GetNativeMediaType(IMFSourceReader *iface, DWORD index, DWORD type_index,
|
||||||
|
IMFMediaType **type)
|
||||||
|
{
|
||||||
|
struct source_reader *reader = impl_from_IMFSourceReader(iface);
|
||||||
|
|
||||||
|
TRACE("%p, %#x, %#x, %p.\n", iface, index, type_index, type);
|
||||||
|
|
||||||
|
return source_reader_get_native_media_type(reader, index, type_index, type);
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReader *iface, DWORD index, IMFMediaType **type)
|
static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReader *iface, DWORD index, IMFMediaType **type)
|
||||||
{
|
{
|
||||||
struct source_reader *reader = impl_from_IMFSourceReader(iface);
|
struct source_reader *reader = impl_from_IMFSourceReader(iface);
|
||||||
|
@ -751,6 +761,184 @@ static HRESULT WINAPI src_reader_GetCurrentMediaType(IMFSourceReader *iface, DWO
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT source_reader_get_source_type_handler(struct source_reader *reader, DWORD index,
|
||||||
|
IMFMediaTypeHandler **handler)
|
||||||
|
{
|
||||||
|
IMFStreamDescriptor *sd;
|
||||||
|
BOOL selected;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(reader->descriptor, index, &selected, &sd)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, handler);
|
||||||
|
IMFStreamDescriptor_Release(sd);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT source_reader_set_compatible_media_type(struct source_reader *reader, DWORD index, IMFMediaType *type)
|
||||||
|
{
|
||||||
|
IMFMediaTypeHandler *type_handler;
|
||||||
|
IMFMediaType *native_type;
|
||||||
|
BOOL type_set = FALSE;
|
||||||
|
unsigned int i = 0;
|
||||||
|
DWORD flags;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (FAILED(hr = IMFMediaType_IsEqual(type, reader->streams[index].current, &flags)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES))
|
||||||
|
return MF_E_INVALIDMEDIATYPE;
|
||||||
|
|
||||||
|
/* No need for a decoder or type change. */
|
||||||
|
if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
if (FAILED(hr = source_reader_get_source_type_handler(reader, index, &type_handler)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
while (!type_set && IMFMediaTypeHandler_GetMediaTypeByIndex(type_handler, i++, &native_type) == S_OK)
|
||||||
|
{
|
||||||
|
static const DWORD compare_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES;
|
||||||
|
|
||||||
|
if (SUCCEEDED(IMFMediaType_IsEqual(native_type, type, &flags)) && (flags & compare_flags) == compare_flags)
|
||||||
|
{
|
||||||
|
if ((type_set = SUCCEEDED(IMFMediaTypeHandler_SetCurrentMediaType(type_handler, native_type))))
|
||||||
|
IMFMediaType_CopyAllItems(native_type, (IMFAttributes *)reader->streams[index].current);
|
||||||
|
}
|
||||||
|
|
||||||
|
IMFMediaType_Release(native_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
IMFMediaTypeHandler_Release(type_handler);
|
||||||
|
|
||||||
|
return type_set ? S_OK : S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWORD index, const CLSID *clsid,
|
||||||
|
IMFMediaType *input_type, IMFMediaType *output_type)
|
||||||
|
{
|
||||||
|
IMFMediaTypeHandler *type_handler;
|
||||||
|
IMFTransform *transform = NULL;
|
||||||
|
IMFMediaType *type = NULL;
|
||||||
|
DWORD flags;
|
||||||
|
HRESULT hr;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform)))
|
||||||
|
{
|
||||||
|
WARN("Failed to create transform object, hr %#x.\n", hr);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)))
|
||||||
|
{
|
||||||
|
WARN("Failed to set decoder input type, hr %#x.\n", hr);
|
||||||
|
IMFTransform_Release(transform);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the relevant output type. */
|
||||||
|
while (IMFTransform_GetOutputAvailableType(transform, 0, i++, &type) == S_OK)
|
||||||
|
{
|
||||||
|
flags = 0;
|
||||||
|
|
||||||
|
if (SUCCEEDED(IMFMediaType_IsEqual(type, output_type, &flags)))
|
||||||
|
{
|
||||||
|
if (flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES)
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(IMFTransform_SetOutputType(transform, 0, type, 0)))
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(source_reader_get_source_type_handler(reader, index, &type_handler)))
|
||||||
|
{
|
||||||
|
IMFMediaTypeHandler_SetCurrentMediaType(type_handler, input_type);
|
||||||
|
IMFMediaTypeHandler_Release(type_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)reader->streams[index].current)))
|
||||||
|
WARN("Failed to copy attributes, hr %#x.\n", hr);
|
||||||
|
IMFMediaType_Release(type);
|
||||||
|
|
||||||
|
if (reader->streams[index].decoder)
|
||||||
|
IMFTransform_Release(reader->streams[index].decoder);
|
||||||
|
|
||||||
|
reader->streams[index].decoder = transform;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMFMediaType_Release(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN("Failed to find suitable decoder output type.\n");
|
||||||
|
|
||||||
|
IMFTransform_Release(transform);
|
||||||
|
|
||||||
|
return MF_E_TOPO_CODEC_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type)
|
||||||
|
{
|
||||||
|
MFT_REGISTER_TYPE_INFO in_type, out_type;
|
||||||
|
CLSID *clsids, mft_clsid, category;
|
||||||
|
unsigned int i = 0, count;
|
||||||
|
IMFMediaType *input_type;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
/* TODO: should we check if the source type is compressed? */
|
||||||
|
|
||||||
|
if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &out_type.guidMajorType)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video))
|
||||||
|
{
|
||||||
|
category = MFT_CATEGORY_VIDEO_DECODER;
|
||||||
|
}
|
||||||
|
else if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio))
|
||||||
|
{
|
||||||
|
category = MFT_CATEGORY_AUDIO_DECODER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WARN("Unhandled major type %s.\n", debugstr_guid(&out_type.guidMajorType));
|
||||||
|
return MF_E_TOPO_CODEC_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &out_type.guidSubtype)))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
in_type.guidMajorType = out_type.guidMajorType;
|
||||||
|
|
||||||
|
while (source_reader_get_native_media_type(reader, index, i++, &input_type) == S_OK)
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &in_type.guidSubtype)))
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
if (SUCCEEDED(hr = MFTEnum(category, 0, &in_type, &out_type, NULL, &clsids, &count)) && count)
|
||||||
|
{
|
||||||
|
mft_clsid = clsids[0];
|
||||||
|
CoTaskMemFree(clsids);
|
||||||
|
|
||||||
|
/* TODO: Should we iterate over all of them? */
|
||||||
|
if (SUCCEEDED(source_reader_configure_decoder(reader, index, &mft_clsid, input_type, output_type)))
|
||||||
|
{
|
||||||
|
IMFMediaType_Release(input_type);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMFMediaType_Release(input_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MF_E_TOPO_CODEC_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWORD index, DWORD *reserved,
|
static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWORD index, DWORD *reserved,
|
||||||
IMFMediaType *type)
|
IMFMediaType *type)
|
||||||
{
|
{
|
||||||
|
@ -774,11 +962,12 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWO
|
||||||
if (index >= reader->stream_count)
|
if (index >= reader->stream_count)
|
||||||
return MF_E_INVALIDSTREAMNUMBER;
|
return MF_E_INVALIDSTREAMNUMBER;
|
||||||
|
|
||||||
/* FIXME: validate passed type and current presentation state. */
|
/* FIXME: setting the output type while streaming should trigger a flush */
|
||||||
|
|
||||||
EnterCriticalSection(&reader->cs);
|
EnterCriticalSection(&reader->cs);
|
||||||
|
|
||||||
hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)reader->streams[index].current);
|
if ((hr = source_reader_set_compatible_media_type(reader, index, type)) == S_FALSE)
|
||||||
|
hr = source_reader_create_decoder_for_stream(reader, index, type);
|
||||||
|
|
||||||
LeaveCriticalSection(&reader->cs);
|
LeaveCriticalSection(&reader->cs);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue