[PATCH v3 2/5] winegstreamer: Move format helpers to a dedicated source.

Rémi Bernon rbernon at codeweavers.com
Wed Feb 16 05:19:06 CST 2022


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/winegstreamer/Makefile.in    |   1 +
 dlls/winegstreamer/unix_private.h |  32 +++
 dlls/winegstreamer/wg_format.c    | 436 ++++++++++++++++++++++++++++++
 dlls/winegstreamer/wg_parser.c    | 397 +--------------------------
 4 files changed, 471 insertions(+), 395 deletions(-)
 create mode 100644 dlls/winegstreamer/unix_private.h
 create mode 100644 dlls/winegstreamer/wg_format.c

diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in
index c53e914e246..d9805e3d797 100644
--- a/dlls/winegstreamer/Makefile.in
+++ b/dlls/winegstreamer/Makefile.in
@@ -12,6 +12,7 @@ C_SRCS = \
 	media_source.c \
 	mfplat.c \
 	quartz_parser.c \
+	wg_format.c \
 	wg_parser.c \
 	wm_asyncreader.c \
 	wm_reader.c \
diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h
new file mode 100644
index 00000000000..b483638403d
--- /dev/null
+++ b/dlls/winegstreamer/unix_private.h
@@ -0,0 +1,32 @@
+/*
+ * winegstreamer Unix library interface
+ *
+ * Copyright 2020-2021 Zebediah Figura for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_WINEGSTREAMER_UNIX_PRIVATE_H
+#define __WINE_WINEGSTREAMER_UNIX_PRIVATE_H
+
+#include "unixlib.h"
+
+#include <gst/gst.h>
+
+extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN;
+extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN;
+extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN;
+
+#endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c
new file mode 100644
index 00000000000..8952acc1c2e
--- /dev/null
+++ b/dlls/winegstreamer/wg_format.c
@@ -0,0 +1,436 @@
+/*
+ * GStreamer format helpers
+ *
+ * Copyright 2010 Maarten Lankhorst for CodeWeavers
+ * Copyright 2010 Aric Stewart for CodeWeavers
+ * Copyright 2019-2020 Zebediah Figura
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#if 0
+#pragma makedep unix
+#endif
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/audio/audio.h>
+
+#include "winternl.h"
+#include "dshow.h"
+
+#include "unix_private.h"
+
+GST_DEBUG_CATEGORY_EXTERN(wine);
+#define GST_CAT_DEFAULT wine
+
+static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format)
+{
+    switch (format)
+    {
+        case GST_AUDIO_FORMAT_U8:
+            return WG_AUDIO_FORMAT_U8;
+        case GST_AUDIO_FORMAT_S16LE:
+            return WG_AUDIO_FORMAT_S16LE;
+        case GST_AUDIO_FORMAT_S24LE:
+            return WG_AUDIO_FORMAT_S24LE;
+        case GST_AUDIO_FORMAT_S32LE:
+            return WG_AUDIO_FORMAT_S32LE;
+        case GST_AUDIO_FORMAT_F32LE:
+            return WG_AUDIO_FORMAT_F32LE;
+        case GST_AUDIO_FORMAT_F64LE:
+            return WG_AUDIO_FORMAT_F64LE;
+        default:
+            return WG_AUDIO_FORMAT_UNKNOWN;
+    }
+}
+
+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 == GST_AUDIO_CHANNEL_POSITION_MONO)
+        return SPEAKER_FRONT_CENTER;
+
+    if (position >= 0 && 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);
+}
+
+static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format)
+{
+    switch (format)
+    {
+        case GST_VIDEO_FORMAT_BGRA:
+            return WG_VIDEO_FORMAT_BGRA;
+        case GST_VIDEO_FORMAT_BGRx:
+            return WG_VIDEO_FORMAT_BGRx;
+        case GST_VIDEO_FORMAT_BGR:
+            return WG_VIDEO_FORMAT_BGR;
+        case GST_VIDEO_FORMAT_RGB15:
+            return WG_VIDEO_FORMAT_RGB15;
+        case GST_VIDEO_FORMAT_RGB16:
+            return WG_VIDEO_FORMAT_RGB16;
+        case GST_VIDEO_FORMAT_AYUV:
+            return WG_VIDEO_FORMAT_AYUV;
+        case GST_VIDEO_FORMAT_I420:
+            return WG_VIDEO_FORMAT_I420;
+        case GST_VIDEO_FORMAT_NV12:
+            return WG_VIDEO_FORMAT_NV12;
+        case GST_VIDEO_FORMAT_UYVY:
+            return WG_VIDEO_FORMAT_UYVY;
+        case GST_VIDEO_FORMAT_YUY2:
+            return WG_VIDEO_FORMAT_YUY2;
+        case GST_VIDEO_FORMAT_YV12:
+            return WG_VIDEO_FORMAT_YV12;
+        case GST_VIDEO_FORMAT_YVYU:
+            return WG_VIDEO_FORMAT_YVYU;
+        default:
+            return WG_VIDEO_FORMAT_UNKNOWN;
+    }
+}
+
+static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info)
+{
+    format->major_type = WG_MAJOR_TYPE_VIDEO;
+    format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info));
+    format->u.video.width = GST_VIDEO_INFO_WIDTH(info);
+    format->u.video.height = GST_VIDEO_INFO_HEIGHT(info);
+    format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info);
+    format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info);
+}
+
+static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps)
+{
+    const GstStructure *structure = gst_caps_get_structure(caps, 0);
+    gint layer, channels, rate;
+
+    if (!gst_structure_get_int(structure, "layer", &layer))
+    {
+        GST_WARNING("Missing \"layer\" value.");
+        return;
+    }
+    if (!gst_structure_get_int(structure, "channels", &channels))
+    {
+        GST_WARNING("Missing \"channels\" value.");
+        return;
+    }
+    if (!gst_structure_get_int(structure, "rate", &rate))
+    {
+        GST_WARNING("Missing \"rate\" value.");
+        return;
+    }
+
+    format->major_type = WG_MAJOR_TYPE_AUDIO;
+
+    if (layer == 1)
+        format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1;
+    else if (layer == 2)
+        format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2;
+    else if (layer == 3)
+        format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3;
+
+    format->u.audio.channels = channels;
+    format->u.audio.rate = rate;
+}
+
+static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps)
+{
+    const GstStructure *structure = gst_caps_get_structure(caps, 0);
+    gint width, height, fps_n, fps_d;
+
+    if (!gst_structure_get_int(structure, "width", &width))
+    {
+        GST_WARNING("Missing \"width\" value.");
+        return;
+    }
+    if (!gst_structure_get_int(structure, "height", &height))
+    {
+        GST_WARNING("Missing \"height\" value.");
+        return;
+    }
+    if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d))
+    {
+        fps_n = 0;
+        fps_d = 1;
+    }
+
+    format->major_type = WG_MAJOR_TYPE_VIDEO;
+    format->u.video.format = WG_VIDEO_FORMAT_CINEPAK;
+    format->u.video.width = width;
+    format->u.video.height = height;
+    format->u.video.fps_n = fps_n;
+    format->u.video.fps_d = fps_d;
+}
+
+void wg_format_from_caps(struct wg_format *format, const GstCaps *caps)
+{
+    const GstStructure *structure = gst_caps_get_structure(caps, 0);
+    const char *name = gst_structure_get_name(structure);
+
+    memset(format, 0, sizeof(*format));
+
+    if (!strcmp(name, "audio/x-raw"))
+    {
+        GstAudioInfo info;
+
+        if (gst_audio_info_from_caps(&info, caps))
+            wg_format_from_audio_info(format, &info);
+    }
+    else if (!strcmp(name, "video/x-raw"))
+    {
+        GstVideoInfo info;
+
+        if (gst_video_info_from_caps(&info, caps))
+            wg_format_from_video_info(format, &info);
+    }
+    else if (!strcmp(name, "audio/mpeg"))
+    {
+        wg_format_from_caps_audio_mpeg(format, caps);
+    }
+    else if (!strcmp(name, "video/x-cinepak"))
+    {
+        wg_format_from_caps_video_cinepak(format, caps);
+    }
+    else
+    {
+        gchar *str = gst_caps_to_string(caps);
+
+        GST_FIXME("Unhandled caps %s.", str);
+        g_free(str);
+    }
+}
+
+static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format)
+{
+    switch (format)
+    {
+        case WG_AUDIO_FORMAT_U8:    return GST_AUDIO_FORMAT_U8;
+        case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE;
+        case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE;
+        case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE;
+        case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE;
+        case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE;
+        default: return GST_AUDIO_FORMAT_UNKNOWN;
+    }
+}
+
+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;
+
+    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);
+}
+
+static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format)
+{
+    switch (format)
+    {
+        case WG_VIDEO_FORMAT_BGRA:  return GST_VIDEO_FORMAT_BGRA;
+        case WG_VIDEO_FORMAT_BGRx:  return GST_VIDEO_FORMAT_BGRx;
+        case WG_VIDEO_FORMAT_BGR:   return GST_VIDEO_FORMAT_BGR;
+        case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15;
+        case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16;
+        case WG_VIDEO_FORMAT_AYUV:  return GST_VIDEO_FORMAT_AYUV;
+        case WG_VIDEO_FORMAT_I420:  return GST_VIDEO_FORMAT_I420;
+        case WG_VIDEO_FORMAT_NV12:  return GST_VIDEO_FORMAT_NV12;
+        case WG_VIDEO_FORMAT_UYVY:  return GST_VIDEO_FORMAT_UYVY;
+        case WG_VIDEO_FORMAT_YUY2:  return GST_VIDEO_FORMAT_YUY2;
+        case WG_VIDEO_FORMAT_YV12:  return GST_VIDEO_FORMAT_YV12;
+        case WG_VIDEO_FORMAT_YVYU:  return GST_VIDEO_FORMAT_YVYU;
+        default: return GST_VIDEO_FORMAT_UNKNOWN;
+    }
+}
+
+static GstCaps *wg_format_to_caps_video(const struct wg_format *format)
+{
+    GstVideoFormat video_format;
+    GstVideoInfo info;
+    unsigned int i;
+    GstCaps *caps;
+
+    if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN)
+        return NULL;
+
+    gst_video_info_set_format(&info, video_format, format->u.video.width, abs(format->u.video.height));
+    if ((caps = gst_video_info_to_caps(&info)))
+    {
+        /* Clear some fields that shouldn't prevent us from connecting. */
+        for (i = 0; i < gst_caps_get_size(caps); ++i)
+        {
+            gst_structure_remove_fields(gst_caps_get_structure(caps, i),
+                    "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL);
+        }
+    }
+    return caps;
+}
+
+GstCaps *wg_format_to_caps(const struct wg_format *format)
+{
+    switch (format->major_type)
+    {
+        case WG_MAJOR_TYPE_UNKNOWN:
+            return NULL;
+        case WG_MAJOR_TYPE_AUDIO:
+            return wg_format_to_caps_audio(format);
+        case WG_MAJOR_TYPE_VIDEO:
+            return wg_format_to_caps_video(format);
+    }
+    assert(0);
+    return NULL;
+}
+
+bool wg_format_compare(const struct wg_format *a, const struct wg_format *b)
+{
+    if (a->major_type != b->major_type)
+        return false;
+
+    switch (a->major_type)
+    {
+        case WG_MAJOR_TYPE_UNKNOWN:
+            return false;
+
+        case WG_MAJOR_TYPE_AUDIO:
+            return a->u.audio.format == b->u.audio.format
+                    && a->u.audio.channels == b->u.audio.channels
+                    && a->u.audio.rate == b->u.audio.rate;
+
+        case WG_MAJOR_TYPE_VIDEO:
+            /* Do not compare FPS. */
+            return a->u.video.format == b->u.video.format
+                    && a->u.video.width == b->u.video.width
+                    && abs(a->u.video.height) == abs(b->u.video.height);
+    }
+
+    assert(0);
+    return false;
+}
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index 013566b25e9..a73685a2e69 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -37,7 +37,7 @@
 #include "winternl.h"
 #include "dshow.h"
 
