Zebediah Figura : winegstreamer: Explicitly translate the channel mask.
Alexandre Julliard
julliard at winehq.org
Fri Feb 19 17:20:07 CST 2021
Module: wine
Branch: master
Commit: 8697c6c0dbc1b6878a6f070b7d6d851d4972e22a
URL: https://source.winehq.org/git/wine.git/?a=commit;h=8697c6c0dbc1b6878a6f070b7d6d851d4972e22a
Author: Zebediah Figura <z.figura12 at gmail.com>
Date: Thu Feb 18 17:01:25 2021 -0600
winegstreamer: Explicitly translate the channel mask.
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/winegstreamer/gst_private.h | 1 +
dlls/winegstreamer/gstdemux.c | 35 +++++++------
dlls/winegstreamer/wg_parser.c | 109 ++++++++++++++++++++++++++++++++++++++-
3 files changed, 129 insertions(+), 16 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 75025fdf7d5..128546a0265 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -128,6 +128,7 @@ struct wg_format
} format;
uint32_t channels;
+ uint32_t channel_mask; /* In WinMM format. */
uint32_t rate;
} audio;
} u;
diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c
index d85bb02160e..75b1cece095 100644
--- a/dlls/winegstreamer/gstdemux.c
+++ b/dlls/winegstreamer/gstdemux.c
@@ -102,20 +102,6 @@ static HRESULT WINAPI GST_ChangeCurrent(IMediaSeeking *iface);
static HRESULT WINAPI GST_ChangeStop(IMediaSeeking *iface);
static HRESULT WINAPI GST_ChangeRate(IMediaSeeking *iface);
-static DWORD channel_mask_from_count(uint32_t count)
-{
- switch (count)
- {
- case 1: return KSAUDIO_SPEAKER_MONO;
- case 2: return KSAUDIO_SPEAKER_STEREO;
- case 4: return KSAUDIO_SPEAKER_SURROUND;
- case 5: return KSAUDIO_SPEAKER_5POINT1 & ~SPEAKER_LOW_FREQUENCY;
- case 6: return KSAUDIO_SPEAKER_5POINT1;
- case 8: return KSAUDIO_SPEAKER_7POINT1;
- default: return 0;
- }
-}
-
static bool amt_from_wg_format_audio(AM_MEDIA_TYPE *mt, const struct wg_format *format)
{
mt->majortype = MEDIATYPE_Audio;
@@ -220,7 +206,7 @@ static bool amt_from_wg_format_audio(AM_MEDIA_TYPE *mt, const struct wg_format *
wave_format->Format.wBitsPerSample = depth;
wave_format->Format.cbSize = sizeof(*wave_format) - sizeof(WAVEFORMATEX);
wave_format->Samples.wValidBitsPerSample = depth;
- wave_format->dwChannelMask = channel_mask_from_count(format->u.audio.channels);
+ wave_format->dwChannelMask = format->u.audio.channel_mask;
wave_format->SubFormat = is_float ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM;
mt->lSampleSize = wave_format->Format.nBlockAlign;
}
@@ -423,6 +409,25 @@ static bool amt_to_wg_format_audio(const AM_MEDIA_TYPE *mt, struct wg_format *fo
format->u.audio.channels = audio_format->nChannels;
format->u.audio.rate = audio_format->nSamplesPerSec;
+ if (audio_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+ {
+ const WAVEFORMATEXTENSIBLE *ext_format = (const WAVEFORMATEXTENSIBLE *)mt->pbFormat;
+
+ format->u.audio.channel_mask = ext_format->dwChannelMask;
+ }
+ else
+ {
+ if (audio_format->nChannels == 1)
+ format->u.audio.channel_mask = KSAUDIO_SPEAKER_MONO;
+ else if (audio_format->nChannels == 2)
+ format->u.audio.channel_mask = KSAUDIO_SPEAKER_STEREO;
+ else
+ {
+ ERR("Unexpected channel count %u.\n", audio_format->nChannels);
+ return false;
+ }
+ }
+
for (i = 0; i < ARRAY_SIZE(format_map); ++i)
{
if (IsEqualGUID(&mt->subtype, format_map[i].subtype)
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index 272029217a9..2540ecd80df 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -109,11 +109,70 @@ static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format)
}
}
+static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position)
+{
+ static const uint32_t position_map[] =
+ {
+ SPEAKER_FRONT_LEFT,
+ SPEAKER_FRONT_RIGHT,
+ SPEAKER_FRONT_CENTER,
+ SPEAKER_LOW_FREQUENCY,
+ SPEAKER_BACK_LEFT,
+ SPEAKER_BACK_RIGHT,
+ SPEAKER_FRONT_LEFT_OF_CENTER,
+ SPEAKER_FRONT_RIGHT_OF_CENTER,
+ SPEAKER_BACK_CENTER,
+ 0,
+ SPEAKER_SIDE_LEFT,
+ SPEAKER_SIDE_RIGHT,
+ SPEAKER_TOP_FRONT_LEFT,
+ SPEAKER_TOP_FRONT_RIGHT,
+ SPEAKER_TOP_FRONT_CENTER,
+ SPEAKER_TOP_CENTER,
+ SPEAKER_TOP_BACK_LEFT,
+ SPEAKER_TOP_BACK_RIGHT,
+ 0,
+ 0,
+ SPEAKER_TOP_BACK_CENTER,
+ };
+
+ if (position < ARRAY_SIZE(position_map))
+ return position_map[position];
+ return 0;
+}
+
+static uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info)
+{
+ uint32_t mask = 0, position;
+ unsigned int i;
+
+ for (i = 0; i < GST_AUDIO_INFO_CHANNELS(info); ++i)
+ {
+ if (!(position = wg_channel_position_from_gst(GST_AUDIO_INFO_POSITION(info, i))))
+ {
+ GST_WARNING("Unsupported channel %#x.", GST_AUDIO_INFO_POSITION(info, i));
+ return 0;
+ }
+ /* Make sure it's also in WinMM order. WinMM mandates that channels be
+ * ordered, as it were, from least to most significant SPEAKER_* bit.
+ * Hence we fail if the current channel was already specified, or if any
+ * higher bit was already specified. */
+ if (mask & ~(position - 1))
+ {
+ GST_WARNING("Unsupported channel order.");
+ return 0;
+ }
+ mask |= position;
+ }
+ return mask;
+}
+
static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info)
{
format->major_type = WG_MAJOR_TYPE_AUDIO;
format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info));
format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info);
+ format->u.audio.channel_mask = wg_channel_mask_from_gst(info);
format->u.audio.rate = GST_AUDIO_INFO_RATE(info);
}
@@ -273,15 +332,63 @@ static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format)
}
}
+static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t mask, uint32_t channel_count)
+{
+ const uint32_t orig_mask = mask;
+ unsigned int i;
+ DWORD bit;
+
+ static const GstAudioChannelPosition position_map[] =
+ {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE1,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_TOP_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT,
+ };
+
+ for (i = 0; i < channel_count; ++i)
+ {
+ positions[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+ if (BitScanForward(&bit, mask))
+ {
+ if (bit < ARRAY_SIZE(position_map))
+ positions[i] = position_map[bit];
+ else
+ GST_WARNING("Invalid channel mask %#x.\n", orig_mask);
+ mask &= ~(1 << bit);
+ }
+ else
+ {
+ GST_WARNING("Incomplete channel mask %#x.\n", orig_mask);
+ }
+ }
+}
+
static GstCaps *wg_format_to_caps_audio(const struct wg_format *format)
{
+ GstAudioChannelPosition positions[32];
GstAudioFormat audio_format;
GstAudioInfo info;
if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN)
return NULL;
- gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, NULL);
+ wg_channel_mask_to_gst(positions, format->u.audio.channel_mask, format->u.audio.channels);
+ gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, positions);
return gst_audio_info_to_caps(&info);
}
More information about the wine-cvs
mailing list