Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/mfreadwrite/main.c | 192 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 4 deletions(-)
diff --git a/dlls/mfreadwrite/main.c b/dlls/mfreadwrite/main.c index 56ec036089..bc5bf0fde9 100644 --- a/dlls/mfreadwrite/main.c +++ b/dlls/mfreadwrite/main.c @@ -94,6 +94,7 @@ struct media_stream { IMFMediaStream *stream; IMFMediaType *current; + IMFTransform *decoder; DWORD id; CRITICAL_SECTION cs; CONDITION_VARIABLE sample_event; @@ -576,6 +577,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 +758,15 @@ 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 *in_stream_type = NULL, *potential_out_stream_type = NULL; + CLSID decoder_id; + BOOL decoder_found = FALSE; + IMFTransform *decoder = NULL; HRESULT hr;
TRACE("%p, %#x, %p, %p.\n", iface, index, reserved, type); @@ -774,14 +786,186 @@ 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. */ - 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)) + { + /* Not gonna happen */ + hr = MF_E_INVALIDMEDIATYPE; + goto done; + } + + if (equal_flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES) + { + /* Similar enough not to need to refind a decoder */ + hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)reader->streams[index].current); + 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; + + 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 */ + for (unsigned int i = 0; hr != MF_E_NO_MORE_TYPES; i++) + { + if (FAILED(hr = IMFSourceReader_GetNativeMediaType(iface, index, i, &in_stream_type))) + continue; + + if (FAILED(hr = IMFMediaType_IsEqual(type, in_stream_type, &equal_flags))) + goto done; + + if (equal_flags & MF_MEDIATYPE_EQUAL_FORMAT_TYPES) + { + if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(stream_type_handler, in_stream_type))) + goto done; + hr = IMFMediaType_CopyAllItems(in_stream_type, (IMFAttributes *)reader->streams[index].current); + goto done; + } + + IMFMediaType_Release(in_stream_type); + in_stream_type = NULL; + } + + /* 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; + } + + hr = S_OK; + 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, &in_stream_type))) + continue; + + if (FAILED(hr = IMFMediaType_GetGUID(in_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) + { + if (!(decoder_found)) + { + /* see if there are other decoders for this stream */ + if (SUCCEEDED(MFTEnum(decoder_category, 0, &in_type, NULL, NULL, &decoder_ids, &decoder_count)) && decoder_count > 0) + { + decoder_found = TRUE; + CoTaskMemFree(decoder_ids); + } + } + + IMFMediaType_Release(in_stream_type); + in_stream_type = NULL; + continue; + } + + if (decoder_count > 1) + FIXME("Just using the first decoder.\n"); + decoder_id = decoder_ids[0]; + CoTaskMemFree(decoder_ids); + + if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(stream_type_handler, in_stream_type))) + goto done; + + break; + } + + if (!in_stream_type) + { + ERR("Failed to find decoder matching request, source has decoder: %u.\n", decoder_found); + hr = decoder_found ? MF_E_INVALIDREQUEST : MF_E_TOPO_CODEC_NOT_FOUND; + goto done; + } + + /* we have the decoder id at this point */ + if (FAILED(hr = CoCreateInstance(&decoder_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void**)&decoder))) + goto done; + + { + DWORD in_min, in_max, out_min, out_max; + + if (FAILED(hr = IMFTransform_GetStreamLimits(decoder, &in_min, &in_max, &out_min, &out_max))) + goto done; + if (in_min != 1 || in_max != 1 || out_min != 1 || out_max != 1) + { + hr = ERROR_INTERNAL_ERROR; + goto done; + } + } + + if (FAILED(hr = IMFTransform_SetInputType(decoder, 0, in_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; + } + + 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 (in_stream_type) + IMFMediaType_Release(in_stream_type); + if (decoder) + IMFTransform_Release(decoder); + if (potential_out_stream_type) + IMFMediaType_Release(potential_out_stream_type); return hr; }