-#include "unixlib.h"
+#include "unix_private.h"
 
 typedef enum
 {
@@ -51,7 +51,7 @@ typedef enum
  * debug logging instead of Wine debug logging. In order to be safe we forbid
  * any use of Wine debug logging in this entire file. */
 
-GST_DEBUG_CATEGORY_STATIC(wine);
+GST_DEBUG_CATEGORY(wine);
 #define GST_CAT_DEFAULT wine
 
 typedef BOOL (*init_gst_cb)(struct wg_parser *parser);
@@ -111,399 +111,6 @@ struct wg_parser_stream
     uint64_t duration;
 };
 
-static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format)
-{
-    switch (format)
-    {
-        case GST_AUDIO_FORMAT_U8:
-            return WG_AUDIO_FORMAT_U8;
-        case GST_AUDIO_FORMAT_S16LE:
-            return WG_AUDIO_FORMAT_S16LE;
-        case GST_AUDIO_FORMAT_S24LE:
-            return WG_AUDIO_FORMAT_S24LE;
-        case GST_AUDIO_FORMAT_S32LE:
-            return WG_AUDIO_FORMAT_S32LE;
-        case GST_AUDIO_FORMAT_F32LE:
-            return WG_AUDIO_FORMAT_F32LE;
-        case GST_AUDIO_FORMAT_F64LE:
-            return WG_AUDIO_FORMAT_F64LE;
-        default:
-            return WG_AUDIO_FORMAT_UNKNOWN;
-    }
-}
-
-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 == GST_AUDIO_CHANNEL_POSITION_MONO)
-        return SPEAKER_FRONT_CENTER;
-
-    if (position >= 0 && 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);
-}
-
-static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format)
-{
-    switch (format)
-    {
-        case GST_VIDEO_FORMAT_BGRA:
-            return WG_VIDEO_FORMAT_BGRA;
-        case GST_VIDEO_FORMAT_BGRx:
-            return WG_VIDEO_FORMAT_BGRx;
-        case GST_VIDEO_FORMAT_BGR:
-            return WG_VIDEO_FORMAT_BGR;
-        case GST_VIDEO_FORMAT_RGB15:
-            return WG_VIDEO_FORMAT_RGB15;
-        case GST_VIDEO_FORMAT_RGB16:
-            return WG_VIDEO_FORMAT_RGB16;
-        case GST_VIDEO_FORMAT_AYUV:
-            return WG_VIDEO_FORMAT_AYUV;
-        case GST_VIDEO_FORMAT_I420:
-            return WG_VIDEO_FORMAT_I420;
-        case GST_VIDEO_FORMAT_NV12:
-            return WG_VIDEO_FORMAT_NV12;
-        case GST_VIDEO_FORMAT_UYVY:
-            return WG_VIDEO_FORMAT_UYVY;
-        case GST_VIDEO_FORMAT_YUY2:
-            return WG_VIDEO_FORMAT_YUY2;
-        case GST_VIDEO_FORMAT_YV12:
-            return WG_VIDEO_FORMAT_YV12;
-        case GST_VIDEO_FORMAT_YVYU:
-            return WG_VIDEO_FORMAT_YVYU;
-        default:
-            return WG_VIDEO_FORMAT_UNKNOWN;
-    }
-}
-
-static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info)
-{
-    format->major_type = WG_MAJOR_TYPE_VIDEO;
-    format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info));
-    format->u.video.width = GST_VIDEO_INFO_WIDTH(info);
-    format->u.video.height = GST_VIDEO_INFO_HEIGHT(info);
-    format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info);
-    format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info);
-}
-
-static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps)
-{
-    const GstStructure *structure = gst_caps_get_structure(caps, 0);
-    gint layer, channels, rate;
-
-    if (!gst_structure_get_int(structure, "layer", &layer))
-    {
-        GST_WARNING("Missing \"layer\" value.");
-        return;
-    }
-    if (!gst_structure_get_int(structure, "channels", &channels))
-    {
-        GST_WARNING("Missing \"channels\" value.");
-        return;
-    }
-    if (!gst_structure_get_int(structure, "rate", &rate))
-    {
-        GST_WARNING("Missing \"rate\" value.");
-        return;
-    }
-
-    format->major_type = WG_MAJOR_TYPE_AUDIO;
-
-    if (layer == 1)
-        format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1;
-    else if (layer == 2)
-        format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2;
-    else if (layer == 3)
-        format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3;
-
-    format->u.audio.channels = channels;
-    format->u.audio.rate = rate;
-}
-
-static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps)
-{
-    const GstStructure *structure = gst_caps_get_structure(caps, 0);
-    gint width, height, fps_n, fps_d;
-
-    if (!gst_structure_get_int(structure, "width", &width))
-    {
-        GST_WARNING("Missing \"width\" value.");
-        return;
-    }
-    if (!gst_structure_get_int(structure, "height", &height))
-    {
-        GST_WARNING("Missing \"height\" value.");
-        return;
-    }
-    if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d))
-    {
-        fps_n = 0;
-        fps_d = 1;
-    }
-
-    format->major_type = WG_MAJOR_TYPE_VIDEO;
-    format->u.video.format = WG_VIDEO_FORMAT_CINEPAK;
-    format->u.video.width = width;
-    format->u.video.height = height;
-    format->u.video.fps_n = fps_n;
-    format->u.video.fps_d = fps_d;
-}
-
-static void wg_format_from_caps(struct wg_format *format, const GstCaps *caps)
-{
-    const GstStructure *structure = gst_caps_get_structure(caps, 0);
-    const char *name = gst_structure_get_name(structure);
-
-    memset(format, 0, sizeof(*format));
-
-    if (!strcmp(name, "audio/x-raw"))
-    {
-        GstAudioInfo info;
-
-        if (gst_audio_info_from_caps(&info, caps))
-            wg_format_from_audio_info(format, &info);
-    }
-    else if (!strcmp(name, "video/x-raw"))
-    {
-        GstVideoInfo info;
-
-        if (gst_video_info_from_caps(&info, caps))
-            wg_format_from_video_info(format, &info);
-    }
-    else if (!strcmp(name, "audio/mpeg"))
-    {
-        wg_format_from_caps_audio_mpeg(format, caps);
-    }
-    else if (!strcmp(name, "video/x-cinepak"))
-    {
-        wg_format_from_caps_video_cinepak(format, caps);
-    }
-    else
-    {
-        gchar *str = gst_caps_to_string(caps);
-
-        GST_FIXME("Unhandled caps %s.", str);
-        g_free(str);
-    }
-}
-
-static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format)
-{
-    switch (format)
-    {
-        case WG_AUDIO_FORMAT_U8:    return GST_AUDIO_FORMAT_U8;
-        case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE;
-        case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE;
-        case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE;
-        case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE;
-        case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE;
-        default: return GST_AUDIO_FORMAT_UNKNOWN;
-    }
-}
-
-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;
-
-    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);
-}
-
-static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format)
-{
-    switch (format)
-    {
-        case WG_VIDEO_FORMAT_BGRA:  return GST_VIDEO_FORMAT_BGRA;
-        case WG_VIDEO_FORMAT_BGRx:  return GST_VIDEO_FORMAT_BGRx;
-        case WG_VIDEO_FORMAT_BGR:   return GST_VIDEO_FORMAT_BGR;
-        case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15;
-        case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16;
-        case WG_VIDEO_FORMAT_AYUV:  return GST_VIDEO_FORMAT_AYUV;
-        case WG_VIDEO_FORMAT_I420:  return GST_VIDEO_FORMAT_I420;
-        case WG_VIDEO_FORMAT_NV12:  return GST_VIDEO_FORMAT_NV12;
-        case WG_VIDEO_FORMAT_UYVY:  return GST_VIDEO_FORMAT_UYVY;
-        case WG_VIDEO_FORMAT_YUY2:  return GST_VIDEO_FORMAT_YUY2;
-        case WG_VIDEO_FORMAT_YV12:  return GST_VIDEO_FORMAT_YV12;
-        case WG_VIDEO_FORMAT_YVYU:  return GST_VIDEO_FORMAT_YVYU;
-        default: return GST_VIDEO_FORMAT_UNKNOWN;
-    }
-}
-
-static GstCaps *wg_format_to_caps_video(const struct wg_format *format)
-{
-    GstVideoFormat video_format;
-    GstVideoInfo info;
-    unsigned int i;
-    GstCaps *caps;
-
-    if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN)
-        return NULL;
-
-    gst_video_info_set_format(&info, video_format, format->u.video.width, abs(format->u.video.height));
-    if ((caps = gst_video_info_to_caps(&info)))
-    {
-        /* Clear some fields that shouldn't prevent us from connecting. */
-        for (i = 0; i < gst_caps_get_size(caps); ++i)
-        {
-            gst_structure_remove_fields(gst_caps_get_structure(caps, i),
-                    "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL);
-        }
-    }
-    return caps;
-}
-
-static GstCaps *wg_format_to_caps(const struct wg_format *format)
-{
-    switch (format->major_type)
-    {
-        case WG_MAJOR_TYPE_UNKNOWN:
-            return NULL;
-        case WG_MAJOR_TYPE_AUDIO:
-            return wg_format_to_caps_audio(format);
-        case WG_MAJOR_TYPE_VIDEO:
-            return wg_format_to_caps_video(format);
-    }
-    assert(0);
-    return NULL;
-}
-
-static bool wg_format_compare(const struct wg_format *a, const struct wg_format *b)
-{
-    if (a->major_type != b->major_type)
-        return false;
-
-    switch (a->major_type)
-    {
-        case WG_MAJOR_TYPE_UNKNOWN:
-            return false;
-
-        case WG_MAJOR_TYPE_AUDIO:
-            return a->u.audio.format == b->u.audio.format
-                    && a->u.audio.channels == b->u.audio.channels
-                    && a->u.audio.rate == b->u.audio.rate;
-
-        case WG_MAJOR_TYPE_VIDEO:
-            /* Do not compare FPS. */
-            return a->u.video.format == b->u.video.format
-                    && a->u.video.width == b->u.video.width
-                    && abs(a->u.video.height) == abs(b->u.video.height);
-    }
-
-    assert(0);
-    return false;
-}
-
 static NTSTATUS wg_parser_get_stream_count(void *args)
 {
     struct wg_parser_get_stream_count_params *params = args;
-- 
2.34.1




More information about the wine-devel mailing list