Along with !4449, this fixes WMV videos in microkiri (https://bugs.winehq.org/show_bug.cgi?id=9127#c102) and Wagamama High Spec Trial Edition (https://wagahigh.com/download_trial.php#normal ; ダウンロード means download).
-- v4: winegstreamer/tests: Test IMediaObject_GetOutputSizeInfo. winegstreamer: Implement DMO interface for WMA decoder. winegstreamer: Switch WMA decoder to use wg_format internally. winegstreamer: Implement WMA <-> AMT conversion.
From: Alfred Agrell floating@muncher.se
--- dlls/winegstreamer/wg_format.c | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 7d4bc7a5f8c..018f554dcff 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -201,6 +201,68 @@ static void wg_format_from_caps_audio_mpeg1(struct wg_format *format, const GstC format->u.audio_mpeg1.rate = rate; }
+static void wg_format_from_caps_audio_wma(struct wg_format *format, const GstCaps *caps) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gint version, bitrate, rate, depth, channels, block_align; + const GValue *codec_data_value; + GstBuffer *codec_data; + GstMapInfo map; + + if (!gst_structure_get_int(structure, "wmaversion", &version)) + { + GST_WARNING("Missing "wmaversion" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "bitrate", &bitrate)) + { + GST_WARNING("Missing "bitrate" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "rate", &rate)) + { + GST_WARNING("Missing "rate" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "depth", &depth)) + { + GST_WARNING("Missing "depth" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "channels", &channels)) + { + GST_WARNING("Missing "channels" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!gst_structure_get_int(structure, "block_align", &block_align)) + { + GST_WARNING("Missing "block_align" value in %" GST_PTR_FORMAT ".", caps); + return; + } + if (!(codec_data_value = gst_structure_get_value(structure, "codec_data")) || !(codec_data = gst_value_get_buffer(codec_data_value))) + { + GST_WARNING("Missing "codec_data" value in %" GST_PTR_FORMAT ".", caps); + return; + } + + format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; + format->u.audio_wma.version = version; + format->u.audio_wma.bitrate = bitrate; + format->u.audio_wma.rate = rate; + format->u.audio_wma.depth = depth; + format->u.audio_wma.channels = channels; + format->u.audio_wma.block_align = block_align; + + gst_buffer_map(codec_data, &map, GST_MAP_READ); + if (map.size <= ARRAY_SIZE(format->u.audio_wma.codec_data)) + { + format->u.audio_wma.codec_data_len = map.size; + memcpy(format->u.audio_wma.codec_data, map.data, map.size); + } + else GST_WARNING("Too big codec_data value (%u) in %" GST_PTR_FORMAT ".", (unsigned)map.size, caps); + gst_buffer_unmap(codec_data, &map); +} + static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps) { const GstStructure *structure = gst_caps_get_structure(caps, 0); @@ -336,6 +398,10 @@ void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) { wg_format_from_caps_audio_mpeg1(format, caps); } + else if (!strcmp(name, "audio/x-wma")) + { + wg_format_from_caps_audio_wma(format, caps); + } else if (!strcmp(name, "video/x-cinepak")) { wg_format_from_caps_video_cinepak(format, caps);
From: Alfred Agrell floating@muncher.se
--- dlls/winegstreamer/quartz_parser.c | 130 ++++++++++++++++++++++++++++- dlls/wmvcore/tests/wmvcore.c | 11 ++- 2 files changed, 133 insertions(+), 8 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 0670fbd5181..bb382420872 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -278,6 +278,71 @@ static bool amt_from_wg_format_audio_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo return false; }
+static bool amt_from_wg_format_audio_wma(AM_MEDIA_TYPE *mt, const struct wg_format *format) +{ + WAVEFORMATEX *wave_format; + WORD fmt_tag; + DWORD size; + const GUID *subtype; + + mt->majortype = MEDIATYPE_Audio; + mt->formattype = FORMAT_WaveFormatEx; + + switch (format->u.audio_wma.version) + { + case 1: + subtype = &MEDIASUBTYPE_MSAUDIO1; + size = sizeof(MSAUDIO1WAVEFORMAT); + fmt_tag = WAVE_FORMAT_MSAUDIO1; + break; + case 2: + subtype = &MEDIASUBTYPE_WMAUDIO2; + size = sizeof(WMAUDIO2WAVEFORMAT); + fmt_tag = WAVE_FORMAT_WMAUDIO2; + break; + case 3: + subtype = &MEDIASUBTYPE_WMAUDIO3; + size = sizeof(WMAUDIO3WAVEFORMAT); + fmt_tag = WAVE_FORMAT_WMAUDIO2; + break; + case 4: + subtype = &MEDIASUBTYPE_WMAUDIO_LOSSLESS; + size = sizeof(WAVEFORMATEX) + 18; + fmt_tag = WAVE_FORMAT_WMAUDIO_LOSSLESS; + break; + default: + assert(false); + return false; + } + + if (!(wave_format = CoTaskMemAlloc(size))) + return false; + memset(wave_format, 0, size); + + mt->subtype = *subtype; + mt->bFixedSizeSamples = TRUE; + mt->lSampleSize = format->u.audio_wma.block_align; + mt->cbFormat = size; + mt->pbFormat = (BYTE *)wave_format; + wave_format->wFormatTag = fmt_tag; + wave_format->nChannels = format->u.audio_wma.channels; + wave_format->nSamplesPerSec = format->u.audio_wma.rate; + wave_format->nAvgBytesPerSec = format->u.audio_wma.bitrate / 8; + wave_format->nBlockAlign = format->u.audio_wma.block_align; + wave_format->wBitsPerSample = format->u.audio_wma.depth; + wave_format->cbSize = size - sizeof(WAVEFORMATEX); + + if (format->u.audio_wma.version == 1 && format->u.audio_wma.codec_data_len == 4) + memcpy(wave_format+1, format->u.audio_wma.codec_data, 4); + if (format->u.audio_wma.version == 2 && format->u.audio_wma.codec_data_len == 10) + memcpy(wave_format+1, format->u.audio_wma.codec_data, 10); + if (format->u.audio_wma.version == 3 && format->u.audio_wma.codec_data_len == 18) + memcpy(wave_format+1, format->u.audio_wma.codec_data, 18); + if (format->u.audio_wma.version == 4 && format->u.audio_wma.codec_data_len == 18) + memcpy(wave_format+1, format->u.audio_wma.codec_data, 18); + return true; +} + #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1))
static unsigned int wg_format_get_max_size_video_raw(enum wg_video_format format, unsigned int width, unsigned int height) @@ -384,8 +449,13 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) } break;
- case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: + /* Estimated max size of a compressed audio frame. + * There's no way to no way to know the real upper bound, + * so let's just use one second of decompressed size and hope it works. */ + return format->u.audio_wma.rate * format->u.audio_wma.channels * format->u.audio_wma.depth / 8; + + case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: @@ -643,7 +713,6 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool switch (format->major_type) { case WG_MAJOR_TYPE_AUDIO_MPEG4: - case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); @@ -657,6 +726,9 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool case WG_MAJOR_TYPE_AUDIO_MPEG1: return amt_from_wg_format_audio_mpeg1(mt, format);
+ case WG_MAJOR_TYPE_AUDIO_WMA: + return amt_from_wg_format_audio_wma(mt, format); + case WG_MAJOR_TYPE_VIDEO: return amt_from_wg_format_video(mt, format, wm);
@@ -787,6 +859,55 @@ static bool amt_to_wg_format_audio_mpeg1_layer3(const AM_MEDIA_TYPE *mt, struct return true; }
+static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format *format) +{ + const WAVEFORMATEX *audio_format = (const WAVEFORMATEX *)mt->pbFormat; + + if (!IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx)) + { + 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_wma.version = 1; + else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2)) + format->u.audio_wma.version = 2; + else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3)) + format->u.audio_wma.version = 3; + else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS)) + format->u.audio_wma.version = 4; + else + { + ERR("Unexpected subtype %s.\n", debugstr_guid(&mt->subtype)); + return false; + } + format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; + format->u.audio_wma.bitrate = audio_format->nAvgBytesPerSec * 8; + format->u.audio_wma.rate = audio_format->nSamplesPerSec; + format->u.audio_wma.depth = audio_format->wBitsPerSample; + format->u.audio_wma.channels = audio_format->nChannels; + format->u.audio_wma.block_align = audio_format->nBlockAlign; + + format->u.audio_wma.codec_data_len = 0; + if (format->u.audio_wma.version == 1) + format->u.audio_wma.codec_data_len = 4; + if (format->u.audio_wma.version == 2) + format->u.audio_wma.codec_data_len = 10; + if (format->u.audio_wma.version == 3) + format->u.audio_wma.codec_data_len = 18; + if (format->u.audio_wma.version == 4) + format->u.audio_wma.codec_data_len = 18; + memcpy(format->u.audio_wma.codec_data, audio_format+1, format->u.audio_wma.codec_data_len); + + return true; +} + static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *format) { static const struct @@ -932,6 +1053,11 @@ bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) return amt_to_wg_format_audio_mpeg1(mt, format); if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MP3)) return amt_to_wg_format_audio_mpeg1_layer3(mt, format); + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MSAUDIO1) + || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2) + || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3) + || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS)) + return amt_to_wg_format_audio_wma(mt, format); return amt_to_wg_format_audio(mt, format); }
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index f40ae37c0ce..1741299e654 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1455,7 +1455,7 @@ static void check_audio_type(const WM_MEDIA_TYPE *mt) }
static void test_stream_media_props(IWMStreamConfig *config, - const GUID *majortype, const GUID *subtype, const GUID *formattype, BOOL todo_subtype) + const GUID *majortype, const GUID *subtype, const GUID *formattype) { char mt_buffer[2000]; WM_MEDIA_TYPE *mt = (WM_MEDIA_TYPE *)mt_buffer; @@ -1484,7 +1484,6 @@ static void test_stream_media_props(IWMStreamConfig *config, ok(size == sizeof(WM_MEDIA_TYPE) + mt->cbFormat, "got %lu.\n", size); ok(IsEqualGUID(&mt->majortype, majortype), "Expected major type %s, got %s.\n", debugstr_guid(majortype), debugstr_guid(&mt->majortype)); - todo_wine_if(todo_subtype) ok(IsEqualGUID(&mt->subtype, subtype), "Expected sub type %s, got %s.\n", debugstr_guid(subtype), debugstr_guid(&mt->subtype)); ok(IsEqualGUID(&mt->formattype, formattype), "Expected format type %s, got %s.\n", @@ -1546,9 +1545,9 @@ static void test_sync_reader_types(void) ok(IsEqualGUID(&majortype, &MEDIATYPE_Audio), "Got major type %s.\n", debugstr_guid(&majortype));
if (IsEqualGUID(&majortype, &MEDIATYPE_Audio)) - test_stream_media_props(config, &MEDIATYPE_Audio, &MEDIASUBTYPE_MSAUDIO1, &FORMAT_WaveFormatEx, TRUE); + test_stream_media_props(config, &MEDIATYPE_Audio, &MEDIASUBTYPE_MSAUDIO1, &FORMAT_WaveFormatEx); else - test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo, FALSE); + test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo);
ref = IWMStreamConfig_Release(config); ok(!ref, "Got outstanding refcount %ld.\n", ref); @@ -3425,9 +3424,9 @@ static void test_async_reader_types(void) ok(IsEqualGUID(&majortype, &MEDIATYPE_Audio), "Got major type %s.\n", debugstr_guid(&majortype));
if (IsEqualGUID(&majortype, &MEDIATYPE_Audio)) - test_stream_media_props(config, &MEDIATYPE_Audio, &MEDIASUBTYPE_MSAUDIO1, &FORMAT_WaveFormatEx, TRUE); + test_stream_media_props(config, &MEDIATYPE_Audio, &MEDIASUBTYPE_MSAUDIO1, &FORMAT_WaveFormatEx); else - test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo, FALSE); + test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo);
ref = IWMStreamConfig_Release(config); ok(!ref, "Got outstanding refcount %ld.\n", ref);
From: Alfred Agrell floating@muncher.se
--- dlls/mf/tests/transform.c | 1 + dlls/winegstreamer/wma_decoder.c | 90 +++++++++++--------------------- 2 files changed, 31 insertions(+), 60 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 3f5524784cc..56103c25d09 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3042,6 +3042,7 @@ static void test_wma_decoder(void) ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050, .required = TRUE), ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2, .required = TRUE), ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 4003), /* not required by SetInputType, but needed for the transform to work */ + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), {0}, }; static const struct attribute_desc output_type_desc[] = diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index d1082fe327a..5d63908481e 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -52,10 +52,11 @@ struct wma_decoder IUnknown *outer; LONG refcount;
- IMFMediaType *input_type; - MFT_INPUT_STREAM_INFO input_info; - IMFMediaType *output_type; - MFT_OUTPUT_STREAM_INFO output_info; + struct wg_format input_format; + struct wg_format output_format; + + DWORD input_buf_size; + DWORD output_buf_size;
wg_transform_t wg_transform; struct wg_sample_queue *wg_sample_queue; @@ -68,22 +69,19 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface)
static HRESULT try_create_wg_transform(struct wma_decoder *decoder) { - struct wg_format input_format, output_format; struct wg_transform_attrs attrs = {0};
if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); decoder->wg_transform = 0;
- mf_media_type_to_wg_format(decoder->input_type, &input_format); - if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE;
- mf_media_type_to_wg_format(decoder->output_type, &output_format); - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + if (decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE;
- if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) + if (!(decoder->wg_transform = wg_transform_create(&decoder->input_format, &decoder->output_format, &attrs))) return E_FAIL;
return S_OK; @@ -135,10 +133,6 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) { 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);
wg_sample_queue_destroy(decoder->wg_sample_queue); free(decoder); @@ -207,13 +201,17 @@ static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id
TRACE("iface %p, id %lu, info %p.\n", iface, id, info);
- if (!decoder->input_type || !decoder->output_type) + if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN || decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) { memset(info, 0, sizeof(*info)); return MF_E_TRANSFORM_TYPE_NOT_SET; }
- *info = decoder->input_info; + info->hnsMaxLatency = 0; + info->dwFlags = 0; + info->cbSize = decoder->input_buf_size; + info->cbMaxLookahead = 0; + info->cbAlignment = 1; return S_OK; }
@@ -223,13 +221,13 @@ static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD i
TRACE("iface %p, id %lu, info %p.\n", iface, id, info);
- if (!decoder->input_type || !decoder->output_type) + if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN || decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) { memset(info, 0, sizeof(*info)); return MF_E_TRANSFORM_TYPE_NOT_SET; }
- *info = decoder->output_info; + *info = (MFT_OUTPUT_STREAM_INFO){ 0, decoder->output_buf_size, 1 }; return S_OK; }
@@ -273,7 +271,7 @@ static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - UINT32 channel_count, sample_size, sample_rate, block_alignment; + UINT32 sample_size, block_alignment; struct wma_decoder *decoder = impl_from_IMFTransform(iface); IMFMediaType *media_type; const GUID *output_type; @@ -281,7 +279,7 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR
TRACE("iface %p, id %lu, index %lu, type %p.\n", iface, id, index, type);
- if (!decoder->input_type) + if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_TRANSFORM_TYPE_NOT_SET;
*type = NULL; @@ -312,20 +310,16 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size))) goto done;
- if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))) - goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channel_count))) + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, decoder->input_format.u.audio_wma.channels))) goto done;
- if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample_rate))) - goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, sample_rate))) + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, decoder->input_format.u.audio_wma.rate))) goto done;
- block_alignment = sample_size * channel_count / 8; + block_alignment = sample_size * decoder->input_format.u.audio_wma.channels / 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, sample_rate * block_alignment))) + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, decoder->input_format.u.audio_wma.rate * block_alignment))) goto done;
if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) @@ -381,23 +375,9 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK;
- if (!decoder->input_type && FAILED(hr = MFCreateMediaType(&decoder->input_type))) - return hr; - - if (decoder->output_type) - { - IMFMediaType_Release(decoder->output_type); - decoder->output_type = NULL; - } - - if (SUCCEEDED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->input_type))) - decoder->input_info.cbSize = block_alignment; - else - { - IMFMediaType_Release(decoder->input_type); - decoder->input_info.cbSize = 0; - decoder->input_type = NULL; - } + 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;
return hr; } @@ -413,7 +393,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_type) + if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_TRANSFORM_TYPE_NOT_SET;
if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || @@ -456,25 +436,18 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK;
- if (FAILED(IMFMediaType_SetUINT32(decoder->input_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size))) - return MF_E_INVALIDMEDIATYPE; - - if (!decoder->output_type && FAILED(hr = MFCreateMediaType(&decoder->output_type))) - return hr; + decoder->input_format.u.audio_wma.depth = sample_size;
- if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) - goto failed; + mf_media_type_to_wg_format(type, &decoder->output_format); + decoder->output_buf_size = 1024 * block_alignment * channel_count;
if (FAILED(hr = try_create_wg_transform(decoder))) goto failed;
- decoder->output_info.cbSize = 1024 * block_alignment * channel_count; return S_OK;
failed: - IMFMediaType_Release(decoder->output_type); - decoder->output_info.cbSize = 0; - decoder->output_type = NULL; + decoder->output_format.major_type = WG_MAJOR_TYPE_UNKNOWN; return hr; }
@@ -881,9 +854,6 @@ HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out) decoder->refcount = 1; decoder->outer = outer ? outer : &decoder->IUnknown_inner;
- decoder->input_info.cbAlignment = 1; - decoder->output_info.cbAlignment = 1; - *out = &decoder->IUnknown_inner; TRACE("Created decoder %p\n", *out); return S_OK;
From: Alfred Agrell floating@muncher.se
--- dlls/mf/tests/transform.c | 32 +---- dlls/winegstreamer/wma_decoder.c | 240 ++++++++++++++++++++++++++++--- 2 files changed, 222 insertions(+), 50 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 56103c25d09..a95926d9dc1 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -1384,7 +1384,7 @@ static void check_dmo_media_type_(int line, DMO_MEDIA_TYPE *media_type, const DM "Got unexpected formattype %s.\n", debugstr_guid(&media_type->formattype)); ok_(__FILE__, line)(media_type->pUnk == NULL, "Got unexpected pUnk %p.\n", media_type->pUnk); - todo_wine_if(expected->cbFormat && expected->cbFormat != sizeof(VIDEOINFOHEADER)) + todo_wine_if(expected->cbFormat && expected->cbFormat != sizeof(VIDEOINFOHEADER) && IsEqualGUID(&expected->majortype, &MEDIATYPE_Video)) check_member_(__FILE__, line, *media_type, *expected, "%lu", cbFormat);
if (expected->pbFormat) @@ -3384,8 +3384,6 @@ static void test_wma_decoder_dmo_input_type(void) bad_input_type = (void *)buffer_bad;
/* Test GetInputType. */ - todo_wine - { count = ARRAY_SIZE(expected_input_types); hr = IMediaObject_GetInputType(dmo, 1, 0, NULL); ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetInputType returned %#lx.\n", hr); @@ -3401,7 +3399,6 @@ static void test_wma_decoder_dmo_input_type(void) ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr); hr = IMediaObject_GetInputType(dmo, 0, count - 1, NULL); ok(hr == S_OK, "GetInputType returned %#lx.\n", hr); - }
i = -1; while (SUCCEEDED(hr = IMediaObject_GetInputType(dmo, 0, ++i, &type))) @@ -3411,17 +3408,13 @@ static void test_wma_decoder_dmo_input_type(void) MoFreeMediaType(&type); winetest_pop_context(); } - todo_wine ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr); - todo_wine ok(i == count, "%lu types.\n", i);
/* Test SetInputType. */ init_dmo_media_type_audio(good_input_type, &MEDIASUBTYPE_WMAUDIO2, 2, 22050, 32); memset(bad_input_type, 0, sizeof(buffer_bad));
- todo_wine - { hr = IMediaObject_SetInputType(dmo, 1, NULL, 0); ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_SetInputType(dmo, 1, bad_input_type, 0); @@ -3477,11 +3470,9 @@ static void test_wma_decoder_dmo_input_type(void) ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0x4); ok(hr == E_INVALIDARG, "SetInputType returned %#lx.\n", hr); - }
/* Test GetInputCurrentType. */ hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR); - todo_wine ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_GetInputCurrentType(dmo, 1, NULL); todo_wine @@ -3497,7 +3488,6 @@ static void test_wma_decoder_dmo_input_type(void) ok(hr == DMO_E_TYPE_NOT_SET, "GetInputCurrentType returned %#lx.\n", hr);
hr = IMediaObject_SetInputType(dmo, 0, good_input_type, 0); - todo_wine ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_GetInputCurrentType(dmo, 1, NULL); todo_wine @@ -3567,18 +3557,13 @@ static void test_wma_decoder_dmo_output_type(void)
/* Test GetOutputType. */ hr = IMediaObject_GetOutputType(dmo, 1, 0, NULL); - todo_wine ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputType returned %#lx.\n", hr); hr = IMediaObject_GetOutputType(dmo, 0, 0, NULL); - todo_wine ok(hr == DMO_E_TYPE_NOT_SET, "GetOutputType returned %#lx.\n", hr);
hr = IMediaObject_SetInputType(dmo, 0, input_type, 0); - todo_wine ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
- todo_wine - { count = 1; hr = IMediaObject_GetOutputType(dmo, 1, 0, NULL); ok(hr == DMO_E_INVALIDSTREAMINDEX, "GetOutputType returned %#lx.\n", hr); @@ -3594,7 +3579,6 @@ static void test_wma_decoder_dmo_output_type(void) ok(hr == DMO_E_NO_MORE_ITEMS, "GetOutputType returned %#lx.\n", hr); hr = IMediaObject_GetOutputType(dmo, 0, count - 1, NULL); ok(hr == S_OK, "GetOutputType returned %#lx.\n", hr); - }
i = -1; while (SUCCEEDED(hr = IMediaObject_GetOutputType(dmo, 0, ++i, &type))) @@ -3604,17 +3588,12 @@ static void test_wma_decoder_dmo_output_type(void) MoFreeMediaType(&type); winetest_pop_context(); } - todo_wine ok(hr == DMO_E_NO_MORE_ITEMS, "GetInputType returned %#lx.\n", hr); - todo_wine ok(i == count, "%lu types.\n", i);
/* Test SetOutputType. */ hr = IMediaObject_SetInputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR); - todo_wine ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); - todo_wine - { hr = IMediaObject_SetOutputType(dmo, 1, NULL, 0); ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr); hr = IMediaObject_SetOutputType(dmo, 1, good_output_type, 0); @@ -3635,14 +3614,10 @@ static void test_wma_decoder_dmo_output_type(void) ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0x4); ok(hr == E_INVALIDARG, "SetOutputType returned %#lx.\n", hr); - }
hr = IMediaObject_SetInputType(dmo, 0, input_type, 0); - todo_wine ok(hr == S_OK, "SetInputType returned %#lx.\n", hr);
- todo_wine - { hr = IMediaObject_SetOutputType(dmo, 1, NULL, 0); ok(hr == DMO_E_INVALIDSTREAMINDEX, "SetOutputType returned %#lx.\n", hr); hr = IMediaObject_SetOutputType(dmo, 1, bad_output_type, 0); @@ -3698,11 +3673,9 @@ static void test_wma_decoder_dmo_output_type(void) ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0x4); ok(hr == E_INVALIDARG, "SetOutputType returned %#lx.\n", hr); - }
/* Test GetOutputCurrentType. */ hr = IMediaObject_SetOutputType(dmo, 0, NULL, DMO_SET_TYPEF_CLEAR); - todo_wine ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); todo_wine { @@ -3717,7 +3690,6 @@ static void test_wma_decoder_dmo_output_type(void) }
hr = IMediaObject_SetOutputType(dmo, 0, good_output_type, 0); - todo_wine ok(hr == S_OK, "SetOutputType returned %#lx.\n", hr); todo_wine { @@ -3740,7 +3712,6 @@ static void test_wma_decoder_dmo_output_type(void) todo_wine ok(hr == S_OK, "GetInputCurrentType returned %#lx.\n", hr); hr = IMediaObject_SetInputType(dmo, 0, input_type, 0); - todo_wine ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_GetOutputCurrentType(dmo, 0, &type); todo_wine @@ -3748,7 +3719,6 @@ static void test_wma_decoder_dmo_output_type(void)
init_dmo_media_type_audio(input_type, input_subtype, channel_count, rate * 2, 32); hr = IMediaObject_SetInputType(dmo, 0, input_type, 0); - todo_wine ok(hr == S_OK, "SetInputType returned %#lx.\n", hr); hr = IMediaObject_GetOutputCurrentType(dmo, 0, &type); todo_wine diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 5d63908481e..095401702df 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -24,6 +24,7 @@ #include "mfobjects.h" #include "mftransform.h" #include "wmcodecdsp.h" +#include "mediaerr.h"
#include "wine/debug.h"
@@ -623,29 +624,182 @@ static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWOR static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) { - FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type); - return E_NOTIMPL; + 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(wma_decoder_input_types)) + return DMO_E_NO_MORE_ITEMS; + if (!type) + return S_OK; + + memset(type, 0, sizeof(*type)); + type->majortype = MFMediaType_Audio; + type->subtype = *wma_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) { - FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type); - return E_NOTIMPL; + struct wma_decoder *decoder = impl_from_IMediaObject(iface); + WAVEFORMATEX *wfx; + + 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 >= 1) + return DMO_E_NO_MORE_ITEMS; + if (decoder->input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + 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); + + wfx = (WAVEFORMATEX *)type->pbFormat; + wfx->wFormatTag = WAVE_FORMAT_PCM; + wfx->nChannels = decoder->input_format.u.audio_wma.channels; + wfx->nSamplesPerSec = decoder->input_format.u.audio_wma.rate; + wfx->wBitsPerSample = decoder->input_format.u.audio_wma.depth; + wfx->nAvgBytesPerSec = wfx->nChannels * wfx->nSamplesPerSec * wfx->wBitsPerSample / 8; + wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8; + + return S_OK; }
static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) { - FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags); - return E_NOTIMPL; + 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); + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + + if (flags & DMO_SET_TYPEF_CLEAR) + { + if (flags != DMO_SET_TYPEF_CLEAR) + return E_INVALIDARG; + memset(&decoder->input_format, 0, sizeof(decoder->input_format)); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + return S_OK; + } + if (!type) + return E_POINTER; + if (flags & ~DMO_SET_TYPEF_TEST_ONLY) + return E_INVALIDARG; + + if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio)) + return DMO_E_TYPE_NOT_ACCEPTED; + + for (i = 0; i < ARRAY_SIZE(wma_decoder_input_types); ++i) + if (IsEqualGUID(&type->subtype, wma_decoder_input_types[i])) + break; + 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; + 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) { - FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags); - return E_NOTIMPL; + struct wma_decoder *decoder = impl_from_IMediaObject(iface); + struct wg_transform_attrs attrs = {0}; + struct wg_format wg_format; + 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 (flags & DMO_SET_TYPEF_CLEAR) + { + if (flags != DMO_SET_TYPEF_CLEAR) + return E_INVALIDARG; + memset(&decoder->output_format, 0, sizeof(decoder->output_format)); + if (decoder->wg_transform) + { + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = 0; + } + return S_OK; + } + if (!type) + return E_POINTER; + if (flags & ~DMO_SET_TYPEF_TEST_ONLY) + return E_INVALIDARG; + + if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio)) + return DMO_E_TYPE_NOT_ACCEPTED; + + for (i = 0; i < ARRAY_SIZE(wma_decoder_output_types); ++i) + if (IsEqualGUID(&type->subtype, wma_decoder_output_types[i])) + break; + 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) + return DMO_E_TYPE_NOT_SET; + + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + decoder->output_format = wg_format; + + /* Set up wg_transform. */ + if (decoder->wg_transform) + { + 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; + + return S_OK; }
static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) @@ -670,8 +824,21 @@ static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD i
static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) { - FIXME("iface %p, index %lu, size %p, alignment %p stub!\n", iface, index, size, alignment); - return E_NOTIMPL; + struct wma_decoder *decoder = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment); + + if (!size || !alignment) + return E_POINTER; + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (decoder->output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return DMO_E_TYPE_NOT_SET; + + *size = 8192; + *alignment = 1; + + return S_OK; }
static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) @@ -688,14 +855,27 @@ static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD
static HRESULT WINAPI media_object_Flush(IMediaObject *iface) { - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; + struct wma_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) { - FIXME("iface %p, index %lu stub!\n", iface, index); - return E_NOTIMPL; + 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) @@ -719,16 +899,38 @@ static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD ind static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) { - FIXME("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s stub!\n", iface, - index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); - return E_NOTIMPL; + struct wma_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) { - FIXME("iface %p, flags %#lx, count %lu, buffers %p, status %p stub!\n", iface, flags, count, buffers, status); - return E_NOTIMPL; + struct wma_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; + + hr = wg_transform_read_dmo(decoder->wg_transform, buffers); + + if (SUCCEEDED(hr)) + { + /* WMA Lossless emits anything from 0 to 12 packets of output for each packet of input */ + buffers[0].dwStatus |= DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE; + wg_sample_queue_flush(decoder->wg_sample_queue, false); + } + + return hr; }
static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock)
From: Alfred Agrell floating@muncher.se
--- dlls/mf/tests/transform.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index a95926d9dc1..51d130a6908 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3531,7 +3531,7 @@ static void test_wma_decoder_dmo_output_type(void)
char buffer_good_output[1024], buffer_bad_output[1024], buffer_input[1024]; DMO_MEDIA_TYPE *good_output_type, *bad_output_type, *input_type, type; - DWORD count, i, ret; + DWORD count, i, ret, size, alignment; IMediaObject *dmo; HRESULT hr;
@@ -3708,6 +3708,20 @@ static void test_wma_decoder_dmo_output_type(void) MoFreeMediaType(&type); }
+ /* Test GetOutputSizeInfo. */ + hr = IMediaObject_GetOutputSizeInfo(dmo, 1, NULL, NULL); + ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr); + hr = IMediaObject_GetOutputSizeInfo(dmo, 0, NULL, NULL); + ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr); + hr = IMediaObject_GetOutputSizeInfo(dmo, 0, &size, NULL); + ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr); + hr = IMediaObject_GetOutputSizeInfo(dmo, 0, NULL, &alignment); + ok(hr == E_POINTER, "GetOutputSizeInfo returned %#lx.\n", hr); + hr = IMediaObject_GetOutputSizeInfo(dmo, 0, &size, &alignment); + ok(hr == S_OK, "GetOutputSizeInfo returned %#lx.\n", hr); + ok(size == 8192, "Unexpected size %lu.\n", size); + ok(alignment == 1, "Unexpected alignment %lu.\n", alignment); + hr = IMediaObject_GetInputCurrentType(dmo, 0, input_type); todo_wine ok(hr == S_OK, "GetInputCurrentType returned %#lx.\n", hr);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=140114
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w7u_adm (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w7u_el (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w8 (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w8adm (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w864 (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w1064v1507 (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w1064v1809 (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w1064_tsign (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w10pro64 (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w10pro64_en_AE_u8 (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w11pro64 (32 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w7pro64 (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w864 (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w1064v1507 (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w1064v1809 (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w1064_2qxl (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w1064_adm (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w1064_tsign (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w10pro64 (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w10pro64_ar (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w10pro64_ja (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w10pro64_zh_CN (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== w11pro64_amd (64 bit report) ===
mf: transform.c:734: Test failed: wmadec: got result 0.
=== debian11 (32 bit report) ===
mf: transform.c:1401: Test failed: wmadec: type 0: Got nAvgBytesPerSec 176400, expected 88200. transform.c:1401: Test failed: wmadec: type 0: Got nBlockAlign 8, expected 4. transform.c:1401: Test failed: wmadec: type 0: Got wBitsPerSample 32, expected 16.
=== debian11 (32 bit ar:MA report) ===
mf: transform.c:1401: Test failed: wmadec: type 0: Got nAvgBytesPerSec 176400, expected 88200. transform.c:1401: Test failed: wmadec: type 0: Got nBlockAlign 8, expected 4. transform.c:1401: Test failed: wmadec: type 0: Got wBitsPerSample 32, expected 16.
=== debian11 (32 bit de report) ===
mf: transform.c:1401: Test failed: wmadec: type 0: Got nAvgBytesPerSec 176400, expected 88200. transform.c:1401: Test failed: wmadec: type 0: Got nBlockAlign 8, expected 4. transform.c:1401: Test failed: wmadec: type 0: Got wBitsPerSample 32, expected 16.
=== debian11 (32 bit fr report) ===
mf: transform.c:1401: Test failed: wmadec: type 0: Got nAvgBytesPerSec 176400, expected 88200. transform.c:1401: Test failed: wmadec: type 0: Got nBlockAlign 8, expected 4. transform.c:1401: Test failed: wmadec: type 0: Got wBitsPerSample 32, expected 16.
=== debian11 (32 bit he:IL report) ===
mf: transform.c:1401: Test failed: wmadec: type 0: Got nAvgBytesPerSec 176400, expected 88200. transform.c:1401: Test failed: wmadec: type 0: Got nBlockAlign 8, expected 4. transform.c:1401: Test failed: wmadec: type 0: Got wBitsPerSample 32, expected 16.
=== debian11 (32 bit hi:IN report) ===
mf: transform.c:1401: Test failed: wmadec: type 0: Got nAvgBytesPerSec 176400, expected 88200. transform.c:1401: Test failed: wmadec: type 0: Got nBlockAlign 8, expected 4. transform.c:1401: Test failed: wmadec: type 0: Got wBitsPerSample 32, expected 16.
=== debian11 (32 bit ja:JP report) ===
mf: transform.c:1401: Test failed: wmadec: type 0: Got nAvgBytesPerSec 176400, expected 88200. transform.c:1401: Test failed: wmadec: type 0: Got nBlockAlign 8, expected 4. transform.c:1401: Test failed: wmadec: type 0: Got wBitsPerSample 32, expected 16.
=== debian11 (32 bit zh:CN report) ===
mf: transform.c:1401: Test failed: wmadec: type 0: Got nAvgBytesPerSec 176400, expected 88200. transform.c:1401: Test failed: wmadec: type 0: Got nBlockAlign 8, expected 4. transform.c:1401: Test failed: wmadec: type 0: Got wBitsPerSample 32, expected 16.
=== debian11b (32 bit WoW report) ===
mf: transform.c:1401: Test failed: wmadec: type 0: Got nAvgBytesPerSec 176400, expected 88200. transform.c:1401: Test failed: wmadec: type 0: Got nBlockAlign 8, expected 4. transform.c:1401: Test failed: wmadec: type 0: Got wBitsPerSample 32, expected 16.
=== debian11b (64 bit WoW report) ===
mf: transform.c:1401: Test failed: wmadec: type 0: Got nAvgBytesPerSec 176400, expected 88200. transform.c:1401: Test failed: wmadec: type 0: Got nBlockAlign 8, expected 4. transform.c:1401: Test failed: wmadec: type 0: Got wBitsPerSample 32, expected 16.
On Tue Nov 21 14:16:03 2023 +0000, Alfred Agrell wrote:
I did that to match some other code ...which I can't find, so I guess I matched myself without thinking about it. Fixed.
I'd use sizeof() instead, since map.size is really supposed to be a byte size, but that's a minor quibble.
On Tue Nov 21 15:16:09 2023 +0000, Alfred Agrell wrote:
Needed by Wagamama. Without it, the sound channel gets stuck looping the same ~second over and over. I completely agree it's ugly; feels to me like some kind of GStreamer or ffmpeg bug. If you can think of a better solution, do tell.
I doubt it's a bug per se; PCM audio output doesn't need to be framed according to the corresponding input, and GStreamer is within its rights to split samples as it wishes.
Rather, I suspect we should set the flag if and only if there are more samples to process. That might mean setting WG_SAMPLE_FLAG_INCOMPLETE in such a case for raw audio specifically, or it might mean adding a separate flag (WG_SAMPLE_FLAG_MORE_SAMPLES_AVAILABLE or something) and setting it for the WMA decoder specifically.
On Tue Nov 21 14:16:18 2023 +0000, Alfred Agrell wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/4450/diffs?diff_id=84781&start_sha=21a3b11a99e324aa921744cebe83ced45e62ef88#50c7dd33d12b007ebcc2f1766ce91dc1d18417ef_211_211)
We potentially could start, if there's no compiler which chokes on them. Though, personally, I don't find it much clearer if you're not going to specify members by name (e.g. I almost always prefer designated initializers), and at that point you might as well just write out each assignment.
Zebediah Figura (@zfigura) commented about dlls/winegstreamer/wg_format.c:
- format->major_type = WG_MAJOR_TYPE_AUDIO_WMA;
- format->u.audio_wma.version = version;
- format->u.audio_wma.bitrate = bitrate;
- format->u.audio_wma.rate = rate;
- format->u.audio_wma.depth = depth;
- format->u.audio_wma.channels = channels;
- format->u.audio_wma.block_align = block_align;
- gst_buffer_map(codec_data, &map, GST_MAP_READ);
- if (map.size <= ARRAY_SIZE(format->u.audio_wma.codec_data))
- {
format->u.audio_wma.codec_data_len = map.size;
memcpy(format->u.audio_wma.codec_data, map.data, map.size);
- }
- else GST_WARNING("Too big codec_data value (%u) in %" GST_PTR_FORMAT ".", (unsigned)map.size, caps);
Please put if/else bodies on their own lines.
Zebediah Figura (@zfigura) commented about dlls/winegstreamer/wg_format.c:
- if (!gst_structure_get_int(structure, "depth", &depth))
- {
GST_WARNING("Missing \"depth\" value in %" GST_PTR_FORMAT ".", caps);
return;
- }
- if (!gst_structure_get_int(structure, "channels", &channels))
- {
GST_WARNING("Missing \"channels\" value in %" GST_PTR_FORMAT ".", caps);
return;
- }
- if (!gst_structure_get_int(structure, "block_align", &block_align))
- {
GST_WARNING("Missing \"block_align\" value in %" GST_PTR_FORMAT ".", caps);
return;
- }
- if (!(codec_data_value = gst_structure_get_value(structure, "codec_data")) || !(codec_data = gst_value_get_buffer(codec_data_value)))
This line is very long. 3/5 also introduces some very long lines. It'd be nice to wrap these. (In this case please see [1] for the preferred style.)
(There's no fixed limit on line length in Wine, but in general I'd consider splitting at around 100 columns or so, and I'd definitely avoid going past 120 or so.)
[1] https://wiki.winehq.org/Wine_Developer%27s_Guide/Coding_Practice#Preferred_D...
Zebediah Figura (@zfigura) commented about dlls/winegstreamer/quartz_parser.c:
- wave_format->wFormatTag = fmt_tag;
- wave_format->nChannels = format->u.audio_wma.channels;
- wave_format->nSamplesPerSec = format->u.audio_wma.rate;
- wave_format->nAvgBytesPerSec = format->u.audio_wma.bitrate / 8;
- wave_format->nBlockAlign = format->u.audio_wma.block_align;
- wave_format->wBitsPerSample = format->u.audio_wma.depth;
- wave_format->cbSize = size - sizeof(WAVEFORMATEX);
- if (format->u.audio_wma.version == 1 && format->u.audio_wma.codec_data_len == 4)
memcpy(wave_format+1, format->u.audio_wma.codec_data, 4);
- if (format->u.audio_wma.version == 2 && format->u.audio_wma.codec_data_len == 10)
memcpy(wave_format+1, format->u.audio_wma.codec_data, 10);
- if (format->u.audio_wma.version == 3 && format->u.audio_wma.codec_data_len == 18)
memcpy(wave_format+1, format->u.audio_wma.codec_data, 18);
- if (format->u.audio_wma.version == 4 && format->u.audio_wma.codec_data_len == 18)
memcpy(wave_format+1, format->u.audio_wma.codec_data, 18);
This seems redundant with the size we already calculated—it should be possible to just check codec_data_len == size.
Also, can we have a FIXME or ERR for the case where the length doesn't match what we expect?
Zebediah Figura (@zfigura) commented about dlls/winegstreamer/quartz_parser.c:
return false;
- }
- if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MSAUDIO1))
format->u.audio_wma.version = 1;
- else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2))
format->u.audio_wma.version = 2;
- else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3))
format->u.audio_wma.version = 3;
- else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS))
format->u.audio_wma.version = 4;
- else
- {
ERR("Unexpected subtype %s.\n", debugstr_guid(&mt->subtype));
return false;
- }
We explicitly check this in the caller, so you could even get rid of the else.
Zebediah Figura (@zfigura) commented about dlls/winegstreamer/quartz_parser.c:
- format->u.audio_wma.bitrate = audio_format->nAvgBytesPerSec * 8;
- format->u.audio_wma.rate = audio_format->nSamplesPerSec;
- format->u.audio_wma.depth = audio_format->wBitsPerSample;
- format->u.audio_wma.channels = audio_format->nChannels;
- format->u.audio_wma.block_align = audio_format->nBlockAlign;
- format->u.audio_wma.codec_data_len = 0;
- if (format->u.audio_wma.version == 1)
format->u.audio_wma.codec_data_len = 4;
- if (format->u.audio_wma.version == 2)
format->u.audio_wma.codec_data_len = 10;
- if (format->u.audio_wma.version == 3)
format->u.audio_wma.codec_data_len = 18;
- if (format->u.audio_wma.version == 4)
format->u.audio_wma.codec_data_len = 18;
- memcpy(format->u.audio_wma.codec_data, audio_format+1, format->u.audio_wma.codec_data_len);
We should validate cbFormat before doing this.
It'd be nice to add some more media type tests to wmvcore, to make sure our understanding of the AM_MEDIA_TYPE and WAVEFORMAT fields is correct.
On Tue Nov 21 19:17:54 2023 +0000, Zebediah Figura wrote:
We potentially could start, if there's no compiler which chokes on them. Though, personally, I don't find it much clearer if you're not going to specify members by name (e.g. I almost always prefer designated initializers), and at that point you might as well just write out each assignment.
We could, but that should be discussed among all Wine maintainers, and a MR is a quite poor place for that.
On Tue Nov 21 18:59:48 2023 +0000, Zebediah Figura wrote:
I'd use sizeof() instead, since map.size is really supposed to be a byte size, but that's a minor quibble.
Yeah, that sounds slightly cleaner.
On Tue Nov 21 19:15:05 2023 +0000, Zebediah Figura wrote:
I doubt it's a bug per se; PCM audio output doesn't need to be framed according to the corresponding input, and GStreamer is within its rights to split samples as it wishes. Rather, I suspect we should set the flag if and only if there are more samples to process. That might mean setting WG_SAMPLE_FLAG_INCOMPLETE in such a case for raw audio specifically, or it might mean adding a separate flag (WG_SAMPLE_FLAG_MORE_SAMPLES_AVAILABLE or something) and setting it for the WMA decoder specifically.
Hard to know if there are more samples to process, other than by simply always saying there's more and occasionally returning "sorry, I've got nothing after all". The first input packet returns zero output packets, so the DMO wrapper has to be prepared for unexpected emptiness anyways; might as well reuse that codepath.
This code is in the WMA decoder specifically.
On Tue Nov 21 21:53:53 2023 +0000, Zebediah Figura wrote:
It'd be nice to add some more media type tests to wmvcore, to make sure our understanding of the AM_MEDIA_TYPE and WAVEFORMAT fields is correct.
Yes, it would. I created a comprehensive test for WMV1+WMA1 media types in !4449 using test.wmv, but as I said at https://gitlab.winehq.org/wine/wine/-/merge_requests/4450#note_53102, I don't have access to other suitable test files; if you do, upload em somewhere and I'll add them.
On Tue Nov 21 19:58:21 2023 +0000, Zebediah Figura wrote:
Please put if/else bodies on their own lines.
Sure
On Tue Nov 21 19:58:22 2023 +0000, Zebediah Figura wrote:
This line is very long. 3/5 also introduces some very long lines. It'd be nice to wrap these. (In this case please see [1] for the preferred style.) (There's no fixed limit on line length in Wine, but in general I'd consider splitting at around 100 columns or so, and I'd definitely avoid going past 120 or so.) [1] https://wiki.winehq.org/Wine_Developer%27s_Guide/Coding_Practice#Preferred_D...
Good point, I've been overfocusing on getting it working and keep forgetting the code style stuff.
On Tue Nov 21 19:58:26 2023 +0000, Zebediah Figura wrote:
This seems redundant with the size we already calculated—it should be possible to just check codec_data_len == size. Also, can we have a FIXME or ERR for the case where the length doesn't match what we expect?
Good point