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