From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 --- dlls/winegstreamer/mfplat.c | 48 ++++++++++++++++++++++++++++++ dlls/winegstreamer/quartz_parser.c | 2 ++ dlls/winegstreamer/unixlib.h | 7 +++++ dlls/winegstreamer/wg_format.c | 34 +++++++++++++++++++++ dlls/winegstreamer/wg_transform.c | 2 ++ dlls/winegstreamer/wm_reader.c | 4 +++ 6 files changed, 97 insertions(+)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 9e6a43a3414..d7d6810965e 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -550,6 +550,7 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) switch (format->major_type) { case WG_MAJOR_TYPE_AUDIO_MPEG1: + case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: @@ -618,6 +619,51 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, const GUID *sub FIXME("Unrecognized audio subtype %s, depth %u.\n", debugstr_guid(subtype), depth); }
+static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, struct wg_format *format) +{ + /* Audio specific config is stored at after HEAACWAVEINFO in MF_MT_USER_DATA + * https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-heaacwavef... + */ + typedef struct + { + WORD wPayloadType; + WORD wAudioProfileLevelIndication; + WORD wStructType; + WORD wReserved1; + DWORD dwReserved2; + } HEAACWAVEINFO; + typedef struct + { + HEAACWAVEINFO wfInfo; + BYTE pbAudioSpecificConfig[1]; + } HEAACWAVEFORMAT; + + BYTE buffer[64]; + HEAACWAVEFORMAT *user_data = (HEAACWAVEFORMAT *)buffer; + UINT32 codec_data_size; + + if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, buffer, sizeof(buffer), &codec_data_size))) + { + FIXME("Codec data is not set.\n"); + return; + } + + codec_data_size -= min(codec_data_size, offsetof(HEAACWAVEFORMAT, pbAudioSpecificConfig)); + if (codec_data_size > sizeof(format->u.audio_mpeg4.codec_data)) + { + FIXME("Codec data needs %u bytes.\n", codec_data_size); + return; + } + + format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG4; + + if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &format->u.audio_mpeg4.payload_type))) + format->u.audio_mpeg4.payload_type = -1; + + format->u.audio_mpeg4.codec_data_len = codec_data_size; + memcpy(format->u.audio_mpeg4.codec_data, user_data->pbAudioSpecificConfig, codec_data_size); +} + static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *subtype, struct wg_format *format) { UINT64 frame_rate, frame_size; @@ -781,6 +827,8 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9) || IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) mf_media_type_to_wg_format_audio_wma(type, &subtype, format); + else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC)) + mf_media_type_to_wg_format_audio_mpeg4(type, format); else mf_media_type_to_wg_format_audio(type, &subtype, format); } diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 55e5988e880..9369b529642 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -359,6 +359,7 @@ 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: case WG_MAJOR_TYPE_VIDEO_H264: FIXME("Format %u not implemented!\n", format->major_type); @@ -528,6 +529,7 @@ 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: FIXME("Format %u not implemented!\n", format->major_type); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 8e6c5e4cc0e..9c53ecbfbc3 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -37,6 +37,7 @@ struct wg_format WG_MAJOR_TYPE_UNKNOWN = 0, WG_MAJOR_TYPE_AUDIO, WG_MAJOR_TYPE_AUDIO_MPEG1, + WG_MAJOR_TYPE_AUDIO_MPEG4, WG_MAJOR_TYPE_AUDIO_WMA, WG_MAJOR_TYPE_VIDEO, WG_MAJOR_TYPE_VIDEO_CINEPAK, @@ -70,6 +71,12 @@ struct wg_format uint32_t channels; } audio_mpeg1; struct + { + uint32_t payload_type; + uint32_t codec_data_len; + unsigned char codec_data[64]; + } audio_mpeg4; + struct { uint32_t version; uint32_t bitrate; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index b67c820dd71..7f28b4d2c90 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -346,6 +346,37 @@ static GstCaps *wg_format_to_caps_audio_mpeg1(const struct wg_format *format) return caps; }
+static GstCaps *wg_format_to_caps_audio_mpeg4(const struct wg_format *format) +{ + GstBuffer *buffer; + GstCaps *caps; + + if (!(caps = gst_caps_new_empty_simple("audio/mpeg"))) + return NULL; + + gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); + + switch (format->u.audio_mpeg4.payload_type) + { + case 0: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "raw", NULL); break; + case 1: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "adts", NULL); break; + case 2: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "adif", NULL); break; + case 3: gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "loas", NULL); break; + } + + /* FIXME: Use gst_codec_utils_aac_caps_set_level_and_profile from GStreamer pbutils library */ + + if (format->u.audio_mpeg4.codec_data_len) + { + buffer = gst_buffer_new_and_alloc(format->u.audio_mpeg4.codec_data_len); + gst_buffer_fill(buffer, 0, format->u.audio_mpeg4.codec_data, format->u.audio_mpeg4.codec_data_len); + gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); + gst_buffer_unref(buffer); + } + + return caps; +} + static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) { GstAudioChannelPosition positions[32]; @@ -533,6 +564,8 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) return wg_format_to_caps_audio(format); case WG_MAJOR_TYPE_AUDIO_MPEG1: return wg_format_to_caps_audio_mpeg1(format); + case WG_MAJOR_TYPE_AUDIO_MPEG4: + return wg_format_to_caps_audio_mpeg4(format); case WG_MAJOR_TYPE_AUDIO_WMA: return wg_format_to_caps_audio_wma(format); case WG_MAJOR_TYPE_VIDEO: @@ -554,6 +587,7 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) switch (a->major_type) { case WG_MAJOR_TYPE_AUDIO_MPEG1: + case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: GST_FIXME("Format %u not implemented!", a->major_type); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 486562fdff6..34b8d25c2e5 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -424,6 +424,7 @@ NTSTATUS wg_transform_create(void *args) goto out; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: + case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_CINEPAK: if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) @@ -474,6 +475,7 @@ NTSTATUS wg_transform_create(void *args) break;
case WG_MAJOR_TYPE_AUDIO_MPEG1: + case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index e68e0a7d0ca..55d98671931 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1555,6 +1555,8 @@ static const char *get_major_type_string(enum wg_major_type type) return "audio"; case WG_MAJOR_TYPE_AUDIO_MPEG1: return "mpeg1-audio"; + case WG_MAJOR_TYPE_AUDIO_MPEG4: + return "mpeg4-audio"; case WG_MAJOR_TYPE_AUDIO_WMA: return "wma"; case WG_MAJOR_TYPE_VIDEO: @@ -1971,6 +1973,7 @@ static HRESULT WINAPI reader_GetOutputFormat(IWMSyncReader2 *iface, break;
case WG_MAJOR_TYPE_AUDIO_MPEG1: + case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: @@ -2010,6 +2013,7 @@ static HRESULT WINAPI reader_GetOutputFormatCount(IWMSyncReader2 *iface, DWORD o break;
case WG_MAJOR_TYPE_AUDIO_MPEG1: + case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264:
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 --- dlls/mf/tests/transform.c | 9 +- dlls/winegstreamer/aac_decoder.c | 418 +++++++++++++++++++++++++++++-- 2 files changed, 395 insertions(+), 32 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index d2bd2b9a065..d3ab6f20a40 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -1942,13 +1942,10 @@ static void test_aac_decoder(void)
check_mft_optional_methods(transform, 1); check_mft_get_attributes(transform, expect_transform_attributes, FALSE); - todo_wine check_mft_get_input_stream_info(transform, S_OK, &input_info); - todo_wine check_mft_get_output_stream_info(transform, S_OK, &output_info);
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; @@ -1962,14 +1959,10 @@ static void test_aac_decoder(void) ok(ret <= 1, "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) || broken(i == 2) /* w7 */ || broken(i == 4) /* w8 */, "%lu input media types\n", i); - if (hr == E_NOTIMPL) - goto skip_tests;
/* setting output media type first doesn't work */ check_mft_set_output_type(transform, output_type_desc, MF_E_TRANSFORM_TYPE_NOT_SET); @@ -2047,6 +2040,7 @@ static void test_aac_decoder(void) ok(i == 1, "got %lu output samples\n", i);
ret = check_mf_sample_collection(output_samples, output_sample_desc, L"aacdecdata.bin"); + todo_wine_if(ret <= 5) ok(ret == 0, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples);
@@ -2062,7 +2056,6 @@ static void test_aac_decoder(void)
ret = IMFSample_Release(input_sample); ok(ret == 0, "Release returned %lu\n", ret); -skip_tests: ret = IMFTransform_Release(transform); ok(ret == 0, "Release returned %lu\n", ret);
diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 5573166b2db..a2a6984dd18 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -28,11 +28,37 @@ #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +WINE_DECLARE_DEBUG_CHANNEL(winediag); + +extern const GUID MFAudioFormat_RAW_AAC; + +static struct +{ + const GUID *const guid; + UINT32 payload_type; +} aac_decoder_input_types[] = +{ + {&MFAudioFormat_AAC, 0}, + {&MFAudioFormat_RAW_AAC, -1}, + {&MFAudioFormat_AAC, 1}, + {&MFAudioFormat_AAC, 3}, + {&MFAudioFormat_ADTS, -1}, +}; +static const GUID *const aac_decoder_output_types[] = +{ + &MFAudioFormat_PCM, + &MFAudioFormat_Float, +};
struct aac_decoder { IMFTransform IMFTransform_iface; LONG refcount; + IMFMediaType *input_type; + IMFMediaType *output_type; + + struct wg_transform *wg_transform; + struct wg_sample_queue *wg_sample_queue; };
static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface) @@ -40,14 +66,35 @@ static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface) return CONTAINING_RECORD(iface, struct aac_decoder, IMFTransform_iface); }
+static HRESULT try_create_wg_transform(struct aac_decoder *decoder) +{ + struct wg_format input_format, output_format; + + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = NULL; + + mf_media_type_to_wg_format(decoder->input_type, &input_format); + if (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) + return MF_E_INVALIDMEDIATYPE; + + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + return E_FAIL; + + return S_OK; +} + static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { struct aac_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)) + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMFTransform)) *out = &decoder->IMFTransform_iface; else { @@ -76,7 +123,16 @@ static ULONG WINAPI transform_Release(IMFTransform *iface) TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount);
if (!refcount) + { + 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); + }
return refcount; } @@ -107,14 +163,30 @@ static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_si
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; + TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + + memset(info, 0, sizeof(*info)); + info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER + | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_INPUT_STREAM_HOLDS_BUFFERS; + + return S_OK; }
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; + TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + + memset(info, 0, sizeof(*info)); + info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES; + info->cbSize = 0xc000; + + return S_OK; }
static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) @@ -150,39 +222,280 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); - return E_NOTIMPL; + IMFMediaType *media_type; + const GUID *subtype; + HRESULT hr; + + TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + + *type = NULL; + if (index >= ARRAY_SIZE(aac_decoder_input_types)) + return MF_E_NO_MORE_TYPES; + subtype = aac_decoder_input_types[index].guid; + + if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + + if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio))) + goto done; + if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype))) + goto done; + + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, 32))) + goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, 6))) + goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, 24))) + goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000))) + goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 1152000))) + goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1))) + goto done; + if (IsEqualGUID(subtype, &MFAudioFormat_AAC)) + { + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0))) + goto done; + if (aac_decoder_input_types[index].payload_type != -1 + && FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AAC_PAYLOAD_TYPE, + aac_decoder_input_types[index].payload_type))) + goto done; + } + +done: + if (SUCCEEDED(hr)) + IMFMediaType_AddRef((*type = media_type)); + + IMFMediaType_Release(media_type); + return hr; }
static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); - return E_NOTIMPL; + UINT32 channel_count, sample_size, sample_rate, block_alignment; + struct aac_decoder *decoder = impl_from_IMFTransform(iface); + IMFMediaType *media_type; + const GUID *output_type; + HRESULT hr; + + TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + if (!decoder->input_type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *type = NULL; + + if (index >= ARRAY_SIZE(aac_decoder_output_types)) + return MF_E_NO_MORE_TYPES; + index = ARRAY_SIZE(aac_decoder_output_types) - index - 1; + output_type = aac_decoder_output_types[index]; + + if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + + if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio))) + goto done; + if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) + goto done; + + if (IsEqualGUID(output_type, &MFAudioFormat_Float)) + sample_size = 32; + else if (IsEqualGUID(output_type, &MFAudioFormat_PCM)) + sample_size = 16; + else + { + FIXME("Subtype %s not implemented!\n", debugstr_guid(output_type)); + hr = E_NOTIMPL; + goto done; + } + + 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))) + 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))) + goto done; + + block_alignment = sample_size * channel_count / 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))) + goto done; + + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) + goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1))) + goto done; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1))) + goto done; + +done: + if (SUCCEEDED(hr)) + IMFMediaType_AddRef((*type = media_type)); + + IMFMediaType_Release(media_type); + return hr; }
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; + struct aac_decoder *decoder = impl_from_IMFTransform(iface); + MF_ATTRIBUTE_TYPE item_type; + GUID major, subtype; + HRESULT hr; + ULONG i; + + TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major))) + return E_INVALIDARG; + + if (!IsEqualGUID(&major, &MFMediaType_Audio) + || FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + return MF_E_INVALIDMEDIATYPE; + + for (i = 0; i < ARRAY_SIZE(aac_decoder_input_types); ++i) + if (IsEqualGUID(&subtype, aac_decoder_input_types[i].guid)) + break; + if (i == ARRAY_SIZE(aac_decoder_input_types)) + return MF_E_INVALIDMEDIATYPE; + + if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) + || item_type != MF_ATTRIBUTE_UINT32) + return MF_E_INVALIDMEDIATYPE; + if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_USER_DATA, &item_type)) + || item_type != MF_ATTRIBUTE_BLOB) + return MF_E_INVALIDMEDIATYPE; + 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; + } + + return IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->input_type); }
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; + struct aac_decoder *decoder = impl_from_IMFTransform(iface); + MF_ATTRIBUTE_TYPE item_type; + GUID major, subtype; + HRESULT hr; + ULONG i; + + TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + if (!decoder->input_type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) + || FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + return hr; + + if (!IsEqualGUID(&major, &MFMediaType_Audio)) + return MF_E_INVALIDMEDIATYPE; + + for (i = 0; i < ARRAY_SIZE(aac_decoder_output_types); ++i) + if (IsEqualGUID(&subtype, aac_decoder_output_types[i])) + break; + if (i == ARRAY_SIZE(aac_decoder_output_types)) + return MF_E_INVALIDMEDIATYPE; + + if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type)) + || item_type != MF_ATTRIBUTE_UINT32) + return MF_E_INVALIDMEDIATYPE; + if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type)) + || item_type != MF_ATTRIBUTE_UINT32) + return MF_E_INVALIDMEDIATYPE; + if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) + || item_type != MF_ATTRIBUTE_UINT32) + return MF_E_INVALIDMEDIATYPE; + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + + if (!decoder->output_type && FAILED(hr = MFCreateMediaType(&decoder->output_type))) + return hr; + + if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) + return hr; + + if (FAILED(hr = try_create_wg_transform(decoder))) + goto failed; + + return S_OK; + +failed: + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + return hr; }
-static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **out) { - FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); - return E_NOTIMPL; + struct aac_decoder *decoder = impl_from_IMFTransform(iface); + IMFMediaType *type; + HRESULT hr; + + TRACE("iface %p, id %#lx, out %p.\n", iface, id, out); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + if (!decoder->input_type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = MFCreateMediaType(&type))) + return hr; + if (SUCCEEDED(hr = IMFMediaType_CopyAllItems(decoder->input_type, (IMFAttributes *)type))) + IMFMediaType_AddRef(*out = type); + IMFMediaType_Release(type); + + return hr; }
-static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **out) { - FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); - return E_NOTIMPL; + struct aac_decoder *decoder = impl_from_IMFTransform(iface); + IMFMediaType *type; + HRESULT hr; + + TRACE("iface %p, id %#lx, out %p.\n", iface, id, out); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + if (!decoder->output_type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = MFCreateMediaType(&type))) + return hr; + if (SUCCEEDED(hr = IMFMediaType_CopyAllItems(decoder->output_type, (IMFAttributes *)type))) + IMFMediaType_AddRef(*out = type); + IMFMediaType_Release(type); + + return hr; }
static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) @@ -217,15 +530,45 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_
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; + struct aac_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue); }
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; + struct aac_decoder *decoder = impl_from_IMFTransform(iface); + MFT_OUTPUT_STREAM_INFO info; + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + + if (count != 1) + return E_INVALIDARG; + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *status = samples->dwStatus = 0; + if (!samples->pSample) + return E_INVALIDARG; + + if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) + return hr; + + if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, + info.cbSize, NULL, &samples->dwStatus))) + wg_sample_queue_flush(decoder->wg_sample_queue, false); + else + samples->dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; + + return hr; }
static const IMFTransformVtbl transform_vtbl = @@ -260,13 +603,40 @@ static const IMFTransformVtbl transform_vtbl =
HRESULT aac_decoder_create(REFIID riid, void **ret) { + static const struct wg_format output_format = + { + .major_type = WG_MAJOR_TYPE_AUDIO, + .u.audio = + { + .format = WG_AUDIO_FORMAT_F32LE, + .channel_mask = 1, + .channels = 1, + .rate = 44100, + }, + }; + static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_AUDIO_MPEG4}; + struct wg_transform *transform; struct aac_decoder *decoder; + HRESULT hr;
TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
+ if (!(transform = wg_transform_create(&input_format, &output_format))) + { + ERR_(winediag)("GStreamer doesn't support WMA 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->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1;
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=124982
Your paranoid android.
=== debian11 (build log) ===
Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24732. Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24732. Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24732.
This merge request was approved by Zebediah Figura.