Module: wine Branch: master Commit: 4199bb7fab8e2e2eb0bea844733787f517e693d7 URL: https://gitlab.winehq.org/wine/wine/-/commit/4199bb7fab8e2e2eb0bea844733787f...
Author: Rémi Bernon rbernon@codeweavers.com Date: Mon Sep 26 12:45:14 2022 +0200
winegstreamer: Support MPEG4 (AAC) compressed audio format.
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: