summaryrefslogtreecommitdiff
path: root/ext/opus/gstopusenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/opus/gstopusenc.c')
-rw-r--r--ext/opus/gstopusenc.c196
1 files changed, 111 insertions, 85 deletions
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;
}