based on !5504
-- v2: winestreamer/video_decoder: Use video_decoder to implement wmv decoder. winegstreamer/video_decoder: Support aggregation. winegstreamer/video_decoder: Add wg_transform_attrs member. winegstreamer/video_decoder: Change decoder attributes. winegstreamer/video_decoder: Set input/output infos in h264_decoder_create. winegstreamer: Implement mf_media_type_to_wg_format_video_wmv. winegstreamer: Introduce new wg_transform_create_quartz helper.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/main.c | 15 +++ dlls/winegstreamer/quartz_parser.c | 5 - dlls/winegstreamer/quartz_transform.c | 13 +-- dlls/winegstreamer/wma_decoder.c | 151 ++++++++++++-------------- dlls/winegstreamer/wmv_decoder.c | 82 ++++++++------ 6 files changed, 140 insertions(+), 128 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 4bdef90e045..92805818ff4 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -83,6 +83,8 @@ void wg_parser_stream_seek(wg_parser_stream_t stream, double rate,
wg_transform_t wg_transform_create(const struct wg_format *input_format, const struct wg_format *output_format, const struct wg_transform_attrs *attrs); +HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_format, const AM_MEDIA_TYPE *output_format, + const struct wg_transform_attrs *attrs, wg_transform_t *transform); void wg_transform_destroy(wg_transform_t transform); bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *format); bool wg_transform_get_status(wg_transform_t transform, bool *accepts_input); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 4d38a2bf66c..0c3768e7538 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -357,6 +357,21 @@ wg_transform_t wg_transform_create(const struct wg_format *input_format, return params.transform; }
+HRESULT wg_transform_create_quartz(const AM_MEDIA_TYPE *input_type, const AM_MEDIA_TYPE *output_type, + const struct wg_transform_attrs *attrs, wg_transform_t *transform) +{ + struct wg_format input_format, output_format; + + TRACE("input_type %p, output_type %p.\n", input_type, output_type); + + amt_to_wg_format(input_type, &input_format); + amt_to_wg_format(output_type, &output_format); + if (!(*transform = wg_transform_create(&input_format, &output_format, attrs))) + return E_FAIL; + + return S_OK; +} + void wg_transform_destroy(wg_transform_t transform) { TRACE("transform %#I64x.\n", transform); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 32eb6e1a4a0..e09cad7ec22 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -873,11 +873,6 @@ static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype)); return false; } - if (mt->cbFormat < sizeof(*audio_format) || !mt->pbFormat) - { - ERR("Unexpected format size %lu.\n", mt->cbFormat); - return false; - }
if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MSAUDIO1)) format->u.audio.version = 1; diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index ad0c3077733..b85b24f4278 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -98,26 +98,19 @@ static HRESULT transform_query_interface(struct strmbase_filter *iface, REFIID i static HRESULT transform_init_stream(struct strmbase_filter *iface) { struct transform *filter = impl_from_strmbase_filter(iface); - struct wg_format input_format, output_format; struct wg_transform_attrs attrs = {0}; HRESULT hr;
if (filter->source.pin.peer) { - if (!amt_to_wg_format(&filter->sink.pin.mt, &input_format)) - return E_FAIL; - - if (!amt_to_wg_format(&filter->source.pin.mt, &output_format)) - return E_FAIL; - if (FAILED(hr = wg_sample_queue_create(&filter->sample_queue))) return hr;
- filter->transform = wg_transform_create(&input_format, &output_format, &attrs); - if (!filter->transform) + if (FAILED(hr = wg_transform_create_quartz(&filter->sink.pin.mt, &filter->source.pin.mt, + &attrs, &filter->transform))) { wg_sample_queue_destroy(filter->sample_queue); - return E_FAIL; + return hr; }
hr = IMemAllocator_Commit(filter->source.pAllocator); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index ee128dd7905..e08aff5923d 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -53,8 +53,8 @@ struct wma_decoder IUnknown *outer; LONG refcount;
- struct wg_format input_format; - struct wg_format output_format; + DMO_MEDIA_TYPE input_type; + DMO_MEDIA_TYPE output_type;
DWORD input_buf_size; DWORD output_buf_size; @@ -73,19 +73,13 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) struct wg_transform_attrs attrs = {0};
if (decoder->wg_transform) + { wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - - if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - if (decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - - if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format, &attrs))) - return E_FAIL; + decoder->wg_transform = 0; + }
- return S_OK; + return wg_transform_create_quartz(&decoder->input_type, &decoder->output_type, + &attrs, &decoder->wg_transform); }
static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) @@ -202,8 +196,8 @@ static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id
TRACE("iface %p, id %lu, info %p.\n", iface, id, info);
- if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN - || decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL) + || IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) { memset(info, 0, sizeof(*info)); return MF_E_TRANSFORM_TYPE_NOT_SET; @@ -223,8 +217,8 @@ static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD i
TRACE("iface %p, id %lu, info %p.\n", iface, id, info);
- if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN - || decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL) + || IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) { memset(info, 0, sizeof(*info)); return MF_E_TRANSFORM_TYPE_NOT_SET; @@ -280,11 +274,12 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR struct wma_decoder *decoder = impl_from_IMFTransform(iface); IMFMediaType *media_type; const GUID *output_type; + WAVEFORMATEX *wfx; HRESULT hr;
TRACE("iface %p, id %lu, index %lu, type %p.\n", iface, id, index, type);
- if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return MF_E_TRANSFORM_TYPE_NOT_SET;
*type = NULL; @@ -316,20 +311,16 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR sample_size))) goto done;
- if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, - decoder->input_format.u.audio.channels))) + wfx = (WAVEFORMATEX *)decoder->input_type.pbFormat; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, wfx->nChannels))) goto done; - - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, - decoder->input_format.u.audio.rate))) + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, wfx->nSamplesPerSec))) goto done;
- block_alignment = sample_size * decoder->input_format.u.audio.channels / 8; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, - block_alignment))) + block_alignment = sample_size * wfx->nChannels / 8; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_alignment))) goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, - decoder->input_format.u.audio.rate * block_alignment))) + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, wfx->nSamplesPerSec * block_alignment))) goto done;
if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) @@ -385,9 +376,13 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK;
- mf_media_type_to_wg_format(type, &decoder->input_format); - decoder->input_buf_size = block_alignment; - decoder->output_format.major_type = WG_MAJOR_TYPE_UNKNOWN; + FreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); + FreeMediaType(&decoder->input_type); + memset(&decoder->input_type, 0, sizeof(decoder->input_type)); + + if (SUCCEEDED(hr = MFInitAMMediaTypeFromMFMediaType(type, GUID_NULL, &decoder->input_type))) + decoder->input_buf_size = block_alignment;
return hr; } @@ -403,7 +398,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF
TRACE("iface %p, id %lu, type %p, flags %#lx.\n", iface, id, type, flags);
- if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return MF_E_TRANSFORM_TYPE_NOT_SET;
if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || @@ -446,10 +441,15 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK;
- decoder->input_format.u.audio.depth = sample_size; + FreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type));
- mf_media_type_to_wg_format(type, &decoder->output_format); - decoder->output_buf_size = 1024 * block_alignment * channel_count; + if (SUCCEEDED(hr = MFInitAMMediaTypeFromMFMediaType(type, GUID_NULL, &decoder->output_type))) + { + WAVEFORMATEX *wfx = (WAVEFORMATEX *)decoder->input_type.pbFormat; + wfx->wBitsPerSample = sample_size; + decoder->output_buf_size = 1024 * block_alignment * channel_count; + }
if (FAILED(hr = try_create_wg_transform(decoder))) goto failed; @@ -457,7 +457,8 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF return S_OK;
failed: - decoder->output_format.major_type = WG_MAJOR_TYPE_UNKNOWN; + FreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); return hr; }
@@ -656,7 +657,9 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde DMO_MEDIA_TYPE *type) { struct wma_decoder *decoder = impl_from_IMediaObject(iface); - WAVEFORMATEX *wfx; + IMFMediaType *media_type; + UINT32 depth; + HRESULT hr;
TRACE("iface %p, index %lu, type_index %lu, type %p\n", iface, index, type_index, type);
@@ -664,42 +667,34 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde return DMO_E_INVALIDSTREAMINDEX; if (type_index >= 1) return DMO_E_NO_MORE_ITEMS; - if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET; if (!type) return S_OK;
- memset(type, 0, sizeof(*type)); - type->majortype = MFMediaType_Audio; - type->subtype = MEDIASUBTYPE_PCM; - type->formattype = FORMAT_WaveFormatEx; - type->bFixedSizeSamples = FALSE; - type->bTemporalCompression = TRUE; - type->lSampleSize = 0; - - type->cbFormat = sizeof(WAVEFORMATEX); - type->pbFormat = CoTaskMemAlloc(type->cbFormat); - memset(type->pbFormat, 0, type->cbFormat); + if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + &decoder->input_type, &media_type))) + return hr;
- wfx = (WAVEFORMATEX *)type->pbFormat; - if (decoder->input_format.u.audio.depth == 32) - wfx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &depth)) + && depth == 32) + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_Float); else - wfx->wFormatTag = WAVE_FORMAT_PCM; - wfx->nChannels = decoder->input_format.u.audio.channels; - wfx->nSamplesPerSec = decoder->input_format.u.audio.rate; - wfx->wBitsPerSample = decoder->input_format.u.audio.depth; - wfx->nAvgBytesPerSec = wfx->nChannels * wfx->nSamplesPerSec * wfx->wBitsPerSample / 8; - wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8; + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
- return S_OK; + if (SUCCEEDED(hr)) + hr = IMFMediaType_DeleteItem(media_type, &MF_MT_USER_DATA); + if (SUCCEEDED(hr)) + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, type); + + IMFMediaType_Release(media_type); + return hr; }
static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) { struct wma_decoder *decoder = impl_from_IMediaObject(iface); - struct wg_format wg_format; unsigned int i;
TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); @@ -711,7 +706,8 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index { if (flags != DMO_SET_TYPEF_CLEAR) return E_INVALIDARG; - memset(&decoder->input_format, 0, sizeof(decoder->input_format)); + FreeMediaType(&decoder->input_type); + memset(&decoder->input_type, 0, sizeof(decoder->input_type)); if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -733,14 +729,13 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (i == ARRAY_SIZE(wma_decoder_input_types)) return DMO_E_TYPE_NOT_ACCEPTED;
- if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) - return DMO_E_TYPE_NOT_ACCEPTED; - assert(wg_format.major_type == WG_MAJOR_TYPE_AUDIO_WMA); - if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK;
- decoder->input_format = wg_format; + FreeMediaType(&decoder->input_type); + memset(&decoder->input_type, 0, sizeof(decoder->input_type)); + CopyMediaType(&decoder->input_type, type); + if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -755,8 +750,8 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde { struct wma_decoder *decoder = impl_from_IMediaObject(iface); struct wg_transform_attrs attrs = {0}; - struct wg_format wg_format; unsigned int i; + HRESULT hr;
TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface, index, type, flags);
@@ -767,7 +762,8 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde { if (flags != DMO_SET_TYPEF_CLEAR) return E_INVALIDARG; - memset(&decoder->output_format, 0, sizeof(decoder->output_format)); + FreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -789,18 +785,14 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde if (i == ARRAY_SIZE(wma_decoder_output_types)) return DMO_E_TYPE_NOT_ACCEPTED;
- - if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) - return DMO_E_TYPE_NOT_ACCEPTED; - assert(wg_format.major_type == WG_MAJOR_TYPE_AUDIO); - - if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET; - if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK;
- decoder->output_format = wg_format; + FreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); + CopyMediaType(&decoder->output_type, type);
/* Set up wg_transform. */ if (decoder->wg_transform) @@ -808,8 +800,9 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde wg_transform_destroy(decoder->wg_transform); decoder->wg_transform = 0; } - if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format, &attrs))) - return E_FAIL; + if (FAILED(hr = wg_transform_create_quartz(&decoder->input_type, &decoder->output_type, + &attrs, &decoder->wg_transform))) + return hr;
return S_OK; } @@ -844,7 +837,7 @@ static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD return E_POINTER; if (index > 0) return DMO_E_INVALIDSTREAMINDEX; - if (decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET;
*size = 8192; diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index ea8b4b19eb6..e63448427b8 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -81,19 +81,13 @@ struct wmv_decoder IUnknown *outer; LONG refcount;
- struct wg_format input_format; - struct wg_format output_format; - GUID output_subtype; + DMO_MEDIA_TYPE input_type; + DMO_MEDIA_TYPE output_type;
wg_transform_t wg_transform; struct wg_sample_queue *wg_sample_queue; };
-static bool wg_format_is_set(struct wg_format *format) -{ - return format->major_type != WG_MAJOR_TYPE_UNKNOWN; -} - static inline struct wmv_decoder *impl_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, struct wmv_decoder, IUnknown_inner); @@ -428,6 +422,8 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde DMO_MEDIA_TYPE *type) { struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + UINT64 frame_size, frame_rate; + IMFMediaType *media_type; VIDEOINFOHEADER *info; const GUID *subtype; LONG width, height; @@ -442,15 +438,25 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde return DMO_E_NO_MORE_ITEMS; if (!type) return S_OK; - if (!wg_format_is_set(&decoder->input_format)) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET;
- width = decoder->input_format.u.video.width; - height = abs(decoder->input_format.u.video.height); + if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + &decoder->input_type, &media_type))) + return hr; + + if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) + frame_size = 0; + if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &frame_rate))) + frame_rate = 0; + + width = frame_size >> 32; + height = (UINT32)frame_size; subtype = wmv_decoder_output_types[type_index].subtype; if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &image_size))) { FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(subtype)); + IMFMediaType_Release(media_type); return hr; }
@@ -470,8 +476,8 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde info->rcSource.bottom = height; info->rcTarget.right = width; info->rcTarget.bottom = height; - info->AvgTimePerFrame = MulDiv(10000000, decoder->input_format.u.video.fps_d, - decoder->input_format.u.video.fps_n); + if (frame_rate) + MFFrameRateToAverageTimePerFrame(frame_rate >> 32, frame_rate, (UINT64 *)&info->AvgTimePerFrame); info->bmiHeader.biSize = sizeof(info->bmiHeader); info->bmiHeader.biWidth = width; info->bmiHeader.biHeight = height; @@ -480,6 +486,7 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde info->bmiHeader.biCompression = wmv_decoder_output_types[type_index].compression; info->bmiHeader.biSizeImage = image_size;
+ IMFMediaType_Release(media_type); return S_OK; }
@@ -487,7 +494,7 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index const DMO_MEDIA_TYPE *type, DWORD flags) { struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - struct wg_format wg_format; + IMFMediaType *media_type; unsigned int i;
TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); @@ -499,7 +506,8 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index { if (flags & DMO_SET_TYPEF_CLEAR) { - memset(&decoder->input_format, 0, sizeof(decoder->input_format)); + FreeMediaType(&decoder->input_type); + memset(&decoder->input_type, 0, sizeof(decoder->input_type)); if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -519,14 +527,16 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (i == ARRAY_SIZE(wmv_decoder_input_types)) return DMO_E_TYPE_NOT_ACCEPTED;
- if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) + if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + (void *)type, &media_type))) return DMO_E_TYPE_NOT_ACCEPTED; - assert(wg_format.major_type == WG_MAJOR_TYPE_VIDEO_WMV); + IMFMediaType_Release(media_type);
if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK;
- decoder->input_format = wg_format; + FreeMediaType(&decoder->input_type); + CopyMediaType(&decoder->input_type, type); if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -541,8 +551,9 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde { struct wmv_decoder *decoder = impl_from_IMediaObject(iface); struct wg_transform_attrs attrs = {0}; - struct wg_format wg_format; + IMFMediaType *media_type; unsigned int i; + HRESULT hr;
TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface, index, type, flags);
@@ -553,7 +564,8 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde { if (flags & DMO_SET_TYPEF_CLEAR) { - memset(&decoder->output_format, 0, sizeof(decoder->output_format)); + FreeMediaType(&decoder->output_type); + memset(&decoder->output_type, 0, sizeof(decoder->output_type)); if (decoder->wg_transform) { wg_transform_destroy(decoder->wg_transform); @@ -564,7 +576,7 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde return E_POINTER; }
- if (!wg_format_is_set(&decoder->input_format)) + if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET;
if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) @@ -576,15 +588,16 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde if (i == ARRAY_SIZE(wmv_decoder_output_types)) return DMO_E_TYPE_NOT_ACCEPTED;
- if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) + if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + (void *)type, &media_type))) return DMO_E_TYPE_NOT_ACCEPTED; - assert(wg_format.major_type == WG_MAJOR_TYPE_VIDEO); + IMFMediaType_Release(media_type);
if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK;
- decoder->output_subtype = type->subtype; - decoder->output_format = wg_format; + FreeMediaType(&decoder->output_type); + CopyMediaType(&decoder->output_type, type);
/* Set up wg_transform. */ if (decoder->wg_transform) @@ -592,8 +605,9 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde wg_transform_destroy(decoder->wg_transform); decoder->wg_transform = 0; } - if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format, &attrs))) - return E_FAIL; + if (FAILED(hr = wg_transform_create_quartz(&decoder->input_type, type, + &attrs, &decoder->wg_transform))) + return hr;
return S_OK; } @@ -621,22 +635,22 @@ static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD i static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) { struct wmv_decoder *decoder = impl_from_IMediaObject(iface); + IMFMediaType *media_type; HRESULT hr;
TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment);
if (index > 0) return DMO_E_INVALIDSTREAMINDEX; - if (!wg_format_is_set(&decoder->output_format)) + if (IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET;
- if (FAILED(hr = MFCalculateImageSize(&decoder->output_subtype, - decoder->output_format.u.video.width, abs(decoder->output_format.u.video.height), (UINT32 *)size))) - { - FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(&decoder->output_subtype)); + if (FAILED(hr = MFCreateMediaType(&media_type))) return hr; - } - *alignment = 1; + if (SUCCEEDED(hr = MFInitMediaTypeFromAMMediaType(media_type, &decoder->output_type)) + && SUCCEEDED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, (UINT32 *)size))) + *alignment = 1; + IMFMediaType_Release(media_type);
return S_OK; }
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/mfplat.c | 65 ++++++++++++++++++++++++++++++++ dlls/winegstreamer/wmv_decoder.c | 3 +- 2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 2344e22b12b..daafa346ab0 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -40,6 +40,7 @@ DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); +DEFINE_GUID(MEDIASUBTYPE_WMV_Unknown, 0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b);
struct class_factory { @@ -863,6 +864,60 @@ static void mf_media_type_to_wg_format_video_indeo(IMFMediaType *type, uint32_t format->u.video.version = version; }
+static void mf_media_type_to_wg_format_video_wmv(IMFMediaType *type, const GUID *subtype, struct wg_format *format) +{ + UINT64 frame_rate, frame_size; + UINT32 codec_data_len; + BYTE *codec_data; + + memset(format, 0, sizeof(*format)); + format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + format->u.video.width = frame_size >> 32; + format->u.video.height = (UINT32)frame_size; + } + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) + { + format->u.video.fps_n = frame_rate >> 32; + format->u.video.fps_d = (UINT32)frame_rate; + } + else + { + format->u.video.fps_n = 1; + format->u.video.fps_d = 1; + } + + if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV1)) + format->u.video.format = WG_VIDEO_FORMAT_WMV1; + else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV2)) + format->u.video.format = WG_VIDEO_FORMAT_WMV2; + else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMV3)) + format->u.video.format = WG_VIDEO_FORMAT_WMV3; + else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WMVA)) + format->u.video.format = WG_VIDEO_FORMAT_WMVA; + else if (IsEqualGUID(subtype, &MEDIASUBTYPE_WVC1)) + format->u.video.format = WG_VIDEO_FORMAT_WVC1; + else + format->u.video.format = WG_VIDEO_FORMAT_UNKNOWN; + + if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(type, &MF_MT_USER_DATA, &codec_data, &codec_data_len))) + { + if (codec_data_len <= sizeof(format->u.video.codec_data)) + { + format->u.video.codec_data_len = codec_data_len; + memcpy(format->u.video.codec_data, codec_data, codec_data_len); + } + else + { + WARN("Codec data buffer too small, codec data size %u.\n", codec_data_len); + } + CoTaskMemFree(codec_data); + } +} + void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) { GUID major_type, subtype; @@ -898,6 +953,16 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) mf_media_type_to_wg_format_video_h264(type, format); else if (IsEqualGUID(&subtype, &MFVideoFormat_IV50)) mf_media_type_to_wg_format_video_indeo(type, 5, format); + else if (IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV1) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV2) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVA) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVP) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WVP2) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV_Unknown) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WVC1) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMV3) + || IsEqualGUID(&subtype, &MFVideoFormat_VC1S)) + mf_media_type_to_wg_format_video_wmv(type, &subtype, format); else mf_media_type_to_wg_format_video(type, &subtype, format); } diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index e63448427b8..ddda8199d99 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -31,8 +31,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag);
extern const GUID MEDIASUBTYPE_VC1S; - -DEFINE_GUID(MEDIASUBTYPE_WMV_Unknown, 0x7ce12ca9,0xbfbf,0x43d9,0x9d,0x00,0x82,0xb8,0xed,0x54,0x31,0x6b); +extern const GUID MEDIASUBTYPE_WMV_Unknown;
struct decoder_type {
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/video_decoder.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 8cdab7cdb8b..c8a045d4ce1 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -821,13 +821,6 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U decoder->output_type_count = output_type_count; decoder->output_types = output_types;
- decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER - | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; - decoder->input_info.cbSize = 0x1000; - decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER - | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; - decoder->output_info.cbSize = 1920 * 1088 * 2; - if (FAILED(hr = MFCreateMediaType(&decoder->stream_type))) goto failed; if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16))) @@ -887,6 +880,7 @@ HRESULT h264_decoder_create(REFIID riid, void **out) }; static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; struct wg_transform_attrs attrs = {0}; + struct video_decoder *decoder; wg_transform_t transform; IMFTransform *iface; HRESULT hr; @@ -903,6 +897,14 @@ HRESULT h264_decoder_create(REFIID riid, void **out) if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) return hr; + decoder = impl_from_IMFTransform(iface); + + decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER + | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; + decoder->input_info.cbSize = 0x1000; + decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER + | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; + decoder->output_info.cbSize = 1920 * 1088 * 2;
hr = IMFTransform_QueryInterface(iface, riid, out); IMFTransform_Release(iface);
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mf/tests/transform.c | 4 ++-- dlls/winegstreamer/video_decoder.c | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 6a4653cccee..ee4ba99cdac 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3932,9 +3932,9 @@ static void test_h264_decoder(void) static const struct attribute_desc expect_transform_attributes[] = { ATTR_UINT32(MF_LOW_LATENCY, 0), - ATTR_UINT32(MF_SA_D3D_AWARE, 1, .todo = TRUE), + ATTR_UINT32(MF_SA_D3D_AWARE, 1), ATTR_UINT32(MF_SA_D3D11_AWARE, 1), - ATTR_UINT32(MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, 0, .todo = TRUE), + ATTR_UINT32(MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, 0), /* more H264 decoder specific attributes from CODECAPI */ ATTR_UINT32(AVDecVideoAcceleration_H264, 1), {0}, diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index c8a045d4ce1..df45d0637d1 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -825,11 +825,11 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U goto failed; if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16))) goto failed; - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0))) - goto failed; - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE))) - goto failed; - if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) + if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, FALSE)) + || FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D_AWARE, TRUE)) + || FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE)) + || FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, + &MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, FALSE))) goto failed;
if (FAILED(hr = MFCreateAttributes(&decoder->output_attributes, 0))) @@ -899,6 +899,12 @@ HRESULT h264_decoder_create(REFIID riid, void **out) return hr; decoder = impl_from_IMFTransform(iface);
+ if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) + { + IMFTransform_Release(iface); + return hr; + } + decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->input_info.cbSize = 0x1000;
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/video_decoder.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index df45d0637d1..baaceafd2da 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -64,6 +64,7 @@ struct video_decoder IMFMediaType *stream_type;
wg_transform_t wg_transform; + struct wg_transform_attrs wg_transform_attrs; struct wg_sample_queue *wg_sample_queue;
IMFVideoSampleAllocatorEx *allocator; @@ -84,12 +85,6 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) * transform to be able to queue its input buffers. We need to use a buffer list * to match its expectations. */ - struct wg_transform_attrs attrs = - { - .output_plane_align = 15, - .input_queue_length = 15, - .allow_size_change = TRUE, - }; struct wg_format input_format; struct wg_format output_format; UINT32 low_latency; @@ -107,9 +102,9 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) return MF_E_INVALIDMEDIATYPE;
if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency))) - attrs.low_latency = !!low_latency; + decoder->wg_transform_attrs.low_latency = !!low_latency;
- if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &decoder->wg_transform_attrs))) { ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); return E_FAIL; @@ -841,6 +836,9 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U if (FAILED(hr = MFCreateSampleCopierMFT(&decoder->copier))) goto failed;
+ decoder->wg_transform_attrs.output_plane_align = 15; + decoder->wg_transform_attrs.input_queue_length = 15; + *ret = &decoder->IMFTransform_iface; TRACE("Created decoder %p\n", *ret); return S_OK; @@ -912,6 +910,8 @@ HRESULT h264_decoder_create(REFIID riid, void **out) | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->output_info.cbSize = 1920 * 1088 * 2;
+ decoder->wg_transform_attrs.allow_size_change = TRUE; + hr = IMFTransform_QueryInterface(iface, riid, out); IMFTransform_Release(iface); return hr;
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/video_decoder.c | 134 ++++++++++++++++++----------- 1 file changed, 83 insertions(+), 51 deletions(-)
diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index baaceafd2da..e3029b06e65 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -45,7 +45,9 @@ static const GUID *const video_decoder_output_types[] =
struct video_decoder { + IUnknown IUnknown_inner; IMFTransform IMFTransform_iface; + IUnknown *outer; LONG refcount;
IMFAttributes *attributes; @@ -73,6 +75,79 @@ struct video_decoder IMFMediaBuffer *temp_buffer; };
+static inline struct video_decoder *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IUnknown_inner); +} + +static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) +{ + struct video_decoder *decoder = impl_from_IUnknown(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown)) + *out = &decoder->IUnknown_inner; + else if (IsEqualGUID(iid, &IID_IMFTransform)) + *out = &decoder->IMFTransform_iface; + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI unknown_AddRef(IUnknown *iface) +{ + struct video_decoder *decoder = impl_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&decoder->refcount); + + TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); + + return refcount; +} + +static ULONG WINAPI unknown_Release(IUnknown *iface) +{ + struct video_decoder *decoder = impl_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&decoder->refcount); + + TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); + + if (!refcount) + { + IMFTransform_Release(decoder->copier); + IMFVideoSampleAllocatorEx_Release(decoder->allocator); + if (decoder->temp_buffer) + IMFMediaBuffer_Release(decoder->temp_buffer); + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + if (decoder->output_attributes) + IMFAttributes_Release(decoder->output_attributes); + if (decoder->attributes) + IMFAttributes_Release(decoder->attributes); + wg_sample_queue_destroy(decoder->wg_sample_queue); + free(decoder); + } + + return refcount; +} + +static const IUnknownVtbl unknown_vtbl = +{ + unknown_QueryInterface, + unknown_AddRef, + unknown_Release, +}; + static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) { return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); @@ -220,62 +295,17 @@ static void uninit_allocator(struct video_decoder *decoder)
static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown) || - IsEqualGUID(iid, &IID_IMFTransform)) - *out = &decoder->IMFTransform_iface; - else - { - *out = NULL; - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; + return IUnknown_QueryInterface(impl_from_IMFTransform(iface)->outer, iid, out); }
static ULONG WINAPI transform_AddRef(IMFTransform *iface) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedIncrement(&decoder->refcount); - - TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); - - return refcount; + return IUnknown_AddRef(impl_from_IMFTransform(iface)->outer); }
static ULONG WINAPI transform_Release(IMFTransform *iface) { - struct video_decoder *decoder = impl_from_IMFTransform(iface); - ULONG refcount = InterlockedDecrement(&decoder->refcount); - - TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); - - if (!refcount) - { - IMFTransform_Release(decoder->copier); - IMFVideoSampleAllocatorEx_Release(decoder->allocator); - if (decoder->temp_buffer) - IMFMediaBuffer_Release(decoder->temp_buffer); - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - if (decoder->output_type) - IMFMediaType_Release(decoder->output_type); - if (decoder->output_attributes) - IMFAttributes_Release(decoder->output_attributes); - if (decoder->attributes) - IMFAttributes_Release(decoder->attributes); - wg_sample_queue_destroy(decoder->wg_sample_queue); - free(decoder); - } - - return refcount; + return IUnknown_Release(impl_from_IMFTransform(iface)->outer); }
static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, @@ -800,7 +830,7 @@ static const IMFTransformVtbl transform_vtbl = };
static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, - const GUID *const *output_types, UINT output_type_count, IMFTransform **ret) + const GUID *const *output_types, UINT output_type_count, IUnknown *outer, IMFTransform **ret) { struct video_decoder *decoder; HRESULT hr; @@ -808,8 +838,10 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY;
+ decoder->IUnknown_inner.lpVtbl = &unknown_vtbl; decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1; + decoder->outer = outer ? outer : &decoder->IUnknown_inner;
decoder->input_type_count = input_type_count; decoder->input_types = input_types; @@ -893,7 +925,7 @@ HRESULT h264_decoder_create(REFIID riid, void **out) wg_transform_destroy(transform);
if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), &iface))) + video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &iface))) return hr; decoder = impl_from_IMFTransform(iface);
@@ -943,5 +975,5 @@ HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) return E_FAIL;
return video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), - iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), out); + iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), NULL, out); }
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mf/tests/transform.c | 94 ++- dlls/winegstreamer/Makefile.in | 3 +- dlls/winegstreamer/video_decoder.c | 735 +++++++++++++++++++++- dlls/winegstreamer/wmv_decoder.c | 942 ----------------------------- 4 files changed, 800 insertions(+), 974 deletions(-) delete mode 100644 dlls/winegstreamer/wmv_decoder.c
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index ee4ba99cdac..fabdbca32a9 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -681,6 +681,7 @@ static void check_mft_set_input_type_required_(int line, IMFTransform *transform hr = IMFMediaType_DeleteItem(media_type, attr->key); ok_(__FILE__, line)(hr == S_OK, "DeleteItem returned %#lx\n", hr); hr = IMFTransform_SetInputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY); + todo_wine_if(attr->todo) ok_(__FILE__, line)(FAILED(hr) == attr->required, "SetInputType returned %#lx.\n", hr); hr = IMFMediaType_SetItem(media_type, attr->key, &attr->value); ok_(__FILE__, line)(hr == S_OK, "SetItem returned %#lx\n", hr); @@ -1285,7 +1286,7 @@ static DWORD check_mf_sample_(const char *file, int line, IMFSample *sample, con timestamp = 0xdeadbeef; hr = IMFSample_GetSampleDuration(sample, ×tamp); ok_(file, line)(hr == S_OK, "GetSampleDuration returned %#lx\n", hr); - todo_wine_if(expect->todo_duration && expect->todo_duration == timestamp) + todo_wine_if(expect->todo_duration) ok_(file, line)(llabs(timestamp - expect->sample_duration) <= 1, "got sample duration %I64d\n", timestamp);
@@ -5597,12 +5598,12 @@ static void test_wmv_decoder(void) static const DWORD actual_width = 96, actual_height = 96; const struct attribute_desc expect_output_attributes[] = { - ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, sizeof(actual_aperture)), - ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, sizeof(actual_aperture)), + ATTR_BLOB(MF_MT_GEOMETRIC_APERTURE, &actual_aperture, sizeof(actual_aperture), .todo = TRUE), + ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, sizeof(actual_aperture), .todo = TRUE), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), - ATTR_UINT32(MF_MT_INTERLACE_MODE, 2), + ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo_value = TRUE), {0}, }; const media_type_desc expect_available_outputs[] = @@ -5714,7 +5715,7 @@ static void test_wmv_decoder(void) { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video, .required = TRUE), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1, .required = TRUE), - ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height, .required = TRUE, .todo = TRUE), {0}, }; const struct attribute_desc output_type_desc[] = @@ -5760,7 +5761,7 @@ static void test_wmv_decoder(void) ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_WMV1), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), - ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE), {0}, }; const struct attribute_desc expect_output_type_desc[] = @@ -5771,7 +5772,20 @@ static void test_wmv_decoder(void) ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width), ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), - ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2), + ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2, .todo = TRUE), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + {0}, + }; + const struct attribute_desc expect_output_type_desc_todo_stride[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), + ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width, .todo_value = TRUE), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2, .todo = TRUE), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), {0}, @@ -5784,7 +5798,7 @@ static void test_wmv_decoder(void) ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4), ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), - ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2), + ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2, .todo = TRUE), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), {0}, @@ -5797,7 +5811,7 @@ static void test_wmv_decoder(void) ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4), ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4), ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), - ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2), + ATTR_UINT32(MF_MT_VIDEO_NOMINAL_RANGE, 2, .todo = TRUE), ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), {0}, @@ -5828,6 +5842,7 @@ static void test_wmv_decoder(void) .cbSize = 0x9000, .cbAlignment = 1, }; + const MFT_INPUT_STREAM_INFO empty_input_info = {0};
const struct attribute_desc output_sample_attributes[] = { @@ -5849,12 +5864,21 @@ static void test_wmv_decoder(void) .attributes = output_sample_attributes, .sample_time = 0, .sample_duration = 333333, .buffer_count = 1, .buffers = &output_buffer_desc_nv12, + .todo_duration = TRUE, + }; + const struct sample_desc output_sample_desc_nv12_todo_time = + { + .attributes = output_sample_attributes, + .sample_time = 0, .sample_duration = 333333, + .buffer_count = 1, .buffers = &output_buffer_desc_nv12, + .todo_time = TRUE, .todo_duration = TRUE, }; const struct sample_desc output_sample_desc_rgb = { .attributes = output_sample_attributes, .sample_time = 0, .sample_duration = 333333, .buffer_count = 1, .buffers = &output_buffer_desc_rgb, + .todo_time = TRUE, .todo_duration = TRUE, };
const struct transform_desc @@ -5883,10 +5907,10 @@ static void test_wmv_decoder(void) { /* WMV1 -> YUV (negative stride) */ .output_type_desc = output_type_desc_negative_stride, - .expect_output_type_desc = expect_output_type_desc, + .expect_output_type_desc = expect_output_type_desc_todo_stride, .expect_input_info = &expect_input_info, .expect_output_info = &expect_output_info, - .output_sample_desc = &output_sample_desc_nv12, + .output_sample_desc = &output_sample_desc_nv12_todo_time, .result_bitmap = L"nv12frame.bmp", .delta = 0, }, @@ -5929,6 +5953,8 @@ static void test_wmv_decoder(void) MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12}; MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_WMV1}; IMFSample *input_sample, *output_sample; + MFT_OUTPUT_STREAM_INFO output_info; + MFT_INPUT_STREAM_INFO input_info; IMFCollection *output_samples; IMFMediaType *media_type; IMFTransform *transform; @@ -5965,13 +5991,27 @@ static void test_wmv_decoder(void)
check_mft_optional_methods(transform, 1); check_mft_get_attributes(transform, expect_attributes, TRUE); + + memset(&input_info, 0xcd, sizeof(input_info)); + hr = IMFTransform_GetInputStreamInfo(transform, 0, &input_info); todo_wine - check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetInputStreamInfo returned %#lx\n", hr); + check_member(input_info, empty_input_info, "%I64d", hnsMaxLatency); + check_member(input_info, empty_input_info, "%#lx", dwFlags); + check_member(input_info, empty_input_info, "%#lx", cbSize); + check_member(input_info, empty_input_info, "%#lx", cbMaxLookahead); + check_member(input_info, empty_input_info, "%#lx", cbAlignment); + + memset(&output_info, 0xcd, sizeof(output_info)); + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); todo_wine - check_mft_get_output_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, &empty_output_info); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputStreamInfo returned %#lx\n", hr); + todo_wine + check_member(output_info, empty_output_info, "%#lx", dwFlags); + check_member(output_info, empty_output_info, "%#lx", cbSize); + check_member(output_info, empty_output_info, "%#lx", cbAlignment);
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type); - todo_wine ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputAvailableType returned %#lx\n", hr);
i = -1; @@ -5985,9 +6025,7 @@ static void test_wmv_decoder(void) ok(!ret, "Release returned %lu\n", ret); winetest_pop_context(); } - todo_wine ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr); - todo_wine ok(i == ARRAY_SIZE(expect_available_inputs), "%lu input media types\n", i);
if (hr == E_NOTIMPL) @@ -6021,10 +6059,28 @@ static void test_wmv_decoder(void)
check_mft_set_output_type_required(transform, transform_tests[j].output_type_desc); check_mft_set_output_type(transform, transform_tests[j].output_type_desc, S_OK); - check_mft_get_output_current_type_(__LINE__, transform, transform_tests[j].expect_output_type_desc, FALSE, FALSE); + check_mft_get_output_current_type_(__LINE__, transform, transform_tests[j].expect_output_type_desc, FALSE, TRUE); + + memset(&input_info, 0xcd, sizeof(input_info)); + hr = IMFTransform_GetInputStreamInfo(transform, 0, &input_info); + ok(hr == S_OK, "GetInputStreamInfo returned %#lx\n", hr); + check_member(input_info, *transform_tests[j].expect_input_info, "%I64d", hnsMaxLatency); + check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", dwFlags); + todo_wine + check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", cbSize); + check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", cbMaxLookahead); + todo_wine + check_member(input_info, *transform_tests[j].expect_input_info, "%#lx", cbAlignment);
- check_mft_get_input_stream_info(transform, S_OK, transform_tests[j].expect_input_info); - check_mft_get_output_stream_info(transform, S_OK, transform_tests[j].expect_output_info); + memset(&output_info, 0xcd, sizeof(output_info)); + hr = IMFTransform_GetOutputStreamInfo(transform, 0, &output_info); + ok(hr == S_OK, "GetOutputStreamInfo returned %#lx\n", hr); + todo_wine + check_member(output_info, *transform_tests[j].expect_output_info, "%#lx", dwFlags); + todo_wine_if(transform_tests[j].expect_output_info == &expect_output_info) + check_member(output_info, *transform_tests[j].expect_output_info, "%#lx", cbSize); + todo_wine + check_member(output_info, *transform_tests[j].expect_output_info, "%#lx", cbAlignment);
load_resource(L"wmvencdata.bin", &wmvenc_data, &wmvenc_data_len);
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 410bbd1dc03..abf3d82d6a8 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -28,5 +28,4 @@ SOURCES = \ wg_transform.c \ winegstreamer_classes.idl \ wm_reader.c \ - wma_decoder.c \ - wmv_decoder.c + wma_decoder.c diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index e3029b06e65..c18055f9b67 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -24,6 +24,8 @@ #include "mferror.h" #include "mfobjects.h" #include "mftransform.h" +#include "mediaerr.h" +#include "wmcodecdsp.h"
#include "wine/debug.h"
@@ -34,6 +36,35 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag);
+struct subtype_info +{ + const GUID *subtype; + WORD bpp; + DWORD compression; +}; + +static const struct subtype_info subtype_info_list[] = +{ + { &MFVideoFormat_NV12, 12, MAKEFOURCC('N', 'V', '1', '2') }, + { &MFVideoFormat_YV12, 12, MAKEFOURCC('Y', 'V', '1', '2') }, + { &MFVideoFormat_IYUV, 12, MAKEFOURCC('I', 'Y', 'U', 'V') }, + { &MFVideoFormat_I420, 12, MAKEFOURCC('I', '4', '2', '0') }, + { &MFVideoFormat_YUY2, 16, MAKEFOURCC('Y', 'U', 'Y', '2') }, + { &MFVideoFormat_UYVY, 16, MAKEFOURCC('U', 'Y', 'V', 'Y') }, + { &MFVideoFormat_YVYU, 16, MAKEFOURCC('Y', 'V', 'Y', 'U') }, + { &MFVideoFormat_NV11, 12, MAKEFOURCC('N', 'V', '1', '1') }, + { &MFVideoFormat_RGB8, 8, BI_RGB }, + { &MFVideoFormat_RGB555, 16, BI_RGB }, + { &MFVideoFormat_RGB565, 16, BI_BITFIELDS }, + { &MFVideoFormat_RGB24, 24, BI_RGB }, + { &MFVideoFormat_RGB32, 32, BI_RGB }, + { &MEDIASUBTYPE_RGB8, 8, BI_RGB }, + { &MEDIASUBTYPE_RGB555, 16, BI_RGB }, + { &MEDIASUBTYPE_RGB565, 16, BI_BITFIELDS }, + { &MEDIASUBTYPE_RGB24, 24, BI_RGB }, + { &MEDIASUBTYPE_RGB32, 32, BI_RGB }, +}; + static const GUID *const video_decoder_output_types[] = { &MFVideoFormat_NV12, @@ -47,6 +78,9 @@ struct video_decoder { IUnknown IUnknown_inner; IMFTransform IMFTransform_iface; + IMediaObject IMediaObject_iface; + IPropertyBag IPropertyBag_iface; + IPropertyStore IPropertyStore_iface; IUnknown *outer; LONG refcount;
@@ -73,6 +107,9 @@ struct video_decoder BOOL allocator_initialized; IMFTransform *copier; IMFMediaBuffer *temp_buffer; + + DMO_MEDIA_TYPE dmo_input_type; + DMO_MEDIA_TYPE dmo_output_type; };
static inline struct video_decoder *impl_from_IUnknown(IUnknown *iface) @@ -90,6 +127,12 @@ static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void * *out = &decoder->IUnknown_inner; else if (IsEqualGUID(iid, &IID_IMFTransform)) *out = &decoder->IMFTransform_iface; + else if (IsEqualGUID(iid, &IID_IMediaObject) && decoder->IMediaObject_iface.lpVtbl) + *out = &decoder->IMediaObject_iface; + else if (IsEqualGUID(iid, &IID_IPropertyBag) && decoder->IPropertyBag_iface.lpVtbl) + *out = &decoder->IPropertyBag_iface; + else if (IsEqualGUID(iid, &IID_IPropertyStore) && decoder->IPropertyStore_iface.lpVtbl) + *out = &decoder->IPropertyStore_iface; else { *out = NULL; @@ -148,6 +191,48 @@ static const IUnknownVtbl unknown_vtbl = unknown_Release, };
+static WORD get_subtype_bpp(const GUID *subtype) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(subtype_info_list); ++i) + { + if (IsEqualGUID(subtype, subtype_info_list[i].subtype)) + return subtype_info_list[i].bpp; + } + + return 0; +} + +static DWORD get_subtype_compression(const GUID *subtype) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(subtype_info_list); ++i) + { + if (IsEqualGUID(subtype, subtype_info_list[i].subtype)) + return subtype_info_list[i].compression; + } + + return 0; +} + +static const GUID *get_dmo_subtype(const GUID *subtype) +{ + if (IsEqualGUID(subtype, &MFVideoFormat_RGB8)) + return &MEDIASUBTYPE_RGB8; + else if (IsEqualGUID(subtype, &MFVideoFormat_RGB555)) + return &MEDIASUBTYPE_RGB555; + else if (IsEqualGUID(subtype, &MFVideoFormat_RGB565)) + return &MEDIASUBTYPE_RGB565; + else if (IsEqualGUID(subtype, &MFVideoFormat_RGB24)) + return &MEDIASUBTYPE_RGB24; + else if (IsEqualGUID(subtype, &MFVideoFormat_RGB32)) + return &MEDIASUBTYPE_RGB32; + else + return subtype; +} + static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) { return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); @@ -224,7 +309,10 @@ static HRESULT create_output_media_type(struct video_decoder *decoder, const GUI goto done;
if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, &value))) + { hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value); + value = abs((INT32)value); + } if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) goto done;
@@ -829,8 +917,547 @@ static const IMFTransformVtbl transform_vtbl = transform_ProcessOutput, };
+static inline struct video_decoder *impl_from_IMediaObject(IMediaObject *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IMediaObject_iface); +} + +static HRESULT WINAPI media_object_QueryInterface(IMediaObject *iface, REFIID iid, void **obj) +{ + return IUnknown_QueryInterface(impl_from_IMediaObject(iface)->outer, iid, obj); +} + +static ULONG WINAPI media_object_AddRef(IMediaObject *iface) +{ + return IUnknown_AddRef(impl_from_IMediaObject(iface)->outer); +} + +static ULONG WINAPI media_object_Release(IMediaObject *iface) +{ + return IUnknown_Release(impl_from_IMediaObject(iface)->outer); +} + +static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) +{ + TRACE("iface %p, input %p, output %p.\n", iface, input, output); + + if (!input || !output) + return E_POINTER; + + *input = *output = 1; + + return S_OK; +} + +static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) +{ + FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) +{ + FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, + DMO_MEDIA_TYPE *type) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (type_index >= decoder->input_type_count) + return DMO_E_NO_MORE_ITEMS; + if (!type) + return S_OK; + + memset(type, 0, sizeof(*type)); + type->majortype = MFMediaType_Video; + type->subtype = *get_dmo_subtype(decoder->input_types[type_index]); + type->bFixedSizeSamples = FALSE; + type->bTemporalCompression = TRUE; + type->lSampleSize = 0; + + return S_OK; +} + +static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, + DMO_MEDIA_TYPE *type) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + UINT64 frame_size, frame_rate; + IMFMediaType *media_type; + VIDEOINFOHEADER *info; + const GUID *subtype; + LONG width, height; + UINT32 image_size; + HRESULT hr; + + TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (type_index >= decoder->output_type_count) + return DMO_E_NO_MORE_ITEMS; + if (!type) + return S_OK; + if (IsEqualGUID(&decoder->dmo_input_type.majortype, &GUID_NULL)) + return DMO_E_TYPE_NOT_SET; + + if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + &decoder->dmo_input_type, &media_type))) + return hr; + + if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) + frame_size = 0; + if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &frame_rate))) + frame_rate = 0; + + width = frame_size >> 32; + height = (UINT32)frame_size; + subtype = get_dmo_subtype(decoder->output_types[type_index]); + if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &image_size))) + { + FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(subtype)); + IMFMediaType_Release(media_type); + return hr; + } + + memset(type, 0, sizeof(*type)); + type->majortype = MFMediaType_Video; + type->subtype = *subtype; + type->bFixedSizeSamples = TRUE; + type->bTemporalCompression = FALSE; + type->lSampleSize = image_size; + type->formattype = FORMAT_VideoInfo; + type->cbFormat = sizeof(VIDEOINFOHEADER); + type->pbFormat = CoTaskMemAlloc(type->cbFormat); + memset(type->pbFormat, 0, type->cbFormat); + + info = (VIDEOINFOHEADER *)type->pbFormat; + info->rcSource.right = width; + info->rcSource.bottom = height; + info->rcTarget.right = width; + info->rcTarget.bottom = height; + if (frame_rate) + MFFrameRateToAverageTimePerFrame(frame_rate >> 32, frame_rate, (UINT64 *)&info->AvgTimePerFrame); + info->bmiHeader.biSize = sizeof(info->bmiHeader); + info->bmiHeader.biWidth = width; + info->bmiHeader.biHeight = height; + info->bmiHeader.biPlanes = 1; + info->bmiHeader.biBitCount = get_subtype_bpp(subtype); + info->bmiHeader.biCompression = get_subtype_compression(subtype); + info->bmiHeader.biSizeImage = image_size; + + IMFMediaType_Release(media_type); + return S_OK; +} + +static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, + const DMO_MEDIA_TYPE *type, DWORD flags) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + IMFMediaType *media_type; + unsigned int i; + + TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + + if (!type) + { + if (flags & DMO_SET_TYPEF_CLEAR) + { + FreeMediaType(&decoder->dmo_input_type); + memset(&decoder->dmo_input_type, 0, sizeof(decoder->dmo_input_type)); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + return S_OK; + } + return DMO_E_TYPE_NOT_ACCEPTED; + } + + if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) + return DMO_E_TYPE_NOT_ACCEPTED; + + for (i = 0; i < decoder->input_type_count; ++i) + if (IsEqualGUID(&type->subtype, get_dmo_subtype(decoder->input_types[i]))) + break; + if (i == decoder->input_type_count) + return DMO_E_TYPE_NOT_ACCEPTED; + + if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + (void *)type, &media_type))) + return DMO_E_TYPE_NOT_ACCEPTED; + IMFMediaType_Release(media_type); + + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + FreeMediaType(&decoder->dmo_input_type); + CopyMediaType(&decoder->dmo_input_type, type); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + + return S_OK; +} + +static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index, + const DMO_MEDIA_TYPE *type, DWORD flags) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + IMFMediaType *media_type; + unsigned int i; + HRESULT hr; + + TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface, index, type, flags); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + + if (!type) + { + if (flags & DMO_SET_TYPEF_CLEAR) + { + FreeMediaType(&decoder->dmo_output_type); + memset(&decoder->dmo_output_type, 0, sizeof(decoder->dmo_output_type)); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + return S_OK; + } + return E_POINTER; + } + + if (IsEqualGUID(&decoder->dmo_input_type.majortype, &GUID_NULL)) + return DMO_E_TYPE_NOT_SET; + + if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) + return DMO_E_TYPE_NOT_ACCEPTED; + + for (i = 0; i < decoder->output_type_count; ++i) + if (IsEqualGUID(&type->subtype, get_dmo_subtype(decoder->output_types[i]))) + break; + if (i == decoder->output_type_count) + return DMO_E_TYPE_NOT_ACCEPTED; + + if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, + (void *)type, &media_type))) + return DMO_E_TYPE_NOT_ACCEPTED; + IMFMediaType_Release(media_type); + + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + FreeMediaType(&decoder->dmo_output_type); + CopyMediaType(&decoder->dmo_output_type, type); + + /* Set up wg_transform. */ + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + if (FAILED(hr = wg_transform_create_quartz(&decoder->dmo_input_type, type, + &decoder->wg_transform_attrs, &decoder->wg_transform))) + return hr; + + return S_OK; +} + +static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) +{ + FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) +{ + FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, + DWORD *lookahead, DWORD *alignment) +{ + FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface, index, size, + lookahead, alignment); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + IMFMediaType *media_type; + HRESULT hr; + + TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (IsEqualGUID(&decoder->dmo_output_type.majortype, &GUID_NULL)) + return DMO_E_TYPE_NOT_SET; + + if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + if (SUCCEEDED(hr = MFInitMediaTypeFromAMMediaType(media_type, &decoder->dmo_output_type)) + && SUCCEEDED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, (UINT32 *)size))) + *alignment = 1; + IMFMediaType_Release(media_type); + + return S_OK; +} + +static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) +{ + FIXME("iface %p, index %lu, latency %p stub!\n", iface, index, latency); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency) +{ + FIXME("iface %p, index %lu, latency %s stub!\n", iface, index, wine_dbgstr_longlong(latency)); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_Flush(IMediaObject *iface) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + HRESULT hr; + + TRACE("iface %p.\n", iface); + + if (FAILED(hr = wg_transform_flush(decoder->wg_transform))) + return hr; + + wg_sample_queue_flush(decoder->wg_sample_queue, TRUE); + + return S_OK; +} + +static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index) +{ + TRACE("iface %p, index %lu.\n", iface, index); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + + return S_OK; +} + +static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_FreeStreamingResources(IMediaObject *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) +{ + TRACE("iface %p, index %lu, flags %p.\n", iface, index, flags); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (!flags) + return E_POINTER; + + *flags = DMO_INPUT_STATUSF_ACCEPT_DATA; + + return S_OK; +} + +static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, + IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s.\n", iface, + index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); + + if (!decoder->wg_transform) + return DMO_E_TYPE_NOT_SET; + + return wg_transform_push_dmo(decoder->wg_transform, buffer, flags, timestamp, timelength, decoder->wg_sample_queue); +} + +static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, + DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) +{ + struct video_decoder *decoder = impl_from_IMediaObject(iface); + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, buffers %p, status %p.\n", iface, flags, count, buffers, status); + + if (!decoder->wg_transform) + return DMO_E_TYPE_NOT_SET; + + if ((hr = wg_transform_read_dmo(decoder->wg_transform, buffers)) == MF_E_TRANSFORM_STREAM_CHANGE) + hr = wg_transform_read_dmo(decoder->wg_transform, buffers); + + if (SUCCEEDED(hr)) + wg_sample_queue_flush(decoder->wg_sample_queue, false); + + return hr; +} + +static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock) +{ + FIXME("iface %p, lock %ld stub!\n", iface, lock); + return E_NOTIMPL; +} + +static const IMediaObjectVtbl media_object_vtbl = +{ + media_object_QueryInterface, + media_object_AddRef, + media_object_Release, + media_object_GetStreamCount, + media_object_GetInputStreamInfo, + media_object_GetOutputStreamInfo, + media_object_GetInputType, + media_object_GetOutputType, + media_object_SetInputType, + media_object_SetOutputType, + media_object_GetInputCurrentType, + media_object_GetOutputCurrentType, + media_object_GetInputSizeInfo, + media_object_GetOutputSizeInfo, + media_object_GetInputMaxLatency, + media_object_SetInputMaxLatency, + media_object_Flush, + media_object_Discontinuity, + media_object_AllocateStreamingResources, + media_object_FreeStreamingResources, + media_object_GetInputStatus, + media_object_ProcessInput, + media_object_ProcessOutput, + media_object_Lock, +}; + +static inline struct video_decoder *impl_from_IPropertyBag(IPropertyBag *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IPropertyBag_iface); +} + +static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out) +{ + return IUnknown_QueryInterface(impl_from_IPropertyBag(iface)->outer, iid, out); +} + +static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface) +{ + return IUnknown_AddRef(impl_from_IPropertyBag(iface)->outer); +} + +static ULONG WINAPI property_bag_Release(IPropertyBag *iface) +{ + return IUnknown_Release(impl_from_IPropertyBag(iface)->outer); +} + +static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value, + IErrorLog *error_log) +{ + FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value) +{ + FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value); + return S_OK; +} + +static const IPropertyBagVtbl property_bag_vtbl = +{ + property_bag_QueryInterface, + property_bag_AddRef, + property_bag_Release, + property_bag_Read, + property_bag_Write, +}; + +static inline struct video_decoder *impl_from_IPropertyStore(IPropertyStore *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IPropertyStore_iface); +} + +static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID iid, void **out) +{ + return IUnknown_QueryInterface(impl_from_IPropertyStore(iface)->outer, iid, out); +} + +static ULONG WINAPI property_store_AddRef(IPropertyStore *iface) +{ + return IUnknown_AddRef(impl_from_IPropertyStore(iface)->outer); +} + +static ULONG WINAPI property_store_Release(IPropertyStore *iface) +{ + return IUnknown_Release(impl_from_IPropertyStore(iface)->outer); +} + +static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count) +{ + FIXME("iface %p, count %p stub!\n", iface, count); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key) +{ + FIXME("iface %p, index %lu, key %p stub!\n", iface, index, key); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value) +{ + FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value) +{ + FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_store_Commit(IPropertyStore *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static const IPropertyStoreVtbl property_store_vtbl = +{ + property_store_QueryInterface, + property_store_AddRef, + property_store_Release, + property_store_GetCount, + property_store_GetAt, + property_store_GetValue, + property_store_SetValue, + property_store_Commit, +}; + static HRESULT video_decoder_create_with_types(const GUID *const *input_types, UINT input_type_count, - const GUID *const *output_types, UINT output_type_count, IUnknown *outer, IMFTransform **ret) + const GUID *const *output_types, UINT output_type_count, IUnknown *outer, struct video_decoder **out) { struct video_decoder *decoder; HRESULT hr; @@ -871,8 +1498,8 @@ static HRESULT video_decoder_create_with_types(const GUID *const *input_types, U decoder->wg_transform_attrs.output_plane_align = 15; decoder->wg_transform_attrs.input_queue_length = 15;
- *ret = &decoder->IMFTransform_iface; - TRACE("Created decoder %p\n", *ret); + *out = decoder; + TRACE("Created decoder %p\n", decoder); return S_OK;
failed: @@ -912,7 +1539,6 @@ HRESULT h264_decoder_create(REFIID riid, void **out) struct wg_transform_attrs attrs = {0}; struct video_decoder *decoder; wg_transform_t transform; - IMFTransform *iface; HRESULT hr;
TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); @@ -925,13 +1551,12 @@ HRESULT h264_decoder_create(REFIID riid, void **out) wg_transform_destroy(transform);
if (FAILED(hr = video_decoder_create_with_types(h264_decoder_input_types, ARRAY_SIZE(h264_decoder_input_types), - video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &iface))) + video_decoder_output_types, ARRAY_SIZE(video_decoder_output_types), NULL, &decoder))) return hr; - decoder = impl_from_IMFTransform(iface);
if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) { - IMFTransform_Release(iface); + IMFTransform_Release(&decoder->IMFTransform_iface); return hr; }
@@ -944,8 +1569,10 @@ HRESULT h264_decoder_create(REFIID riid, void **out)
decoder->wg_transform_attrs.allow_size_change = TRUE;
- hr = IMFTransform_QueryInterface(iface, riid, out); - IMFTransform_Release(iface); + TRACE("Created h264 transform %p.\n", &decoder->IMFTransform_iface); + + hr = IMFTransform_QueryInterface(&decoder->IMFTransform_iface, riid, out); + IMFTransform_Release(&decoder->IMFTransform_iface); return hr; }
@@ -969,11 +1596,97 @@ static const GUID *const iv50_decoder_output_types[] =
HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) { + struct video_decoder *decoder; + HRESULT hr; + TRACE("out %p.\n", out);
if (!init_gstreamer()) return E_FAIL;
- return video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), - iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), NULL, out); + if (FAILED(hr = video_decoder_create_with_types(iv50_decoder_input_types, ARRAY_SIZE(iv50_decoder_input_types), + iv50_decoder_output_types, ARRAY_SIZE(iv50_decoder_output_types), NULL, &decoder))) + return hr; + + TRACE("Created iv50 transform %p.\n", &decoder->IMFTransform_iface); + + *out = &decoder->IMFTransform_iface; + return S_OK; +} + +extern const GUID MEDIASUBTYPE_VC1S; +extern const GUID MEDIASUBTYPE_WMV_Unknown; +static const GUID *const wmv_decoder_input_types[] = +{ + &MEDIASUBTYPE_WMV1, + &MEDIASUBTYPE_WMV2, + &MEDIASUBTYPE_WMVA, + &MEDIASUBTYPE_WMVP, + &MEDIASUBTYPE_WVP2, + &MEDIASUBTYPE_WMV_Unknown, + &MEDIASUBTYPE_WVC1, + &MEDIASUBTYPE_WMV3, + &MEDIASUBTYPE_VC1S, +}; +static const GUID *const wmv_decoder_output_types[] = +{ + &MFVideoFormat_NV12, + &MFVideoFormat_YV12, + &MFVideoFormat_IYUV, + &MFVideoFormat_I420, + &MFVideoFormat_YUY2, + &MFVideoFormat_UYVY, + &MFVideoFormat_YVYU, + &MFVideoFormat_NV11, + &MFVideoFormat_RGB32, + &MFVideoFormat_RGB24, + &MFVideoFormat_RGB565, + &MFVideoFormat_RGB555, + &MFVideoFormat_RGB8, +}; + +HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) +{ + static const struct wg_format input_format = + { + .major_type = WG_MAJOR_TYPE_VIDEO_WMV, + .u.video.format = WG_VIDEO_FORMAT_WMV3, + }; + static const struct wg_format output_format = + { + .major_type = WG_MAJOR_TYPE_VIDEO, + .u.video = + { + .format = WG_VIDEO_FORMAT_NV12, + .width = 1920, + .height = 1080, + }, + }; + struct wg_transform_attrs attrs = {0}; + struct video_decoder *decoder; + wg_transform_t transform; + HRESULT hr; + + TRACE("outer %p, out %p.\n", outer, out); + + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) + { + ERR_(winediag)("GStreamer doesn't support WMV decoding, please install appropriate plugins.\n"); + return E_FAIL; + } + wg_transform_destroy(transform); + + if (FAILED(hr = video_decoder_create_with_types(wmv_decoder_input_types, ARRAY_SIZE(wmv_decoder_input_types), + wmv_decoder_output_types, ARRAY_SIZE(wmv_decoder_output_types), outer, &decoder))) + return hr; + + decoder->IMediaObject_iface.lpVtbl = &media_object_vtbl; + decoder->IPropertyBag_iface.lpVtbl = &property_bag_vtbl; + decoder->IPropertyStore_iface.lpVtbl = &property_store_vtbl; + + TRACE("Created wmv transform %p, media object %p.\n", + &decoder->IMFTransform_iface, &decoder->IMediaObject_iface); + + *out = &decoder->IUnknown_inner; + return S_OK; } diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c deleted file mode 100644 index ddda8199d99..00000000000 --- a/dlls/winegstreamer/wmv_decoder.c +++ /dev/null @@ -1,942 +0,0 @@ -/* Copyright 2022 Rémi Bernon for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "gst_private.h" - -#include "mfapi.h" -#include "mferror.h" -#include "mediaerr.h" -#include "mfobjects.h" -#include "mftransform.h" -#include "wmcodecdsp.h" -#include "initguid.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -WINE_DECLARE_DEBUG_CHANNEL(winediag); - -extern const GUID MEDIASUBTYPE_VC1S; -extern const GUID MEDIASUBTYPE_WMV_Unknown; - -struct decoder_type -{ - const GUID *subtype; - WORD bpp; - DWORD compression; -}; - -static const GUID *const wmv_decoder_input_types[] = -{ - &MEDIASUBTYPE_WMV1, - &MEDIASUBTYPE_WMV2, - &MEDIASUBTYPE_WMVA, - &MEDIASUBTYPE_WMVP, - &MEDIASUBTYPE_WVP2, - &MEDIASUBTYPE_WMV_Unknown, - &MEDIASUBTYPE_WVC1, - &MEDIASUBTYPE_WMV3, - &MEDIASUBTYPE_VC1S, -}; - -static const struct decoder_type wmv_decoder_output_types[] = -{ - { &MEDIASUBTYPE_NV12, 12, MAKEFOURCC('N', 'V', '1', '2') }, - { &MEDIASUBTYPE_YV12, 12, MAKEFOURCC('Y', 'V', '1', '2') }, - { &MEDIASUBTYPE_IYUV, 12, MAKEFOURCC('I', 'Y', 'U', 'V') }, - { &MEDIASUBTYPE_I420, 12, MAKEFOURCC('I', '4', '2', '0') }, - { &MEDIASUBTYPE_YUY2, 16, MAKEFOURCC('Y', 'U', 'Y', '2') }, - { &MEDIASUBTYPE_UYVY, 16, MAKEFOURCC('U', 'Y', 'V', 'Y') }, - { &MEDIASUBTYPE_YVYU, 16, MAKEFOURCC('Y', 'V', 'Y', 'U') }, - { &MEDIASUBTYPE_NV11, 12, MAKEFOURCC('N', 'V', '1', '1') }, - { &MEDIASUBTYPE_RGB32, 32, BI_RGB }, - { &MEDIASUBTYPE_RGB24, 24, BI_RGB }, - { &MEDIASUBTYPE_RGB565, 16, BI_BITFIELDS }, - { &MEDIASUBTYPE_RGB555, 16, BI_RGB }, - { &MEDIASUBTYPE_RGB8, 8, BI_RGB }, -}; - -struct wmv_decoder -{ - IUnknown IUnknown_inner; - IMFTransform IMFTransform_iface; - IMediaObject IMediaObject_iface; - IPropertyBag IPropertyBag_iface; - IPropertyStore IPropertyStore_iface; - IUnknown *outer; - LONG refcount; - - DMO_MEDIA_TYPE input_type; - DMO_MEDIA_TYPE output_type; - - wg_transform_t wg_transform; - struct wg_sample_queue *wg_sample_queue; -}; - -static inline struct wmv_decoder *impl_from_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, struct wmv_decoder, IUnknown_inner); -} - -static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) -{ - struct wmv_decoder *impl = impl_from_IUnknown(iface); - - TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown)) - *out = &impl->IUnknown_inner; - else if (IsEqualGUID(iid, &IID_IMFTransform)) - *out = &impl->IMFTransform_iface; - else if (IsEqualGUID(iid, &IID_IMediaObject)) - *out = &impl->IMediaObject_iface; - else if (IsEqualIID(iid, &IID_IPropertyBag)) - *out = &impl->IPropertyBag_iface; - else if (IsEqualIID(iid, &IID_IPropertyStore)) - *out = &impl->IPropertyStore_iface; - else - { - *out = NULL; - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; -} - -static ULONG WINAPI unknown_AddRef(IUnknown *iface) -{ - struct wmv_decoder *impl = impl_from_IUnknown(iface); - ULONG refcount = InterlockedIncrement(&impl->refcount); - - TRACE("iface %p increasing refcount to %lu.\n", iface, refcount); - - return refcount; -} - -static ULONG WINAPI unknown_Release(IUnknown *iface) -{ - struct wmv_decoder *impl = impl_from_IUnknown(iface); - ULONG refcount = InterlockedDecrement(&impl->refcount); - - TRACE("iface %p decreasing refcount to %lu.\n", iface, refcount); - - if (!refcount) - { - if (impl->wg_transform) - wg_transform_destroy(impl->wg_transform); - wg_sample_queue_destroy(impl->wg_sample_queue); - free(impl); - } - - return refcount; -} - -static const IUnknownVtbl unknown_vtbl = -{ - unknown_QueryInterface, - unknown_AddRef, - unknown_Release, -}; - -static struct wmv_decoder *impl_from_IMFTransform(IMFTransform *iface) -{ - return CONTAINING_RECORD(iface, struct wmv_decoder, IMFTransform_iface); -} - -static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) -{ - return IUnknown_QueryInterface(impl_from_IMFTransform(iface)->outer, iid, out); -} - -static ULONG WINAPI transform_AddRef(IMFTransform *iface) -{ - return IUnknown_AddRef(impl_from_IMFTransform(iface)->outer); -} - -static ULONG WINAPI transform_Release(IMFTransform *iface) -{ - return IUnknown_Release(impl_from_IMFTransform(iface)->outer); -} - -static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, - DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) -{ - TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", - iface, input_minimum, input_maximum, output_minimum, output_maximum); - *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1; - return S_OK; -} - -static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -{ - TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); - *inputs = *outputs = 1; - return S_OK; -} - -static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, - DWORD output_size, DWORD *outputs) -{ - TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface, - input_size, inputs, output_size, outputs); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -{ - FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -{ - FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -{ - FIXME("iface %p, attributes %p stub!\n", iface, attributes); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) -{ - TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) -{ - FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id) -{ - TRACE("iface %p, id %#lx.\n", iface, id); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -{ - TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, index %lu, type %p stub!\n", iface, id, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, index %lu, type %p stub!\n", iface, id, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -{ - FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -{ - FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -{ - FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) -{ - FIXME("iface %p, flags %p stub!\n", iface, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -{ - TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -{ - FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -{ - FIXME("iface %p, message %#x, param %#Ix stub!\n", iface, message, param); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -{ - FIXME("iface %p, id %#lx, sample %p, flags %#lx stub!\n", iface, id, sample, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -{ - FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); - return E_NOTIMPL; -} - -static const IMFTransformVtbl transform_vtbl = -{ - transform_QueryInterface, - transform_AddRef, - transform_Release, - transform_GetStreamLimits, - transform_GetStreamCount, - transform_GetStreamIDs, - transform_GetInputStreamInfo, - transform_GetOutputStreamInfo, - transform_GetAttributes, - transform_GetInputStreamAttributes, - transform_GetOutputStreamAttributes, - transform_DeleteInputStream, - transform_AddInputStreams, - transform_GetInputAvailableType, - transform_GetOutputAvailableType, - transform_SetInputType, - transform_SetOutputType, - transform_GetInputCurrentType, - transform_GetOutputCurrentType, - transform_GetInputStatus, - transform_GetOutputStatus, - transform_SetOutputBounds, - transform_ProcessEvent, - transform_ProcessMessage, - transform_ProcessInput, - transform_ProcessOutput, -}; - -static inline struct wmv_decoder *impl_from_IMediaObject(IMediaObject *iface) -{ - return CONTAINING_RECORD(iface, struct wmv_decoder, IMediaObject_iface); -} - -static HRESULT WINAPI media_object_QueryInterface(IMediaObject *iface, REFIID iid, void **obj) -{ - return IUnknown_QueryInterface(impl_from_IMediaObject(iface)->outer, iid, obj); -} - -static ULONG WINAPI media_object_AddRef(IMediaObject *iface) -{ - return IUnknown_AddRef(impl_from_IMediaObject(iface)->outer); -} - -static ULONG WINAPI media_object_Release(IMediaObject *iface) -{ - return IUnknown_Release(impl_from_IMediaObject(iface)->outer); -} - -static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) -{ - TRACE("iface %p, input %p, output %p.\n", iface, input, output); - - if (!input || !output) - return E_POINTER; - - *input = *output = 1; - - return S_OK; -} - -static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) -{ - FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) -{ - FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, - DMO_MEDIA_TYPE *type) -{ - TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (type_index >= ARRAY_SIZE(wmv_decoder_input_types)) - return DMO_E_NO_MORE_ITEMS; - if (!type) - return S_OK; - - memset(type, 0, sizeof(*type)); - type->majortype = MFMediaType_Video; - type->subtype = *wmv_decoder_input_types[type_index]; - type->bFixedSizeSamples = FALSE; - type->bTemporalCompression = TRUE; - type->lSampleSize = 0; - - return S_OK; -} - -static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, - DMO_MEDIA_TYPE *type) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - UINT64 frame_size, frame_rate; - IMFMediaType *media_type; - VIDEOINFOHEADER *info; - const GUID *subtype; - LONG width, height; - UINT32 image_size; - HRESULT hr; - - TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (type_index >= ARRAY_SIZE(wmv_decoder_output_types)) - return DMO_E_NO_MORE_ITEMS; - if (!type) - return S_OK; - if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) - return DMO_E_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, - &decoder->input_type, &media_type))) - return hr; - - if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) - frame_size = 0; - if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_RATE, &frame_rate))) - frame_rate = 0; - - width = frame_size >> 32; - height = (UINT32)frame_size; - subtype = wmv_decoder_output_types[type_index].subtype; - if (FAILED(hr = MFCalculateImageSize(subtype, width, height, &image_size))) - { - FIXME("Failed to get image size of subtype %s.\n", debugstr_guid(subtype)); - IMFMediaType_Release(media_type); - return hr; - } - - memset(type, 0, sizeof(*type)); - type->majortype = MFMediaType_Video; - type->subtype = *subtype; - type->bFixedSizeSamples = TRUE; - type->bTemporalCompression = FALSE; - type->lSampleSize = image_size; - type->formattype = FORMAT_VideoInfo; - type->cbFormat = sizeof(VIDEOINFOHEADER); - type->pbFormat = CoTaskMemAlloc(type->cbFormat); - memset(type->pbFormat, 0, type->cbFormat); - - info = (VIDEOINFOHEADER *)type->pbFormat; - info->rcSource.right = width; - info->rcSource.bottom = height; - info->rcTarget.right = width; - info->rcTarget.bottom = height; - if (frame_rate) - MFFrameRateToAverageTimePerFrame(frame_rate >> 32, frame_rate, (UINT64 *)&info->AvgTimePerFrame); - info->bmiHeader.biSize = sizeof(info->bmiHeader); - info->bmiHeader.biWidth = width; - info->bmiHeader.biHeight = height; - info->bmiHeader.biPlanes = 1; - info->bmiHeader.biBitCount = wmv_decoder_output_types[type_index].bpp; - info->bmiHeader.biCompression = wmv_decoder_output_types[type_index].compression; - info->bmiHeader.biSizeImage = image_size; - - IMFMediaType_Release(media_type); - return S_OK; -} - -static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, - const DMO_MEDIA_TYPE *type, DWORD flags) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - IMFMediaType *media_type; - unsigned int i; - - TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - - if (!type) - { - if (flags & DMO_SET_TYPEF_CLEAR) - { - FreeMediaType(&decoder->input_type); - memset(&decoder->input_type, 0, sizeof(decoder->input_type)); - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - return S_OK; - } - return DMO_E_TYPE_NOT_ACCEPTED; - } - - if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) - return DMO_E_TYPE_NOT_ACCEPTED; - - for (i = 0; i < ARRAY_SIZE(wmv_decoder_input_types); ++i) - if (IsEqualGUID(&type->subtype, wmv_decoder_input_types[i])) - break; - if (i == ARRAY_SIZE(wmv_decoder_input_types)) - return DMO_E_TYPE_NOT_ACCEPTED; - - if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, - (void *)type, &media_type))) - return DMO_E_TYPE_NOT_ACCEPTED; - IMFMediaType_Release(media_type); - - if (flags & DMO_SET_TYPEF_TEST_ONLY) - return S_OK; - - FreeMediaType(&decoder->input_type); - CopyMediaType(&decoder->input_type, type); - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - - return S_OK; -} - -static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index, - const DMO_MEDIA_TYPE *type, DWORD flags) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - struct wg_transform_attrs attrs = {0}; - IMFMediaType *media_type; - unsigned int i; - HRESULT hr; - - TRACE("iface %p, index %lu, type %p, flags %#lx,\n", iface, index, type, flags); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - - if (!type) - { - if (flags & DMO_SET_TYPEF_CLEAR) - { - FreeMediaType(&decoder->output_type); - memset(&decoder->output_type, 0, sizeof(decoder->output_type)); - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - return S_OK; - } - return E_POINTER; - } - - if (IsEqualGUID(&decoder->input_type.majortype, &GUID_NULL)) - return DMO_E_TYPE_NOT_SET; - - if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) - return DMO_E_TYPE_NOT_ACCEPTED; - - for (i = 0; i < ARRAY_SIZE(wmv_decoder_output_types); ++i) - if (IsEqualGUID(&type->subtype, wmv_decoder_output_types[i].subtype)) - break; - if (i == ARRAY_SIZE(wmv_decoder_output_types)) - return DMO_E_TYPE_NOT_ACCEPTED; - - if (FAILED(MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, - (void *)type, &media_type))) - return DMO_E_TYPE_NOT_ACCEPTED; - IMFMediaType_Release(media_type); - - if (flags & DMO_SET_TYPEF_TEST_ONLY) - return S_OK; - - FreeMediaType(&decoder->output_type); - CopyMediaType(&decoder->output_type, type); - - /* Set up wg_transform. */ - if (decoder->wg_transform) - { - wg_transform_destroy(decoder->wg_transform); - decoder->wg_transform = 0; - } - if (FAILED(hr = wg_transform_create_quartz(&decoder->input_type, type, - &attrs, &decoder->wg_transform))) - return hr; - - return S_OK; -} - -static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) -{ - FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) -{ - FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, - DWORD *lookahead, DWORD *alignment) -{ - FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface, index, size, - lookahead, alignment); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - IMFMediaType *media_type; - HRESULT hr; - - TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (IsEqualGUID(&decoder->output_type.majortype, &GUID_NULL)) - return DMO_E_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaType(&media_type))) - return hr; - if (SUCCEEDED(hr = MFInitMediaTypeFromAMMediaType(media_type, &decoder->output_type)) - && SUCCEEDED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, (UINT32 *)size))) - *alignment = 1; - IMFMediaType_Release(media_type); - - return S_OK; -} - -static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) -{ - FIXME("iface %p, index %lu, latency %p stub!\n", iface, index, latency); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency) -{ - FIXME("iface %p, index %lu, latency %s stub!\n", iface, index, wine_dbgstr_longlong(latency)); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_Flush(IMediaObject *iface) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - HRESULT hr; - - TRACE("iface %p.\n", iface); - - if (FAILED(hr = wg_transform_flush(decoder->wg_transform))) - return hr; - - wg_sample_queue_flush(decoder->wg_sample_queue, TRUE); - - return S_OK; -} - -static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index) -{ - TRACE("iface %p, index %lu.\n", iface, index); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - - return S_OK; -} - -static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface) -{ - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_FreeStreamingResources(IMediaObject *iface) -{ - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; -} - -static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) -{ - TRACE("iface %p, index %lu, flags %p.\n", iface, index, flags); - - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (!flags) - return E_POINTER; - - *flags = DMO_INPUT_STATUSF_ACCEPT_DATA; - - return S_OK; -} - -static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, - IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - - TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s.\n", iface, - index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); - - if (!decoder->wg_transform) - return DMO_E_TYPE_NOT_SET; - - return wg_transform_push_dmo(decoder->wg_transform, buffer, flags, timestamp, timelength, decoder->wg_sample_queue); -} - -static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, - DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) -{ - struct wmv_decoder *decoder = impl_from_IMediaObject(iface); - HRESULT hr; - - TRACE("iface %p, flags %#lx, count %lu, buffers %p, status %p.\n", iface, flags, count, buffers, status); - - if (!decoder->wg_transform) - return DMO_E_TYPE_NOT_SET; - - if ((hr = wg_transform_read_dmo(decoder->wg_transform, buffers)) == MF_E_TRANSFORM_STREAM_CHANGE) - hr = wg_transform_read_dmo(decoder->wg_transform, buffers); - - if (SUCCEEDED(hr)) - wg_sample_queue_flush(decoder->wg_sample_queue, false); - - return hr; -} - -static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock) -{ - FIXME("iface %p, lock %ld stub!\n", iface, lock); - return E_NOTIMPL; -} - -static const IMediaObjectVtbl media_object_vtbl = -{ - media_object_QueryInterface, - media_object_AddRef, - media_object_Release, - media_object_GetStreamCount, - media_object_GetInputStreamInfo, - media_object_GetOutputStreamInfo, - media_object_GetInputType, - media_object_GetOutputType, - media_object_SetInputType, - media_object_SetOutputType, - media_object_GetInputCurrentType, - media_object_GetOutputCurrentType, - media_object_GetInputSizeInfo, - media_object_GetOutputSizeInfo, - media_object_GetInputMaxLatency, - media_object_SetInputMaxLatency, - media_object_Flush, - media_object_Discontinuity, - media_object_AllocateStreamingResources, - media_object_FreeStreamingResources, - media_object_GetInputStatus, - media_object_ProcessInput, - media_object_ProcessOutput, - media_object_Lock, -}; - -static inline struct wmv_decoder *impl_from_IPropertyBag(IPropertyBag *iface) -{ - return CONTAINING_RECORD(iface, struct wmv_decoder, IPropertyBag_iface); -} - -static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out) -{ - return IUnknown_QueryInterface(impl_from_IPropertyBag(iface)->outer, iid, out); -} - -static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface) -{ - return IUnknown_AddRef(impl_from_IPropertyBag(iface)->outer); -} - -static ULONG WINAPI property_bag_Release(IPropertyBag *iface) -{ - return IUnknown_Release(impl_from_IPropertyBag(iface)->outer); -} - -static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value, - IErrorLog *error_log) -{ - FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value) -{ - FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value); - return S_OK; -} - -static const IPropertyBagVtbl property_bag_vtbl = -{ - property_bag_QueryInterface, - property_bag_AddRef, - property_bag_Release, - property_bag_Read, - property_bag_Write, -}; - -static inline struct wmv_decoder *impl_from_IPropertyStore(IPropertyStore *iface) -{ - return CONTAINING_RECORD(iface, struct wmv_decoder, IPropertyStore_iface); -} - -static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID iid, void **out) -{ - return IUnknown_QueryInterface(impl_from_IPropertyStore(iface)->outer, iid, out); -} - -static ULONG WINAPI property_store_AddRef(IPropertyStore *iface) -{ - return IUnknown_AddRef(impl_from_IPropertyStore(iface)->outer); -} - -static ULONG WINAPI property_store_Release(IPropertyStore *iface) -{ - return IUnknown_Release(impl_from_IPropertyStore(iface)->outer); -} - -static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count) -{ - FIXME("iface %p, count %p stub!\n", iface, count); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key) -{ - FIXME("iface %p, index %lu, key %p stub!\n", iface, index, key); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value) -{ - FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value) -{ - FIXME("iface %p, key %p, value %p stub!\n", iface, key, value); - return E_NOTIMPL; -} - -static HRESULT WINAPI property_store_Commit(IPropertyStore *iface) -{ - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; -} - -static const IPropertyStoreVtbl property_store_vtbl = -{ - property_store_QueryInterface, - property_store_AddRef, - property_store_Release, - property_store_GetCount, - property_store_GetAt, - property_store_GetValue, - property_store_SetValue, - property_store_Commit, -}; - -HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out) -{ - static const struct wg_format input_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO_WMV, - .u.video.format = WG_VIDEO_FORMAT_WMV3, - }; - static const struct wg_format output_format = - { - .major_type = WG_MAJOR_TYPE_VIDEO, - .u.video = - { - .format = WG_VIDEO_FORMAT_NV12, - .width = 1920, - .height = 1080, - }, - }; - struct wg_transform_attrs attrs = {0}; - wg_transform_t transform; - struct wmv_decoder *decoder; - HRESULT hr; - - TRACE("outer %p, out %p.\n", outer, out); - - if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) - { - ERR_(winediag)("GStreamer doesn't support WMV decoding, please install appropriate plugins.\n"); - return E_FAIL; - } - wg_transform_destroy(transform); - - if (!(decoder = calloc(1, sizeof(*decoder)))) - return E_OUTOFMEMORY; - if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) - { - free(decoder); - return hr; - } - - decoder->IUnknown_inner.lpVtbl = &unknown_vtbl; - decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; - decoder->IMediaObject_iface.lpVtbl = &media_object_vtbl; - decoder->IPropertyBag_iface.lpVtbl = &property_bag_vtbl; - decoder->IPropertyStore_iface.lpVtbl = &property_store_vtbl; - decoder->refcount = 1; - decoder->outer = outer ? outer : &decoder->IUnknown_inner; - - *out = &decoder->IUnknown_inner; - TRACE("Created %p\n", *out); - return S_OK; -}
On Fri Apr 26 11:47:33 2024 +0000, Rémi Bernon wrote:
The WMV decoder MF transform also aligns buffers the same way as the H264 decoder, so the output plane alignment could be kept. The input queue length attribute also could probably be kept. I'm not sure if it supports frame size changes, that would require some tests with concatenated streams like we have for H264, although I think it's probably safe to keep it as default.
keeping frame size change will make the ProcessOutput tests return unexpected value.
On Fri Apr 26 07:02:21 2024 +0000, Ziqing Hui wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/5508/diffs?diff_id=111382&start_sha=b62443f2b2bb575921f74db16b340f5f6bf763ef#bd62eaa50df6790a4fd6a511972092cad3bb6fa1_1553_1570)
Oh, I found MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER is also exposed by h264 decoder.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/video_decoder.c:
goto done; if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, &value)))
- { hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, (LONG *)&value);
value = abs((INT32)value);
- } if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, value))) goto done;
```suggestion:-6+0 /* WMV decoder uses positive stride by default, and enforces it for YUV formats, accepts negative stride for RGB if specified */ if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, width, &default_stride))) goto done; if (!output_type || FAILED(IMFMediaType_GetUINT32(output_type, &MF_MT_DEFAULT_STRIDE, (UINT32 *)&stride))) stride = abs(default_stride); else if (default_stride > 0) stride = abs(stride); if (FAILED(hr) || FAILED(hr = IMFVideoMediaType_SetUINT32(video_type, &MF_MT_DEFAULT_STRIDE, stride))) goto done; ```
With `LONG default_stride, stride;` declared above, should pass the tests (removing the need for the "WMV1 -> YUV (negative stride)" test todo).
Then I think something like https://gitlab.winehq.org/wine/wine/-/merge_requests/5541 could also help reduce the number of todo_wine, which are causing the test to fail (because of too much output being printed). It also splits the wg_transform_quartz change to make it cleaner, leaving WMA change for later.
On Sun Apr 28 01:47:43 2024 +0000, Rémi Bernon wrote:
Then I think something like https://gitlab.winehq.org/wine/wine/-/merge_requests/5541 could also help reduce the number of todo_wine, which are causing the test to fail (because of too much output being printed). It also splits the wg_transform_quartz change to make it cleaner, leaving WMA change for later.
Maybe I should wait for !5541 to be merged first and rebase this MR on it then?