2 * GStreamer format helpers
4 * Copyright 2010 Maarten Lankhorst for CodeWeavers
5 * Copyright 2010 Aric Stewart for CodeWeavers
6 * Copyright 2019-2020 Zebediah Figura
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include <gst/video/video.h>
35 #include <gst/audio/audio.h>
40 #include "unix_private.h"
42 GST_DEBUG_CATEGORY_EXTERN(wine
);
43 #define GST_CAT_DEFAULT wine
45 static enum wg_audio_format
wg_audio_format_from_gst(GstAudioFormat format
)
49 case GST_AUDIO_FORMAT_U8
:
50 return WG_AUDIO_FORMAT_U8
;
51 case GST_AUDIO_FORMAT_S16LE
:
52 return WG_AUDIO_FORMAT_S16LE
;
53 case GST_AUDIO_FORMAT_S24LE
:
54 return WG_AUDIO_FORMAT_S24LE
;
55 case GST_AUDIO_FORMAT_S32LE
:
56 return WG_AUDIO_FORMAT_S32LE
;
57 case GST_AUDIO_FORMAT_F32LE
:
58 return WG_AUDIO_FORMAT_F32LE
;
59 case GST_AUDIO_FORMAT_F64LE
:
60 return WG_AUDIO_FORMAT_F64LE
;
62 return WG_AUDIO_FORMAT_UNKNOWN
;
66 static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position
)
68 static const uint32_t position_map
[] =
73 SPEAKER_LOW_FREQUENCY
,
76 SPEAKER_FRONT_LEFT_OF_CENTER
,
77 SPEAKER_FRONT_RIGHT_OF_CENTER
,
82 SPEAKER_TOP_FRONT_LEFT
,
83 SPEAKER_TOP_FRONT_RIGHT
,
84 SPEAKER_TOP_FRONT_CENTER
,
86 SPEAKER_TOP_BACK_LEFT
,
87 SPEAKER_TOP_BACK_RIGHT
,
90 SPEAKER_TOP_BACK_CENTER
,
93 if (position
== GST_AUDIO_CHANNEL_POSITION_MONO
)
94 return SPEAKER_FRONT_CENTER
;
96 if (position
>= 0 && position
< ARRAY_SIZE(position_map
))
97 return position_map
[position
];
101 static uint32_t wg_channel_mask_from_gst(const GstAudioInfo
*info
)
103 uint32_t mask
= 0, position
;
106 for (i
= 0; i
< GST_AUDIO_INFO_CHANNELS(info
); ++i
)
108 if (!(position
= wg_channel_position_from_gst(GST_AUDIO_INFO_POSITION(info
, i
))))
110 GST_WARNING("Unsupported channel %#x.", GST_AUDIO_INFO_POSITION(info
, i
));
113 /* Make sure it's also in WinMM order. WinMM mandates that channels be
114 * ordered, as it were, from least to most significant SPEAKER_* bit.
115 * Hence we fail if the current channel was already specified, or if any
116 * higher bit was already specified. */
117 if (mask
& ~(position
- 1))
119 GST_WARNING("Unsupported channel order.");
127 static void wg_format_from_audio_info(struct wg_format
*format
, const GstAudioInfo
*info
)
129 format
->major_type
= WG_MAJOR_TYPE_AUDIO
;
130 format
->u
.audio
.format
= wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info
));
131 format
->u
.audio
.channels
= GST_AUDIO_INFO_CHANNELS(info
);
132 format
->u
.audio
.channel_mask
= wg_channel_mask_from_gst(info
);
133 format
->u
.audio
.rate
= GST_AUDIO_INFO_RATE(info
);
136 static enum wg_video_format
wg_video_format_from_gst(GstVideoFormat format
)
140 case GST_VIDEO_FORMAT_BGRA
:
141 return WG_VIDEO_FORMAT_BGRA
;
142 case GST_VIDEO_FORMAT_BGRx
:
143 return WG_VIDEO_FORMAT_BGRx
;
144 case GST_VIDEO_FORMAT_BGR
:
145 return WG_VIDEO_FORMAT_BGR
;
146 case GST_VIDEO_FORMAT_RGB15
:
147 return WG_VIDEO_FORMAT_RGB15
;
148 case GST_VIDEO_FORMAT_RGB16
:
149 return WG_VIDEO_FORMAT_RGB16
;
150 case GST_VIDEO_FORMAT_AYUV
:
151 return WG_VIDEO_FORMAT_AYUV
;
152 case GST_VIDEO_FORMAT_I420
:
153 return WG_VIDEO_FORMAT_I420
;
154 case GST_VIDEO_FORMAT_NV12
:
155 return WG_VIDEO_FORMAT_NV12
;
156 case GST_VIDEO_FORMAT_UYVY
:
157 return WG_VIDEO_FORMAT_UYVY
;
158 case GST_VIDEO_FORMAT_YUY2
:
159 return WG_VIDEO_FORMAT_YUY2
;
160 case GST_VIDEO_FORMAT_YV12
:
161 return WG_VIDEO_FORMAT_YV12
;
162 case GST_VIDEO_FORMAT_YVYU
:
163 return WG_VIDEO_FORMAT_YVYU
;
165 return WG_VIDEO_FORMAT_UNKNOWN
;
169 static void wg_format_from_video_info(struct wg_format
*format
, const GstVideoInfo
*info
)
171 format
->major_type
= WG_MAJOR_TYPE_VIDEO
;
172 format
->u
.video
.format
= wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info
));
173 format
->u
.video
.width
= GST_VIDEO_INFO_WIDTH(info
);
174 format
->u
.video
.height
= GST_VIDEO_INFO_HEIGHT(info
);
175 format
->u
.video
.fps_n
= GST_VIDEO_INFO_FPS_N(info
);
176 format
->u
.video
.fps_d
= GST_VIDEO_INFO_FPS_D(info
);
179 static void wg_format_from_caps_audio_mpeg(struct wg_format
*format
, const GstCaps
*caps
)
181 const GstStructure
*structure
= gst_caps_get_structure(caps
, 0);
182 gint layer
, channels
, rate
;
184 if (!gst_structure_get_int(structure
, "layer", &layer
))
186 GST_WARNING("Missing \"layer\" value.");
189 if (!gst_structure_get_int(structure
, "channels", &channels
))
191 GST_WARNING("Missing \"channels\" value.");
194 if (!gst_structure_get_int(structure
, "rate", &rate
))
196 GST_WARNING("Missing \"rate\" value.");
200 format
->major_type
= WG_MAJOR_TYPE_AUDIO
;
203 format
->u
.audio
.format
= WG_AUDIO_FORMAT_MPEG1_LAYER1
;
205 format
->u
.audio
.format
= WG_AUDIO_FORMAT_MPEG1_LAYER2
;
207 format
->u
.audio
.format
= WG_AUDIO_FORMAT_MPEG1_LAYER3
;
209 format
->u
.audio
.channels
= channels
;
210 format
->u
.audio
.rate
= rate
;
213 static void wg_format_from_caps_video_cinepak(struct wg_format
*format
, const GstCaps
*caps
)
215 const GstStructure
*structure
= gst_caps_get_structure(caps
, 0);
216 gint width
, height
, fps_n
, fps_d
;
218 if (!gst_structure_get_int(structure
, "width", &width
))
220 GST_WARNING("Missing \"width\" value.");
223 if (!gst_structure_get_int(structure
, "height", &height
))
225 GST_WARNING("Missing \"height\" value.");
228 if (!gst_structure_get_fraction(structure
, "framerate", &fps_n
, &fps_d
))
234 format
->major_type
= WG_MAJOR_TYPE_VIDEO
;
235 format
->u
.video
.format
= WG_VIDEO_FORMAT_CINEPAK
;
236 format
->u
.video
.width
= width
;
237 format
->u
.video
.height
= height
;
238 format
->u
.video
.fps_n
= fps_n
;
239 format
->u
.video
.fps_d
= fps_d
;
242 void wg_format_from_caps(struct wg_format
*format
, const GstCaps
*caps
)
244 const GstStructure
*structure
= gst_caps_get_structure(caps
, 0);
245 const char *name
= gst_structure_get_name(structure
);
247 memset(format
, 0, sizeof(*format
));
249 if (!strcmp(name
, "audio/x-raw"))
253 if (gst_audio_info_from_caps(&info
, caps
))
254 wg_format_from_audio_info(format
, &info
);
256 else if (!strcmp(name
, "video/x-raw"))
260 if (gst_video_info_from_caps(&info
, caps
))
261 wg_format_from_video_info(format
, &info
);
263 else if (!strcmp(name
, "audio/mpeg"))
265 wg_format_from_caps_audio_mpeg(format
, caps
);
267 else if (!strcmp(name
, "video/x-cinepak"))
269 wg_format_from_caps_video_cinepak(format
, caps
);
273 gchar
*str
= gst_caps_to_string(caps
);
275 GST_FIXME("Unhandled caps %s.", str
);
280 static GstAudioFormat
wg_audio_format_to_gst(enum wg_audio_format format
)
284 case WG_AUDIO_FORMAT_U8
: return GST_AUDIO_FORMAT_U8
;
285 case WG_AUDIO_FORMAT_S16LE
: return GST_AUDIO_FORMAT_S16LE
;
286 case WG_AUDIO_FORMAT_S24LE
: return GST_AUDIO_FORMAT_S24LE
;
287 case WG_AUDIO_FORMAT_S32LE
: return GST_AUDIO_FORMAT_S32LE
;
288 case WG_AUDIO_FORMAT_F32LE
: return GST_AUDIO_FORMAT_F32LE
;
289 case WG_AUDIO_FORMAT_F64LE
: return GST_AUDIO_FORMAT_F64LE
;
290 default: return GST_AUDIO_FORMAT_UNKNOWN
;
294 static void wg_channel_mask_to_gst(GstAudioChannelPosition
*positions
, uint32_t mask
, uint32_t channel_count
)
296 const uint32_t orig_mask
= mask
;
300 static const GstAudioChannelPosition position_map
[] =
302 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT
,
303 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT
,
304 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER
,
305 GST_AUDIO_CHANNEL_POSITION_LFE1
,
306 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT
,
307 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT
,
308 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
,
309 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
,
310 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER
,
311 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT
,
312 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
,
313 GST_AUDIO_CHANNEL_POSITION_TOP_CENTER
,
314 GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT
,
315 GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER
,
316 GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT
,
317 GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT
,
318 GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER
,
319 GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT
,
322 for (i
= 0; i
< channel_count
; ++i
)
324 positions
[i
] = GST_AUDIO_CHANNEL_POSITION_NONE
;
325 if (BitScanForward(&bit
, mask
))
327 if (bit
< ARRAY_SIZE(position_map
))
328 positions
[i
] = position_map
[bit
];
330 GST_WARNING("Invalid channel mask %#x.", orig_mask
);
335 GST_WARNING("Incomplete channel mask %#x.", orig_mask
);
340 static GstCaps
*wg_format_to_caps_audio(const struct wg_format
*format
)
342 GstAudioChannelPosition positions
[32];
343 GstAudioFormat audio_format
;
346 if ((audio_format
= wg_audio_format_to_gst(format
->u
.audio
.format
)) == GST_AUDIO_FORMAT_UNKNOWN
)
349 wg_channel_mask_to_gst(positions
, format
->u
.audio
.channel_mask
, format
->u
.audio
.channels
);
350 gst_audio_info_set_format(&info
, audio_format
, format
->u
.audio
.rate
, format
->u
.audio
.channels
, positions
);
351 return gst_audio_info_to_caps(&info
);
354 static GstVideoFormat
wg_video_format_to_gst(enum wg_video_format format
)
358 case WG_VIDEO_FORMAT_BGRA
: return GST_VIDEO_FORMAT_BGRA
;
359 case WG_VIDEO_FORMAT_BGRx
: return GST_VIDEO_FORMAT_BGRx
;
360 case WG_VIDEO_FORMAT_BGR
: return GST_VIDEO_FORMAT_BGR
;
361 case WG_VIDEO_FORMAT_RGB15
: return GST_VIDEO_FORMAT_RGB15
;
362 case WG_VIDEO_FORMAT_RGB16
: return GST_VIDEO_FORMAT_RGB16
;
363 case WG_VIDEO_FORMAT_AYUV
: return GST_VIDEO_FORMAT_AYUV
;
364 case WG_VIDEO_FORMAT_I420
: return GST_VIDEO_FORMAT_I420
;
365 case WG_VIDEO_FORMAT_NV12
: return GST_VIDEO_FORMAT_NV12
;
366 case WG_VIDEO_FORMAT_UYVY
: return GST_VIDEO_FORMAT_UYVY
;
367 case WG_VIDEO_FORMAT_YUY2
: return GST_VIDEO_FORMAT_YUY2
;
368 case WG_VIDEO_FORMAT_YV12
: return GST_VIDEO_FORMAT_YV12
;
369 case WG_VIDEO_FORMAT_YVYU
: return GST_VIDEO_FORMAT_YVYU
;
370 default: return GST_VIDEO_FORMAT_UNKNOWN
;
374 static GstCaps
*wg_format_to_caps_video(const struct wg_format
*format
)
376 GstVideoFormat video_format
;
381 if ((video_format
= wg_video_format_to_gst(format
->u
.video
.format
)) == GST_VIDEO_FORMAT_UNKNOWN
)
384 gst_video_info_set_format(&info
, video_format
, format
->u
.video
.width
, abs(format
->u
.video
.height
));
385 if ((caps
= gst_video_info_to_caps(&info
)))
387 /* Clear some fields that shouldn't prevent us from connecting. */
388 for (i
= 0; i
< gst_caps_get_size(caps
); ++i
)
390 gst_structure_remove_fields(gst_caps_get_structure(caps
, i
),
391 "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL
);
397 static GstCaps
*wg_format_to_caps_wma(const struct wg_format
*format
)
402 if (!(caps
= gst_caps_new_empty_simple("audio/x-wma")))
404 if (format
->u
.wma
.version
)
405 gst_caps_set_simple(caps
, "wmaversion", G_TYPE_INT
, format
->u
.wma
.version
, NULL
);
407 if (format
->u
.wma
.bitrate
)
408 gst_caps_set_simple(caps
, "bitrate", G_TYPE_INT
, format
->u
.wma
.bitrate
, NULL
);
409 if (format
->u
.wma
.rate
)
410 gst_caps_set_simple(caps
, "rate", G_TYPE_INT
, format
->u
.wma
.rate
, NULL
);
411 if (format
->u
.wma
.depth
)
412 gst_caps_set_simple(caps
, "depth", G_TYPE_INT
, format
->u
.wma
.depth
, NULL
);
413 if (format
->u
.wma
.channels
)
414 gst_caps_set_simple(caps
, "channels", G_TYPE_INT
, format
->u
.wma
.channels
, NULL
);
415 if (format
->u
.wma
.block_align
)
416 gst_caps_set_simple(caps
, "block_align", G_TYPE_INT
, format
->u
.wma
.block_align
, NULL
);
418 if (format
->u
.wma
.codec_data_len
)
420 if (!(buffer
= gst_buffer_new_and_alloc(format
->u
.wma
.codec_data_len
)))
422 gst_caps_unref(caps
);
426 gst_buffer_fill(buffer
, 0, format
->u
.wma
.codec_data
, format
->u
.wma
.codec_data_len
);
427 gst_caps_set_simple(caps
, "codec_data", GST_TYPE_BUFFER
, buffer
, NULL
);
428 gst_buffer_unref(buffer
);
434 GstCaps
*wg_format_to_caps(const struct wg_format
*format
)
436 switch (format
->major_type
)
438 case WG_MAJOR_TYPE_UNKNOWN
:
440 case WG_MAJOR_TYPE_WMA
:
441 return wg_format_to_caps_wma(format
);
442 case WG_MAJOR_TYPE_AUDIO
:
443 return wg_format_to_caps_audio(format
);
444 case WG_MAJOR_TYPE_VIDEO
:
445 return wg_format_to_caps_video(format
);
451 bool wg_format_compare(const struct wg_format
*a
, const struct wg_format
*b
)
453 if (a
->major_type
!= b
->major_type
)
456 switch (a
->major_type
)
458 case WG_MAJOR_TYPE_UNKNOWN
:
461 case WG_MAJOR_TYPE_WMA
:
462 GST_FIXME("WMA format not implemented!\n");
465 case WG_MAJOR_TYPE_AUDIO
:
466 return a
->u
.audio
.format
== b
->u
.audio
.format
467 && a
->u
.audio
.channels
== b
->u
.audio
.channels
468 && a
->u
.audio
.rate
== b
->u
.audio
.rate
;
470 case WG_MAJOR_TYPE_VIDEO
:
471 /* Do not compare FPS. */
472 return a
->u
.video
.format
== b
->u
.video
.format
473 && a
->u
.video
.width
== b
->u
.video
.width
474 && abs(a
->u
.video
.height
) == abs(b
->u
.video
.height
);