summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2015-11-03 14:50:53 +0200
committerSebastian Dröge <sebastian@centricular.com>2015-11-03 20:35:41 +0200
commit4ca84a9b1a0ee1643a698662680aab4cd0d46ef0 (patch)
tree7d8d3cb4dda9195865e543559b0a440281aaa131
parentfc475ce01a3c9d444c47cda15ceac2e93ca9621e (diff)
downloadgstreamer-plugins-base-4ca84a9b1a0ee1643a698662680aab4cd0d46ef0.tar.gz
opus: Add proper support for multichannel audio
https://bugzilla.gnome.org/show_bug.cgi?id=757152
-rw-r--r--ext/opus/Makefile.am1
-rw-r--r--ext/opus/gstopusdec.c133
-rw-r--r--ext/opus/gstopusdec.h6
-rw-r--r--ext/opus/gstopusenc.c196
-rw-r--r--ext/opus/gstopusheader.c212
-rw-r--r--ext/opus/gstopusheader.h6
6 files changed, 177 insertions, 377 deletions
diff --git a/ext/opus/Makefile.am b/ext/opus/Makefile.am
index d22c664e0..c64369252 100644
--- a/ext/opus/Makefile.am
+++ b/ext/opus/Makefile.am
@@ -10,6 +10,7 @@ libgstopus_la_CFLAGS = \
libgstopus_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
-lgsttag-$(GST_API_VERSION) -lgstrtp-$(GST_API_VERSION) \
+ -lgstpbutils-$(GST_API_VERSION) \
$(GST_BASE_LIBS) \
$(GST_LIBS) \
$(OPUS_LIBS)
diff --git a/ext/opus/gstopusdec.c b/ext/opus/gstopusdec.c
index 23649d2ab..8ca2809a3 100644
--- a/ext/opus/gstopusdec.c
+++ b/ext/opus/gstopusdec.c
@@ -47,6 +47,7 @@
#include "gstopusheader.h"
#include "gstopuscommon.h"
#include "gstopusdec.h"
+#include <gst/pbutils/pbutils.h>
GST_DEBUG_CATEGORY_STATIC (opusdec_debug);
#define GST_CAT_DEFAULT opusdec_debug
@@ -225,6 +226,8 @@ gst_opus_dec_negotiate (GstOpusDec * dec, const GstAudioChannelPosition * pos)
GstAudioInfo info;
if (caps) {
+ gint rate, channels;
+
caps = gst_caps_truncate (caps);
caps = gst_caps_make_writable (caps);
s = gst_caps_get_structure (caps, 0);
@@ -233,13 +236,15 @@ gst_opus_dec_negotiate (GstOpusDec * dec, const GstAudioChannelPosition * pos)
gst_structure_fixate_field_nearest_int (s, "rate", dec->sample_rate);
else
gst_structure_set (s, "rate", G_TYPE_INT, dec->sample_rate, NULL);
- gst_structure_get_int (s, "rate", &dec->sample_rate);
+ gst_structure_get_int (s, "rate", &rate);
+ dec->sample_rate = rate;
if (gst_structure_has_field (s, "channels"))
gst_structure_fixate_field_nearest_int (s, "channels", dec->n_channels);
else
gst_structure_set (s, "channels", G_TYPE_INT, dec->n_channels, NULL);
- gst_structure_get_int (s, "channels", &dec->n_channels);
+ gst_structure_get_int (s, "channels", &channels);
+ dec->n_channels = channels;
gst_caps_unref (caps);
}
@@ -273,7 +278,6 @@ gst_opus_dec_negotiate (GstOpusDec * dec, const GstAudioChannelPosition * pos)
/* but we still need the opus order for later reordering */
if (pos) {
memcpy (dec->opus_pos, pos, sizeof (pos[0]) * dec->n_channels);
- gst_audio_channel_positions_to_valid_order (dec->opus_pos, dec->n_channels);
} else {
dec->opus_pos[0] = GST_AUDIO_CHANNEL_POSITION_INVALID;
}
@@ -284,79 +288,64 @@ gst_opus_dec_negotiate (GstOpusDec * dec, const GstAudioChannelPosition * pos)
static GstFlowReturn
gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf)
{
- const guint8 *data;
GstAudioChannelPosition pos[64];
const GstAudioChannelPosition *posn = NULL;
- GstMapInfo map;
if (!gst_opus_header_is_id_header (buf)) {
GST_ERROR_OBJECT (dec, "Header is not an Opus ID header");
return GST_FLOW_ERROR;
}
- gst_buffer_map (buf, &map, GST_MAP_READ);
- data = map.data;
-
- dec->n_channels = data[9];
- dec->sample_rate = GST_READ_UINT32_LE (data + 12);
- if (dec->sample_rate == 0)
- dec->sample_rate = 48000;
- dec->pre_skip = GST_READ_UINT16_LE (data + 10);
- dec->r128_gain = GST_READ_UINT16_LE (data + 16);
+ if (!gst_codec_utils_opus_parse_header (buf,
+ &dec->sample_rate,
+ &dec->n_channels,
+ &dec->channel_mapping_family,
+ &dec->n_streams,
+ &dec->n_stereo_streams,
+ dec->channel_mapping, &dec->pre_skip, &dec->r128_gain)) {
+ GST_ERROR_OBJECT (dec, "Failed to parse Opus ID header");
+ return GST_FLOW_ERROR;
+ }
dec->r128_gain_volume = gst_opus_dec_get_r128_volume (dec->r128_gain);
+
GST_INFO_OBJECT (dec,
"Found pre-skip of %u samples, R128 gain %d (volume %f)",
dec->pre_skip, dec->r128_gain, dec->r128_gain_volume);
- dec->channel_mapping_family = data[18];
- if (dec->channel_mapping_family == 0) {
- /* implicit mapping */
- GST_INFO_OBJECT (dec, "Channel mapping family 0, implicit mapping");
- dec->n_streams = dec->n_stereo_streams = 1;
- dec->channel_mapping[0] = 0;
- dec->channel_mapping[1] = 1;
- } else {
- dec->n_streams = data[19];
- dec->n_stereo_streams = data[20];
- memcpy (dec->channel_mapping, data + 21, dec->n_channels);
-
- if (dec->channel_mapping_family == 1) {
- GST_INFO_OBJECT (dec, "Channel mapping family 1, Vorbis mapping");
- switch (dec->n_channels) {
- case 1:
- case 2:
- /* nothing */
- break;
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- posn = gst_opus_channel_positions[dec->n_channels - 1];
- break;
- default:{
- gint i;
-
- GST_ELEMENT_WARNING (GST_ELEMENT (dec), STREAM, DECODE,
- (NULL), ("Using NONE channel layout for more than 8 channels"));
-
- for (i = 0; i < dec->n_channels; i++)
- pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
-
- posn = pos;
- }
+ if (dec->channel_mapping_family == 1) {
+ GST_INFO_OBJECT (dec, "Channel mapping family 1, Vorbis mapping");
+ switch (dec->n_channels) {
+ case 1:
+ case 2:
+ /* nothing */
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ posn = gst_opus_channel_positions[dec->n_channels - 1];
+ break;
+ default:{
+ gint i;
+
+ GST_ELEMENT_WARNING (GST_ELEMENT (dec), STREAM, DECODE,
+ (NULL), ("Using NONE channel layout for more than 8 channels"));
+
+ for (i = 0; i < dec->n_channels; i++)
+ pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+
+ posn = pos;
}
- } else {
- GST_INFO_OBJECT (dec, "Channel mapping family %d",
- dec->channel_mapping_family);
}
+ } else {
+ GST_INFO_OBJECT (dec, "Channel mapping family %d",
+ dec->channel_mapping_family);
}
gst_opus_dec_negotiate (dec, posn);
- gst_buffer_unmap (buf, &map);
-
return GST_FLOW_OK;
}
@@ -660,8 +649,10 @@ gst_opus_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
if (header && G_VALUE_HOLDS (header, GST_TYPE_BUFFER)) {
buf = gst_value_get_buffer (header);
res = gst_opus_dec_parse_header (dec, buf);
- if (res != GST_FLOW_OK)
+ if (res != GST_FLOW_OK) {
+ ret = FALSE;
goto done;
+ }
gst_buffer_replace (&dec->streamheader, buf);
}
@@ -669,26 +660,26 @@ gst_opus_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
if (vorbiscomment && G_VALUE_HOLDS (vorbiscomment, GST_TYPE_BUFFER)) {
buf = gst_value_get_buffer (vorbiscomment);
res = gst_opus_dec_parse_comments (dec, buf);
- if (res != GST_FLOW_OK)
+ if (res != GST_FLOW_OK) {
+ ret = FALSE;
goto done;
+ }
gst_buffer_replace (&dec->vorbiscomment, buf);
}
} else {
- /* defaults if not in the caps */
- dec->n_channels = 2;
- dec->sample_rate = 48000;
+ const GstAudioChannelPosition *posn = NULL;
- gst_structure_get_int (s, "channels", &dec->n_channels);
- gst_structure_get_int (s, "rate", &dec->sample_rate);
+ if (!gst_codec_utils_opus_parse_caps (caps, &dec->sample_rate,
+ &dec->n_channels, &dec->channel_mapping_family, &dec->n_streams,
+ &dec->n_stereo_streams, dec->channel_mapping)) {
+ ret = FALSE;
+ goto done;
+ }
- /* default stereo mapping */
- dec->channel_mapping_family = 0;
- dec->channel_mapping[0] = 0;
- dec->channel_mapping[1] = 1;
- dec->n_streams = 1;
- dec->n_stereo_streams = 1;
+ if (dec->channel_mapping_family == 1 && dec->n_channels <= 8)
+ posn = gst_opus_channel_positions[dec->n_channels - 1];
- gst_opus_dec_negotiate (dec, NULL);
+ gst_opus_dec_negotiate (dec, posn);
}
done:
diff --git a/ext/opus/gstopusdec.h b/ext/opus/gstopusdec.h
index f8d43a926..df52cfb6f 100644
--- a/ext/opus/gstopusdec.h
+++ b/ext/opus/gstopusdec.h
@@ -52,9 +52,9 @@ struct _GstOpusDec {
GstBuffer *streamheader;
GstBuffer *vorbiscomment;
- int sample_rate;
- int n_channels;
- guint32 pre_skip;
+ guint32 sample_rate;
+ guint8 n_channels;
+ guint16 pre_skip;
gint16 r128_gain;
GstAudioChannelPosition opus_pos[64];
diff --git a/ext/opus/gstopusenc.c b/ext/opus/gstopusenc.c
index 17004ce1b..4196c1c8c 100644
--- a/ext/opus/gstopusenc.c
+++ b/ext/opus/gstopusenc.c
@@ -48,6 +48,8 @@
#include <gst/gsttagsetter.h>
#include <gst/audio/audio.h>
+#include <gst/pbutils/pbutils.h>
+#include <gst/tag/tag.h>
#include <gst/glib-compat-private.h>
#include "gstopusheader.h"
#include "gstopuscommon.h"
@@ -167,12 +169,12 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
"format = (string) " FORMAT_STR ", "
"layout = (string) interleaved, "
"rate = (int) 48000, "
- "channels = (int) [ 1, 2 ]; "
+ "channels = (int) [ 1, 8 ]; "
"audio/x-raw, "
"format = (string) " FORMAT_STR ", "
"layout = (string) interleaved, "
"rate = (int) { 8000, 12000, 16000, 24000 }, "
- "channels = (int) [ 1, 2 ] ")
+ "channels = (int) [ 1, 8 ] ")
);
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
@@ -545,27 +547,20 @@ gst_opus_enc_setup_channel_mappings (GstOpusEnc * enc,
/* For two channels, use the basic RTP mapping if the channels are
mapped as left/right. */
if (enc->n_channels == 2) {
- if (MAPS (0, FRONT_LEFT) && MAPS (1, FRONT_RIGHT)) {
- GST_INFO_OBJECT (enc, "Stereo, canonical mapping");
- enc->channel_mapping_family = 0;
- enc->n_stereo_streams = 1;
- /* The channel mapping is implicit for family 0, that's why we do not
- attempt to create one for right/left - this will be mapped to the
- Vorbis mapping below. */
- return;
- } else {
- GST_DEBUG_OBJECT (enc, "Stereo, but not canonical mapping, continuing");
- }
+ GST_INFO_OBJECT (enc, "Stereo, trivial RTP mapping");
+ enc->channel_mapping_family = 0;
+ enc->n_stereo_streams = 1;
+ /* implicit mapping for family 0 */
+ return;
}
- /* For channels between 1 and 8, we use the Vorbis mapping if we can
- find a permutation that matches it. Mono will have been taken care
- of earlier, but this code also handles it. Same for left/right stereo.
- There are two mappings. One maps the input channels to an ordering
- which has the natural pairs first so they can benefit from the Opus
- stereo channel coupling, and the other maps this ordering to the
- Vorbis ordering. */
- if (enc->n_channels >= 1 && enc->n_channels <= 8) {
+ /* For channels between 3 and 8, we use the Vorbis mapping if we can
+ find a permutation that matches it. Mono and stereo will have been taken
+ care of earlier, but this code also handles it. There are two mappings.
+ One maps the input channels to an ordering which has the natural pairs
+ first so they can benefit from the Opus stereo channel coupling, and the
+ other maps this ordering to the Vorbis ordering. */
+ if (enc->n_channels >= 3 && enc->n_channels <= 8) {
int c0, c1, c0v, c1v;
int mapped;
gboolean positions_done[256];
@@ -580,6 +575,8 @@ gst_opus_enc_setup_channel_mappings (GstOpusEnc * enc,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER},
{GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
};
size_t pair;
@@ -633,13 +630,8 @@ gst_opus_enc_setup_channel_mappings (GstOpusEnc * enc,
GST_DEBUG_OBJECT (enc, "Channel position %s is not mapped yet, adding",
gst_opus_channel_names[position]);
cv = gst_opus_enc_find_channel_position_in_vorbis_order (enc, position);
- if (cv < 0) {
- GST_WARNING_OBJECT (enc,
- "Cannot map channel positions to Vorbis order, using unknown mapping");
- enc->channel_mapping_family = 255;
- enc->n_stereo_streams = 0;
- return;
- }
+ if (cv < 0)
+ g_assert_not_reached ();
enc->encoding_channel_mapping[mapped] = n;
enc->decoding_channel_mapping[cv] = mapped;
mapped++;
@@ -718,6 +710,8 @@ gst_opus_enc_setup (GstOpusEnc * enc)
GstCaps *caps;
gboolean ret;
gint32 lookahead;
+ const GstTagList *tags;
+ GstBuffer *header, *comments;
#ifndef GST_DISABLE_GST_DEBUG
GST_DEBUG_OBJECT (enc,
@@ -764,10 +758,17 @@ gst_opus_enc_setup (GstOpusEnc * enc)
lookahead = lookahead * 48000 / enc->sample_rate;
enc->lookahead = enc->pending_lookahead = lookahead;
- gst_opus_header_create_caps (&caps, NULL, lookahead, enc->sample_rate,
- enc->n_channels, enc->n_stereo_streams, enc->channel_mapping_family,
- enc->decoding_channel_mapping,
- gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc)));
+ header = gst_codec_utils_opus_create_header (enc->sample_rate,
+ enc->n_channels, enc->channel_mapping_family,
+ enc->n_channels - enc->n_stereo_streams, enc->n_stereo_streams,
+ enc->decoding_channel_mapping, lookahead, 0);
+ tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
+ comments =
+ gst_tag_list_to_vorbiscomment_buffer (tags, (const guint8 *) "OpusTags",
+ 8, "Encoded with GStreamer opusenc");
+ caps = gst_codec_utils_opus_create_caps_from_header (header, comments);
+ gst_buffer_unref (header);
+ gst_buffer_unref (comments);
/* negotiate with these caps */
GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
@@ -814,70 +815,95 @@ gst_opus_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
}
static GstCaps *
+gst_opus_enc_get_sink_template_caps (void)
+{
+ static volatile gsize init = 0;
+ static GstCaps *caps = NULL;
+
+ if (g_once_init_enter (&init)) {
+ GValue rate_array = G_VALUE_INIT;
+ GValue v = G_VALUE_INIT;
+ GstStructure *s1, *s2, *s;
+ gint i, c;
+
+ caps = gst_caps_new_empty ();
+
+ /* Generate our two template structures */
+ g_value_init (&rate_array, GST_TYPE_LIST);
+ g_value_init (&v, G_TYPE_INT);
+ g_value_set_int (&v, 8000);
+ gst_value_list_append_value (&rate_array, &v);
+ g_value_set_int (&v, 12000);
+ gst_value_list_append_value (&rate_array, &v);
+ g_value_set_int (&v, 16000);
+ gst_value_list_append_value (&rate_array, &v);
+ g_value_set_int (&v, 24000);
+ gst_value_list_append_value (&rate_array, &v);
+
+ s1 = gst_structure_new ("audio/x-raw",
+ "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
+ "layout", G_TYPE_STRING, "interleaved",
+ "rate", G_TYPE_INT, 48000, NULL);
+ s2 = gst_structure_new ("audio/x-raw",
+ "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
+ "layout", G_TYPE_STRING, "interleaved", NULL);
+ gst_structure_set_value (s2, "rate", &rate_array);
+ g_value_unset (&rate_array);
+ g_value_unset (&v);
+
+ /* Mono */
+ s = gst_structure_copy (s1);
+ gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
+ gst_caps_append_structure (caps, s);
+
+ s = gst_structure_copy (s2);
+ gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
+ gst_caps_append_structure (caps, s);
+
+ /* Stereo and further */
+ for (i = 2; i <= 8; i++) {
+ guint64 channel_mask = 0;
+ const GstAudioChannelPosition *pos = gst_opus_channel_positions[i - 1];
+
+ for (c = 0; c < i; c++) {
+ channel_mask |= G_GUINT64_CONSTANT (1) << pos[c];
+ }
+
+ s = gst_structure_copy (s1);
+ gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
+ GST_TYPE_BITMASK, channel_mask, NULL);
+ gst_caps_append_structure (caps, s);
+
+ s = gst_structure_copy (s2);
+ gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
+ GST_TYPE_BITMASK, channel_mask, NULL);
+ gst_caps_append_structure (caps, s);
+ }
+
+ gst_structure_free (s1);
+ gst_structure_free (s2);
+
+ g_once_init_leave (&init, 1);
+ }
+
+ return caps;
+}
+
+static GstCaps *
gst_opus_enc_sink_getcaps (GstAudioEncoder * benc, GstCaps * filter)
{
GstOpusEnc *enc;
GstCaps *caps;
- GstCaps *tcaps;
- GstCaps *peercaps = NULL;
- GstCaps *intersect = NULL;
- guint i;
- gboolean allow_multistream;
enc = GST_OPUS_ENC (benc);
GST_DEBUG_OBJECT (enc, "sink getcaps");
- peercaps = gst_pad_peer_query_caps (GST_AUDIO_ENCODER_SRC_PAD (benc), NULL);
- if (!peercaps) {
- GST_DEBUG_OBJECT (benc, "No peercaps, returning template sink caps");
- return gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SINK_PAD (benc));
- }
-
- tcaps = gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (benc));
- intersect = gst_caps_intersect (peercaps, tcaps);
- gst_caps_unref (tcaps);
- gst_caps_unref (peercaps);
-
- if (gst_caps_is_empty (intersect))
- return intersect;
-
- allow_multistream = FALSE;
- for (i = 0; i < gst_caps_get_size (intersect); i++) {
- GstStructure *s = gst_caps_get_structure (intersect, i);
- gboolean multistream;
- if (gst_structure_get_boolean (s, "multistream", &multistream)) {
- if (multistream) {
- allow_multistream = TRUE;
- }
- } else {
- allow_multistream = TRUE;
- }
- }
-
- gst_caps_unref (intersect);
-
- caps = gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SINK_PAD (benc));
- caps = gst_caps_make_writable (caps);
- if (!allow_multistream) {
- GValue range = { 0 };
- g_value_init (&range, GST_TYPE_INT_RANGE);
- gst_value_set_int_range (&range, 1, 2);
- for (i = 0; i < gst_caps_get_size (caps); i++) {
- GstStructure *s = gst_caps_get_structure (caps, i);
- gst_structure_set_value (s, "channels", &range);
- }
- g_value_unset (&range);
- }
-
- if (filter) {
- GstCaps *tmp = gst_caps_intersect_full (caps, filter,
- GST_CAPS_INTERSECT_FIRST);
- gst_caps_unref (caps);
- caps = tmp;
- }
+ caps = gst_opus_enc_get_sink_template_caps ();
+ caps = gst_audio_encoder_proxy_getcaps (benc, caps, filter);
GST_DEBUG_OBJECT (enc, "Returning caps: %" GST_PTR_FORMAT, caps);
+
return caps;
}
diff --git a/ext/opus/gstopusheader.c b/ext/opus/gstopusheader.c
index 7c1cebe3c..dcc85897d 100644
--- a/ext/opus/gstopusheader.c
+++ b/ext/opus/gstopusheader.c
@@ -26,218 +26,6 @@
#include <gst/base/gstbytewriter.h>
#include "gstopusheader.h"
-static GstBuffer *
-gst_opus_enc_create_id_buffer (guint16 pre_skip, guint sample_rate,
- guint8 nchannels, guint8 n_stereo_streams, guint8 channel_mapping_family,
- const guint8 * channel_mapping)
-{
- GstBuffer *buffer;
- GstByteWriter bw;
- gboolean hdl = TRUE;
-
- g_return_val_if_fail (nchannels > 0, NULL);
- g_return_val_if_fail (n_stereo_streams <= nchannels - n_stereo_streams, 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, nchannels);
- hdl &= gst_byte_writer_put_uint16_le (&bw, pre_skip);
- hdl &= gst_byte_writer_put_uint32_le (&bw, sample_rate);
- hdl &= gst_byte_writer_put_uint16_le (&bw, 0); /* output gain */
- hdl &= gst_byte_writer_put_uint8 (&bw, channel_mapping_family);
- if (channel_mapping_family > 0) {
- hdl &= gst_byte_writer_put_uint8 (&bw, nchannels - n_stereo_streams);
- hdl &= gst_byte_writer_put_uint8 (&bw, n_stereo_streams);
- hdl &= gst_byte_writer_put_data (&bw, channel_mapping, nchannels);
- }
-
- if (!hdl)
- GST_WARNING ("Error creating header");
-
- buffer = gst_byte_writer_reset_and_get_buffer (&bw);
-
- GST_BUFFER_OFFSET (buffer) = 0;
- GST_BUFFER_OFFSET_END (buffer) = 0;
-
- return buffer;
-}
-
-static GstBuffer *
-gst_opus_enc_create_metadata_buffer (const GstTagList * tags)
-{
- GstTagList *empty_tags = NULL;
- GstBuffer *comments = NULL;
-
- GST_DEBUG ("tags = %" GST_PTR_FORMAT, tags);
-
- if (tags == NULL) {
- /* FIXME: better fix chain of callers to not write metadata at all,
- * if there is none */
- empty_tags = gst_tag_list_new_empty ();
- tags = empty_tags;
- }
- comments =
- gst_tag_list_to_vorbiscomment_buffer (tags, (const guint8 *) "OpusTags",
- 8, "Encoded with GStreamer Opusenc");
-
- GST_BUFFER_OFFSET (comments) = 0;
- GST_BUFFER_OFFSET_END (comments) = 0;
-
- if (empty_tags)
- gst_tag_list_unref (empty_tags);
-
- return comments;
-}
-
-/*
- * (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;
-}
-
-void
-gst_opus_header_create_caps_from_headers (GstCaps ** caps, GSList ** headers,
- GstBuffer * buf1, GstBuffer * buf2)
-{
- int n_streams, family;
- gint channels, rate;
- gboolean multistream;
- GstMapInfo map;
- guint8 *data;
-
- g_return_if_fail (caps);
- g_return_if_fail (!headers || !*headers);
- g_return_if_fail (gst_buffer_get_size (buf1) >= 19);
-
- gst_buffer_map (buf1, &map, GST_MAP_READ);
- data = map.data;
-
- channels = data[9];
- rate = GST_READ_UINT32_LE (data + 12);
-
- /* work out the number of streams */
- family = data[18];
- if (family == 0) {
- n_streams = 1;
- } else {
- /* only included in the header for family > 0 */
- if (map.size >= 20)
- n_streams = data[19];
- else {
- g_warning ("family > 0 but header buffer size < 20");
- gst_buffer_unmap (buf1, &map);
- return;
- }
- }
-
- /* TODO: should probably also put the channel mapping into the caps too once
- * we actually support multi channel, and pre-skip and other fields */
-
- gst_buffer_unmap (buf1, &map);
-
- /* mark and put on caps */
- multistream = n_streams > 1;
- *caps = gst_caps_new_simple ("audio/x-opus",
- "multistream", G_TYPE_BOOLEAN, multistream,
- "channels", G_TYPE_INT, channels, NULL);
-
- if (rate > 0) {
- gst_caps_set_simple (*caps, "rate", G_TYPE_INT, rate, NULL);
- }
-
- *caps = _gst_caps_set_buffer_array (*caps, "streamheader", buf1, buf2, NULL);
-
- if (headers) {
- *headers = g_slist_prepend (*headers, gst_buffer_ref (buf2));
- *headers = g_slist_prepend (*headers, gst_buffer_ref (buf1));
- }
-}
-
-void
-gst_opus_header_create_caps (GstCaps ** caps, GSList ** headers,
- guint16 pre_skip, guint sample_rate, guint8 nchannels,
- guint8 n_stereo_streams, guint8 channel_mapping_family,
- const guint8 * channel_mapping, const GstTagList * tags)
-{
- GstBuffer *buf1, *buf2;
-
- g_return_if_fail (caps);
- g_return_if_fail (!headers || !*headers);
- g_return_if_fail (nchannels > 0);
- g_return_if_fail (channel_mapping_family == 0 || channel_mapping);
-
- /* Opus streams in Ogg begin with two headers; the initial header (with
- most of the codec setup parameters) which is mandated by the Ogg
- bitstream spec. The second header holds any comment fields. */
-
- /* create header buffers */
- buf1 =
- gst_opus_enc_create_id_buffer (pre_skip, sample_rate, nchannels,
- n_stereo_streams, channel_mapping_family, channel_mapping);
- buf2 = gst_opus_enc_create_metadata_buffer (tags);
-
- gst_opus_header_create_caps_from_headers (caps, headers, buf1, buf2);
-
- gst_buffer_unref (buf2);
- gst_buffer_unref (buf1);
-}
-
gboolean
gst_opus_header_is_header (GstBuffer * buf, const char *magic, guint magic_size)
{
diff --git a/ext/opus/gstopusheader.h b/ext/opus/gstopusheader.h
index 567d88c1f..2a91c03f7 100644
--- a/ext/opus/gstopusheader.h
+++ b/ext/opus/gstopusheader.h
@@ -26,12 +26,6 @@
G_BEGIN_DECLS
-extern void gst_opus_header_create_caps_from_headers (GstCaps **caps, GSList **headers,
- GstBuffer *id_header, GstBuffer *comment_header);
-extern void gst_opus_header_create_caps (GstCaps **caps, GSList **headers,
- guint16 pre_skip, guint sample_rate32, guint8 nchannels, guint8 n_stereo_streams,
- guint8 channel_mapping_family, const guint8 *channel_mapping,
- const GstTagList *tags);
extern gboolean gst_opus_header_is_header (GstBuffer * buf,
const char *magic, guint magic_size);
extern gboolean gst_opus_header_is_id_header (GstBuffer * buf);