[PATCH v2 2/4] winegstreamer: Move format helpers to a dedicated source.
Rémi Bernon
rbernon at codeweavers.com
Mon Feb 14 04:19:45 CST 2022
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/winegstreamer/Makefile.in | 1 +
dlls/winegstreamer/unix_private.h | 6 +
dlls/winegstreamer/wg_format.c | 436 ++++++++++++++++++++++++++++++
dlls/winegstreamer/wg_parser.c | 393 ---------------------------
4 files changed, 443 insertions(+), 393 deletions(-)
create mode 100644 dlls/winegstreamer/wg_format.c
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in
index 52295418f0f..0bcdb3eec65 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 \
wg_transform.c \
wm_asyncreader.c \
diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h
index 375d33e7728..f9c4da2f6ea 100644
--- a/dlls/winegstreamer/unix_private.h
+++ b/dlls/winegstreamer/unix_private.h
@@ -23,8 +23,14 @@
#include "unixlib.h"
+#include <gst/gst.h>
+
extern bool init_gstreamer(void) DECLSPEC_HIDDEN;
+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;
+
extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN;
extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN;
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 ac8c5a2b95c..6828865eef6 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -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