mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
codec-utils: Add utilities for Opus caps and the OpusHead header
https://bugzilla.gnome.org/show_bug.cgi?id=757152
This commit is contained in:
parent
0fa8d284c7
commit
bcd7b2fff2
5 changed files with 544 additions and 0 deletions
|
@ -2180,6 +2180,12 @@ gst_codec_utils_h265_caps_set_level_tier_and_profile
|
||||||
gst_codec_utils_mpeg4video_get_profile
|
gst_codec_utils_mpeg4video_get_profile
|
||||||
gst_codec_utils_mpeg4video_get_level
|
gst_codec_utils_mpeg4video_get_level
|
||||||
gst_codec_utils_mpeg4video_caps_set_level_and_profile
|
gst_codec_utils_mpeg4video_caps_set_level_and_profile
|
||||||
|
<SUBSECTION>
|
||||||
|
gst_codec_utils_opus_create_caps
|
||||||
|
gst_codec_utils_opus_create_caps_from_header
|
||||||
|
gst_codec_utils_opus_parse_caps
|
||||||
|
gst_codec_utils_opus_create_header
|
||||||
|
gst_codec_utils_opus_parse_header
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
|
|
@ -48,6 +48,7 @@ noinst_HEADERS = \
|
||||||
libgstpbutils_@GST_API_VERSION@_la_LIBADD = \
|
libgstpbutils_@GST_API_VERSION@_la_LIBADD = \
|
||||||
$(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_API_VERSION@.la \
|
$(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_API_VERSION@.la \
|
||||||
$(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_API_VERSION@.la \
|
$(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_API_VERSION@.la \
|
||||||
|
$(top_builddir)/gst-libs/gst/tag/libgsttag-@GST_API_VERSION@.la \
|
||||||
$(GST_LIBS)
|
$(GST_LIBS)
|
||||||
libgstpbutils_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
libgstpbutils_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
||||||
libgstpbutils_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
|
libgstpbutils_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* 2010 Collabora Multimedia
|
* 2010 Collabora Multimedia
|
||||||
* 2010 Nokia Corporation
|
* 2010 Nokia Corporation
|
||||||
* 2013 Intel Corporation
|
* 2013 Intel Corporation
|
||||||
|
* 2015 Sebastian Dröge <sebastian@centricular.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -38,6 +39,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "pbutils.h"
|
#include "pbutils.h"
|
||||||
|
#include <gst/base/base.h>
|
||||||
|
#include <gst/tag/tag.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -1100,3 +1103,495 @@ gst_codec_utils_mpeg4video_caps_set_level_and_profile (GstCaps * caps,
|
||||||
|
|
||||||
return (profile != NULL && level != NULL);
|
return (profile != NULL && level != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_codec_utils_opus_parse_caps:
|
||||||
|
* @caps: the #GstCaps to which the level and profile are to be added
|
||||||
|
* @rate: the sample rate
|
||||||
|
* @channels: the number of channels
|
||||||
|
* @channel_mapping_family: the channel mapping family
|
||||||
|
* @stream_count: the number of independent streams
|
||||||
|
* @coupled_count: the number of stereo streams
|
||||||
|
* @channel_mapping: the mapping between the streams
|
||||||
|
*
|
||||||
|
* Parses Opus caps and fills the different fields with defaults if possible.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if parsing was successful, %FALSE otherwise.
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_codec_utils_opus_parse_caps (GstCaps * caps,
|
||||||
|
guint32 * rate,
|
||||||
|
guint8 * channels,
|
||||||
|
guint8 * channel_mapping_family,
|
||||||
|
guint8 * stream_count, guint8 * coupled_count, guint8 channel_mapping[256])
|
||||||
|
{
|
||||||
|
GstStructure *s;
|
||||||
|
gint c, f, sc, cc;
|
||||||
|
const GValue *va, *v;
|
||||||
|
|
||||||
|
g_return_val_if_fail (caps != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
|
||||||
|
g_return_val_if_fail (!gst_caps_is_empty (caps), FALSE);
|
||||||
|
|
||||||
|
s = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
|
g_return_val_if_fail (gst_structure_has_name (s, "audio/x-opus"), FALSE);
|
||||||
|
g_return_val_if_fail (gst_structure_has_field_typed (s,
|
||||||
|
"channel-mapping-family", G_TYPE_INT), FALSE);
|
||||||
|
|
||||||
|
if (rate) {
|
||||||
|
gint r;
|
||||||
|
|
||||||
|
if (gst_structure_get_int (s, "rate", &r))
|
||||||
|
*rate = r;
|
||||||
|
else
|
||||||
|
*rate = 48000;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_structure_get_int (s, "channel-mapping-family", &f);
|
||||||
|
if (channel_mapping_family)
|
||||||
|
*channel_mapping_family = f;
|
||||||
|
|
||||||
|
if (!gst_structure_get_int (s, "channels", &c)) {
|
||||||
|
if (f == 0)
|
||||||
|
c = 2;
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channels)
|
||||||
|
*channels = c;
|
||||||
|
|
||||||
|
/* RTP mapping */
|
||||||
|
if (f == 0) {
|
||||||
|
if (c > 2)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (stream_count)
|
||||||
|
*stream_count = 1;
|
||||||
|
if (coupled_count)
|
||||||
|
*coupled_count = c == 2 ? 1 : 0;
|
||||||
|
|
||||||
|
if (channel_mapping) {
|
||||||
|
channel_mapping[0] = 0;
|
||||||
|
channel_mapping[1] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_structure_get_int (s, "stream-count", &sc))
|
||||||
|
return FALSE;
|
||||||
|
if (stream_count)
|
||||||
|
*stream_count = sc;
|
||||||
|
|
||||||
|
if (!gst_structure_get_int (s, "coupled-count", &cc))
|
||||||
|
return FALSE;
|
||||||
|
if (coupled_count)
|
||||||
|
*coupled_count = cc;
|
||||||
|
|
||||||
|
va = gst_structure_get_value (s, "channel-mapping");
|
||||||
|
if (!va || !G_VALUE_HOLDS (va, GST_TYPE_ARRAY))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (gst_value_array_get_size (va) != c)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (channel_mapping) {
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
for (i = 0; i < c; i++) {
|
||||||
|
gint cm;
|
||||||
|
|
||||||
|
v = gst_value_array_get_value (va, i);
|
||||||
|
|
||||||
|
if (!G_VALUE_HOLDS (v, G_TYPE_INT))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
cm = g_value_get_int (v);
|
||||||
|
if (cm < 0 || cm > 255)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
channel_mapping[i] = cm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_codec_utils_opus_create_caps:
|
||||||
|
* @rate: the sample rate
|
||||||
|
* @channels: the number of channels
|
||||||
|
* @channel_mapping_family: the channel mapping family
|
||||||
|
* @stream_count: the number of independent streams
|
||||||
|
* @coupled_count: the number of stereo streams
|
||||||
|
* @channel_mapping: (allow-none): the mapping between the streams
|
||||||
|
*
|
||||||
|
* Creates Opus caps from the given parameters.
|
||||||
|
*
|
||||||
|
* Returns: The #GstCaps.
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
GstCaps *
|
||||||
|
gst_codec_utils_opus_create_caps (guint32 rate,
|
||||||
|
guint8 channels,
|
||||||
|
guint8 channel_mapping_family,
|
||||||
|
guint8 stream_count, guint8 coupled_count, const guint8 * channel_mapping)
|
||||||
|
{
|
||||||
|
GstCaps *caps;
|
||||||
|
GValue va = G_VALUE_INIT;
|
||||||
|
GValue v = G_VALUE_INIT;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
if (rate == 0)
|
||||||
|
rate = 48000;
|
||||||
|
|
||||||
|
if (channel_mapping_family == 0) {
|
||||||
|
g_return_val_if_fail (channels <= 2, NULL);
|
||||||
|
if (channels == 0)
|
||||||
|
channels = 2;
|
||||||
|
|
||||||
|
g_return_val_if_fail (stream_count == 0 || stream_count == 1, NULL);
|
||||||
|
if (stream_count == 0)
|
||||||
|
stream_count = 1;
|
||||||
|
|
||||||
|
g_return_val_if_fail (coupled_count == 0 || coupled_count == 1, NULL);
|
||||||
|
if (coupled_count == 0)
|
||||||
|
coupled_count = channels == 2 ? 1 : 0;
|
||||||
|
|
||||||
|
return gst_caps_new_simple ("audio/x-opus",
|
||||||
|
"rate", G_TYPE_INT, rate,
|
||||||
|
"channels", G_TYPE_INT, channels,
|
||||||
|
"channel-mapping-family", G_TYPE_INT, channel_mapping_family,
|
||||||
|
"stream-count", G_TYPE_INT, stream_count,
|
||||||
|
"coupled-count", G_TYPE_INT, coupled_count, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_return_val_if_fail (channels > 0 && channels < 256, NULL);
|
||||||
|
g_return_val_if_fail (stream_count > 0, NULL);
|
||||||
|
g_return_val_if_fail (coupled_count <= stream_count, NULL);
|
||||||
|
g_return_val_if_fail (channel_mapping != NULL, NULL);
|
||||||
|
|
||||||
|
caps = gst_caps_new_simple ("audio/x-opus",
|
||||||
|
"rate", G_TYPE_INT, rate,
|
||||||
|
"channels", G_TYPE_INT, channels,
|
||||||
|
"channel-mapping-family", G_TYPE_INT, channel_mapping_family,
|
||||||
|
"stream-count", G_TYPE_INT, stream_count,
|
||||||
|
"coupled-count", G_TYPE_INT, coupled_count, NULL);
|
||||||
|
|
||||||
|
g_value_init (&va, GST_TYPE_ARRAY);
|
||||||
|
g_value_init (&v, G_TYPE_INT);
|
||||||
|
for (i = 0; i < channels; i++) {
|
||||||
|
g_value_set_int (&v, channel_mapping[i]);
|
||||||
|
gst_value_array_append_value (&va, &v);
|
||||||
|
}
|
||||||
|
gst_structure_set_value (gst_caps_get_structure (caps, 0), "channel-mapping",
|
||||||
|
&va);
|
||||||
|
g_value_unset (&va);
|
||||||
|
g_value_unset (&v);
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (really really) FIXME: move into core (dixit tpm)
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* _gst_caps_set_buffer_array:
|
||||||
|
* @caps: (transfer full): a #GstCaps
|
||||||
|
* @field: field in caps to set
|
||||||
|
* @buf: header buffers
|
||||||
|
*
|
||||||
|
* Adds given buffers to an array of buffers set as the given @field
|
||||||
|
* on the given @caps. List of buffer arguments must be NULL-terminated.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): input caps with a streamheader field added, or NULL
|
||||||
|
* if some error occurred
|
||||||
|
*/
|
||||||
|
static GstCaps *
|
||||||
|
_gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
|
||||||
|
GstBuffer * buf, ...)
|
||||||
|
{
|
||||||
|
GstStructure *structure = NULL;
|
||||||
|
va_list va;
|
||||||
|
GValue array = { 0 };
|
||||||
|
GValue value = { 0 };
|
||||||
|
|
||||||
|
g_return_val_if_fail (caps != NULL, NULL);
|
||||||
|
g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
|
||||||
|
g_return_val_if_fail (field != NULL, NULL);
|
||||||
|
|
||||||
|
caps = gst_caps_make_writable (caps);
|
||||||
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
|
|
||||||
|
g_value_init (&array, GST_TYPE_ARRAY);
|
||||||
|
|
||||||
|
va_start (va, buf);
|
||||||
|
/* put buffers in a fixed list */
|
||||||
|
while (buf) {
|
||||||
|
g_assert (gst_buffer_is_writable (buf));
|
||||||
|
|
||||||
|
/* mark buffer */
|
||||||
|
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
|
||||||
|
|
||||||
|
g_value_init (&value, GST_TYPE_BUFFER);
|
||||||
|
buf = gst_buffer_copy (buf);
|
||||||
|
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
|
||||||
|
gst_value_set_buffer (&value, buf);
|
||||||
|
gst_buffer_unref (buf);
|
||||||
|
gst_value_array_append_value (&array, &value);
|
||||||
|
g_value_unset (&value);
|
||||||
|
|
||||||
|
buf = va_arg (va, GstBuffer *);
|
||||||
|
}
|
||||||
|
va_end (va);
|
||||||
|
|
||||||
|
gst_structure_set_value (structure, field, &array);
|
||||||
|
g_value_unset (&array);
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_codec_utils_opus_create_caps_from_header:
|
||||||
|
* @header: OpusHead header
|
||||||
|
* @comments: (allow-none): Comment header or NULL
|
||||||
|
*
|
||||||
|
* Creates Opus caps from the given OpusHead @header and comment header
|
||||||
|
* @comments.
|
||||||
|
*
|
||||||
|
* Returns: The #GstCaps.
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
GstCaps *
|
||||||
|
gst_codec_utils_opus_create_caps_from_header (GstBuffer * header,
|
||||||
|
GstBuffer * comments)
|
||||||
|
{
|
||||||
|
GstCaps *caps;
|
||||||
|
guint32 rate;
|
||||||
|
guint8 channels;
|
||||||
|
guint8 channel_mapping_family;
|
||||||
|
guint8 stream_count;
|
||||||
|
guint8 coupled_count;
|
||||||
|
guint8 channel_mapping[256];
|
||||||
|
GstBuffer *dummy_comments = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER (header), NULL);
|
||||||
|
g_return_val_if_fail (comments == NULL || GST_IS_BUFFER (comments), NULL);
|
||||||
|
|
||||||
|
if (!gst_codec_utils_opus_parse_header (header, &rate, &channels,
|
||||||
|
&channel_mapping_family, &stream_count, &coupled_count,
|
||||||
|
channel_mapping, NULL, NULL))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
caps =
|
||||||
|
gst_codec_utils_opus_create_caps (rate, channels, channel_mapping_family,
|
||||||
|
stream_count, coupled_count, channel_mapping);
|
||||||
|
|
||||||
|
if (!comments) {
|
||||||
|
GstTagList *tags = gst_tag_list_new_empty ();
|
||||||
|
dummy_comments =
|
||||||
|
gst_tag_list_to_vorbiscomment_buffer (tags, (const guint8 *) "OpusTags",
|
||||||
|
8, NULL);
|
||||||
|
gst_tag_list_unref (tags);
|
||||||
|
}
|
||||||
|
_gst_caps_set_buffer_array (caps, "streamheader", header,
|
||||||
|
comments ? comments : dummy_comments, NULL);
|
||||||
|
|
||||||
|
if (dummy_comments)
|
||||||
|
gst_buffer_unref (dummy_comments);
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_codec_utils_opus_create_header:
|
||||||
|
* @rate: the sample rate
|
||||||
|
* @channels: the number of channels
|
||||||
|
* @channel_mapping_family: the channel mapping family
|
||||||
|
* @stream_count: the number of independent streams
|
||||||
|
* @coupled_count: the number of stereo streams
|
||||||
|
* @channel_mapping: (allow-none): the mapping between the streams
|
||||||
|
* @pre_skip: Pre-skip in 48kHz samples or 0
|
||||||
|
* @output_gain: Output gain or 0
|
||||||
|
*
|
||||||
|
* Creates OpusHead header from the given parameters.
|
||||||
|
*
|
||||||
|
* Returns: The #GstBuffer containing the OpusHead.
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
GstBuffer *
|
||||||
|
gst_codec_utils_opus_create_header (guint32 rate,
|
||||||
|
guint8 channels,
|
||||||
|
guint8 channel_mapping_family,
|
||||||
|
guint8 stream_count,
|
||||||
|
guint8 coupled_count,
|
||||||
|
const guint8 * channel_mapping, guint16 pre_skip, gint16 output_gain)
|
||||||
|
{
|
||||||
|
GstBuffer *buffer;
|
||||||
|
GstByteWriter bw;
|
||||||
|
gboolean hdl = TRUE;
|
||||||
|
|
||||||
|
if (rate == 0)
|
||||||
|
rate = 48000;
|
||||||
|
|
||||||
|
if (channel_mapping_family == 0) {
|
||||||
|
g_return_val_if_fail (channels <= 2, NULL);
|
||||||
|
if (channels == 0)
|
||||||
|
channels = 2;
|
||||||
|
|
||||||
|
g_return_val_if_fail (stream_count == 0 || stream_count == 1, NULL);
|
||||||
|
if (stream_count == 0)
|
||||||
|
stream_count = 1;
|
||||||
|
|
||||||
|
g_return_val_if_fail (coupled_count == 0 || coupled_count == 1, NULL);
|
||||||
|
if (coupled_count == 0)
|
||||||
|
coupled_count = channels == 2 ? 1 : 0;
|
||||||
|
|
||||||
|
channel_mapping = NULL;
|
||||||
|
} else {
|
||||||
|
g_return_val_if_fail (channels > 0 && channels < 256, NULL);
|
||||||
|
g_return_val_if_fail (stream_count > 0, NULL);
|
||||||
|
g_return_val_if_fail (coupled_count <= stream_count, NULL);
|
||||||
|
g_return_val_if_fail (channel_mapping != NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_byte_writer_init (&bw);
|
||||||
|
/* See http://wiki.xiph.org/OggOpus */
|
||||||
|
hdl &= gst_byte_writer_put_data (&bw, (const guint8 *) "OpusHead", 8);
|
||||||
|
hdl &= gst_byte_writer_put_uint8 (&bw, 0x01); /* version number */
|
||||||
|
hdl &= gst_byte_writer_put_uint8 (&bw, channels);
|
||||||
|
hdl &= gst_byte_writer_put_uint16_le (&bw, pre_skip);
|
||||||
|
hdl &= gst_byte_writer_put_uint32_le (&bw, rate);
|
||||||
|
hdl &= gst_byte_writer_put_uint16_le (&bw, output_gain);
|
||||||
|
hdl &= gst_byte_writer_put_uint8 (&bw, channel_mapping_family);
|
||||||
|
if (channel_mapping_family > 0) {
|
||||||
|
hdl &= gst_byte_writer_put_uint8 (&bw, stream_count);
|
||||||
|
hdl &= gst_byte_writer_put_uint8 (&bw, coupled_count);
|
||||||
|
hdl &= gst_byte_writer_put_data (&bw, channel_mapping, channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hdl) {
|
||||||
|
GST_WARNING ("Error creating header");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = gst_byte_writer_reset_and_get_buffer (&bw);
|
||||||
|
GST_BUFFER_OFFSET (buffer) = 0;
|
||||||
|
GST_BUFFER_OFFSET_END (buffer) = 0;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_codec_utils_opus_parse_header:
|
||||||
|
* @header: the OpusHead #GstBuffer
|
||||||
|
* @rate: the sample rate
|
||||||
|
* @channels: the number of channels
|
||||||
|
* @channel_mapping_family: the channel mapping family
|
||||||
|
* @stream_count: the number of independent streams
|
||||||
|
* @coupled_count: the number of stereo streams
|
||||||
|
* @channel_mapping: the mapping between the streams
|
||||||
|
* @pre_skip: Pre-skip in 48kHz samples or 0
|
||||||
|
* @output_gain: Output gain or 0
|
||||||
|
*
|
||||||
|
* Parses the OpusHead header.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if parsing was successful, %FALSE otherwise.
|
||||||
|
*
|
||||||
|
* Since: 1.8
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_codec_utils_opus_parse_header (GstBuffer * header,
|
||||||
|
guint32 * rate,
|
||||||
|
guint8 * channels,
|
||||||
|
guint8 * channel_mapping_family,
|
||||||
|
guint8 * stream_count,
|
||||||
|
guint8 * coupled_count,
|
||||||
|
guint8 channel_mapping[256], guint16 * pre_skip, gint16 * output_gain)
|
||||||
|
{
|
||||||
|
GstByteReader br;
|
||||||
|
GstMapInfo map;
|
||||||
|
gboolean ret = TRUE;
|
||||||
|
guint8 c, f;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER (header), FALSE);
|
||||||
|
g_return_val_if_fail (gst_buffer_get_size (header) >= 19, FALSE);
|
||||||
|
|
||||||
|
if (!gst_buffer_map (header, &map, GST_MAP_READ))
|
||||||
|
return FALSE;
|
||||||
|
gst_byte_reader_init (&br, map.data, map.size);
|
||||||
|
/* See http://wiki.xiph.org/OggOpus */
|
||||||
|
if (memcmp (gst_byte_reader_get_data_unchecked (&br, 8), "OpusHead", 8) != 0) {
|
||||||
|
ret = FALSE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (gst_byte_reader_get_uint8_unchecked (&br) != 0x01) {
|
||||||
|
ret = FALSE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = gst_byte_reader_get_uint8_unchecked (&br);
|
||||||
|
if (channels)
|
||||||
|
*channels = c;
|
||||||
|
|
||||||
|
if (pre_skip)
|
||||||
|
*pre_skip = gst_byte_reader_get_uint16_le_unchecked (&br);
|
||||||
|
else
|
||||||
|
gst_byte_reader_skip_unchecked (&br, 2);
|
||||||
|
|
||||||
|
if (rate)
|
||||||
|
*rate = gst_byte_reader_get_uint32_le_unchecked (&br);
|
||||||
|
else
|
||||||
|
gst_byte_reader_skip_unchecked (&br, 4);
|
||||||
|
|
||||||
|
if (output_gain)
|
||||||
|
*output_gain = gst_byte_reader_get_uint16_le_unchecked (&br);
|
||||||
|
else
|
||||||
|
gst_byte_reader_skip_unchecked (&br, 2);
|
||||||
|
|
||||||
|
f = gst_byte_reader_get_uint8_unchecked (&br);
|
||||||
|
if (channel_mapping_family)
|
||||||
|
*channel_mapping_family = f;
|
||||||
|
if (f == 0 && c <= 2) {
|
||||||
|
if (stream_count)
|
||||||
|
*stream_count = 1;
|
||||||
|
if (coupled_count)
|
||||||
|
*coupled_count = c == 2 ? 1 : 0;
|
||||||
|
if (channel_mapping) {
|
||||||
|
channel_mapping[0] = 0;
|
||||||
|
channel_mapping[1] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gst_byte_reader_get_remaining (&br) < 2 + c) {
|
||||||
|
ret = FALSE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream_count)
|
||||||
|
*stream_count = gst_byte_reader_get_uint8_unchecked (&br);
|
||||||
|
else
|
||||||
|
gst_byte_reader_skip_unchecked (&br, 1);
|
||||||
|
|
||||||
|
if (coupled_count)
|
||||||
|
*coupled_count = gst_byte_reader_get_uint8_unchecked (&br);
|
||||||
|
else
|
||||||
|
gst_byte_reader_skip_unchecked (&br, 1);
|
||||||
|
|
||||||
|
if (channel_mapping)
|
||||||
|
memcpy (channel_mapping, gst_byte_reader_get_data_unchecked (&br, c), c);
|
||||||
|
|
||||||
|
done:
|
||||||
|
gst_buffer_unmap (header, &map);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -77,6 +77,43 @@ gboolean gst_codec_utils_mpeg4video_caps_set_level_and_profile (GstCaps
|
||||||
const guint8 * vis_obj_seq,
|
const guint8 * vis_obj_seq,
|
||||||
guint len);
|
guint len);
|
||||||
|
|
||||||
|
/* Opus */
|
||||||
|
gboolean gst_codec_utils_opus_parse_caps (GstCaps * caps,
|
||||||
|
guint32 * rate,
|
||||||
|
guint8 * channels,
|
||||||
|
guint8 * channel_mapping_family,
|
||||||
|
guint8 * stream_count,
|
||||||
|
guint8 * coupled_count,
|
||||||
|
guint8 channel_mapping[256]);
|
||||||
|
|
||||||
|
GstCaps * gst_codec_utils_opus_create_caps (guint32 rate,
|
||||||
|
guint8 channels,
|
||||||
|
guint8 channel_mapping_family,
|
||||||
|
guint8 stream_count,
|
||||||
|
guint8 coupled_count,
|
||||||
|
const guint8 * channel_mapping);
|
||||||
|
|
||||||
|
GstCaps * gst_codec_utils_opus_create_caps_from_header (GstBuffer * header, GstBuffer * comments);
|
||||||
|
|
||||||
|
GstBuffer * gst_codec_utils_opus_create_header (guint32 rate,
|
||||||
|
guint8 channels,
|
||||||
|
guint8 channel_mapping_family,
|
||||||
|
guint8 stream_count,
|
||||||
|
guint8 coupled_count,
|
||||||
|
const guint8 * channel_mapping,
|
||||||
|
guint16 pre_skip,
|
||||||
|
gint16 output_gain);
|
||||||
|
|
||||||
|
gboolean gst_codec_utils_opus_parse_header (GstBuffer * header,
|
||||||
|
guint32 * rate,
|
||||||
|
guint8 * channels,
|
||||||
|
guint8 * channel_mapping_family,
|
||||||
|
guint8 * stream_count,
|
||||||
|
guint8 * coupled_count,
|
||||||
|
guint8 channel_mapping[256],
|
||||||
|
guint16 * pre_skip,
|
||||||
|
gint16 * output_gain);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_PB_UTILS_CODEC_UTILS_H__ */
|
#endif /* __GST_PB_UTILS_CODEC_UTILS_H__ */
|
||||||
|
|
|
@ -18,6 +18,11 @@ EXPORTS
|
||||||
gst_codec_utils_mpeg4video_caps_set_level_and_profile
|
gst_codec_utils_mpeg4video_caps_set_level_and_profile
|
||||||
gst_codec_utils_mpeg4video_get_level
|
gst_codec_utils_mpeg4video_get_level
|
||||||
gst_codec_utils_mpeg4video_get_profile
|
gst_codec_utils_mpeg4video_get_profile
|
||||||
|
gst_codec_utils_opus_create_caps
|
||||||
|
gst_codec_utils_opus_create_caps_from_header
|
||||||
|
gst_codec_utils_opus_create_header
|
||||||
|
gst_codec_utils_opus_parse_caps
|
||||||
|
gst_codec_utils_opus_parse_header
|
||||||
gst_discoverer_audio_info_get_bitrate
|
gst_discoverer_audio_info_get_bitrate
|
||||||
gst_discoverer_audio_info_get_channels
|
gst_discoverer_audio_info_get_channels
|
||||||
gst_discoverer_audio_info_get_depth
|
gst_discoverer_audio_info_get_depth
|
||||||
|
|
Loading…
Reference in a new issue