diff options
Diffstat (limited to 'ext/opus/gstopusenc.c')
-rw-r--r-- | ext/opus/gstopusenc.c | 196 |
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; } |