diff options
author | Tim-Philipp Müller <tim@centricular.com> | 2016-02-19 00:38:33 +0000 |
---|---|---|
committer | Tim-Philipp Müller <tim@centricular.com> | 2016-02-26 00:44:34 +0000 |
commit | 5f6ab24e0d8766ee69cffcf3282d94578655a0a9 (patch) | |
tree | 1a636494146cca855a1710da3e14071a2568c050 /ext/opus | |
parent | abec124f6946e9fe0635dc53d729b3c2d92be9a9 (diff) | |
download | gstreamer-plugins-bad-5f6ab24e0d8766ee69cffcf3282d94578655a0a9.tar.gz |
opus: remove Opus encoder/decoder, moved to -base
https://bugzilla.gnome.org/show_bug.cgi?id=756282
Diffstat (limited to 'ext/opus')
-rw-r--r-- | ext/opus/Makefile.am | 4 | ||||
-rw-r--r-- | ext/opus/gstopus.c | 11 | ||||
-rw-r--r-- | ext/opus/gstopuscommon.c | 111 | ||||
-rw-r--r-- | ext/opus/gstopuscommon.h | 37 | ||||
-rw-r--r-- | ext/opus/gstopusdec.c | 819 | ||||
-rw-r--r-- | ext/opus/gstopusdec.h | 86 | ||||
-rw-r--r-- | ext/opus/gstopusenc.c | 1282 | ||||
-rw-r--r-- | ext/opus/gstopusenc.h | 102 |
8 files changed, 2 insertions, 2450 deletions
diff --git a/ext/opus/Makefile.am b/ext/opus/Makefile.am index aa0d4388e..4630715ba 100644 --- a/ext/opus/Makefile.am +++ b/ext/opus/Makefile.am @@ -1,6 +1,6 @@ plugin_LTLIBRARIES = libgstopus.la -libgstopus_la_SOURCES = gstopus.c gstopusdec.c gstopusenc.c gstopusparse.c gstopusheader.c gstopuscommon.c +libgstopus_la_SOURCES = gstopus.c gstopusparse.c gstopusheader.c libgstopus_la_CFLAGS = \ -DGST_USE_UNSTABLE_API \ $(GST_PLUGINS_BAD_CFLAGS) \ @@ -17,4 +17,4 @@ libgstopus_la_LIBADD = \ libgstopus_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(LIBM) libgstopus_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) -noinst_HEADERS = gstopusenc.h gstopusdec.h gstopusparse.h gstopusheader.h gstopuscommon.h +noinst_HEADERS = gstopusparse.h gstopusheader.h diff --git a/ext/opus/gstopus.c b/ext/opus/gstopus.c index 63d50ef3e..0f9cc379e 100644 --- a/ext/opus/gstopus.c +++ b/ext/opus/gstopus.c @@ -21,8 +21,6 @@ #include <config.h> #endif -#include "gstopusdec.h" -#include "gstopusenc.h" #include "gstopusparse.h" #include <gst/tag/tag.h> @@ -30,15 +28,6 @@ static gboolean plugin_init (GstPlugin * plugin) { - - if (!gst_element_register (plugin, "opusenc", GST_RANK_PRIMARY, - GST_TYPE_OPUS_ENC)) - return FALSE; - - if (!gst_element_register (plugin, "opusdec", GST_RANK_PRIMARY, - GST_TYPE_OPUS_DEC)) - return FALSE; - if (!gst_element_register (plugin, "opusparse", GST_RANK_NONE, GST_TYPE_OPUS_PARSE)) return FALSE; diff --git a/ext/opus/gstopuscommon.c b/ext/opus/gstopuscommon.c deleted file mode 100644 index febccd85f..000000000 --- a/ext/opus/gstopuscommon.c +++ /dev/null @@ -1,111 +0,0 @@ -/* GStreamer - * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include <stdio.h> -#include <string.h> -#include "gstopuscommon.h" - -/* http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 */ -/* copy of the same structure in the vorbis plugin */ -const GstAudioChannelPosition gst_opus_channel_positions[][8] = { - { /* Mono */ - GST_AUDIO_CHANNEL_POSITION_MONO}, - { /* Stereo */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, - { /* Stereo + Centre */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, - { /* Quadraphonic */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - }, - { /* Stereo + Centre + rear stereo */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - }, - { /* Full 5.1 Surround */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_LFE1, - }, - { /* 6.1 Surround, in Vorbis spec since 2010-01-13 */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, - GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE1}, - { /* 7.1 Surround, in Vorbis spec since 2010-01-13 */ - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, - GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_LFE1}, -}; - -const char *gst_opus_channel_names[] = { - "mono", - "front left", - "front right", - "rear center", - "rear left", - "rear right", - "lfe", - "front center", - "front left of center", - "front right of center", - "side left", - "side right", - "none" -}; - -void -gst_opus_common_log_channel_mapping_table (GstElement * element, - GstDebugCategory * category, const char *msg, int n_channels, - const guint8 * table) -{ - int n; - GString *s; - - if (gst_debug_category_get_threshold (category) < GST_LEVEL_INFO) - return; - - s = g_string_new ("[ "); - for (n = 0; n < n_channels; ++n) { - g_string_append_printf (s, "%d ", table[n]); - } - g_string_append (s, "]"); - - GST_CAT_LEVEL_LOG (category, GST_LEVEL_INFO, element, "%s: %s", msg, s->str); - g_string_free (s, TRUE); -} diff --git a/ext/opus/gstopuscommon.h b/ext/opus/gstopuscommon.h deleted file mode 100644 index 71771ae74..000000000 --- a/ext/opus/gstopuscommon.h +++ /dev/null @@ -1,37 +0,0 @@ -/* GStreamer Opus Encoder - * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - - -#ifndef __GST_OPUS_COMMON_H__ -#define __GST_OPUS_COMMON_H__ - -#include <gst/gst.h> -#include <gst/audio/audio.h> - -G_BEGIN_DECLS - -extern const GstAudioChannelPosition gst_opus_channel_positions[][8]; -extern const char *gst_opus_channel_names[]; -extern void gst_opus_common_log_channel_mapping_table (GstElement *element, - GstDebugCategory * category, const char *msg, - int n_channels, const guint8 *table); - -G_END_DECLS - -#endif /* __GST_OPUS_COMMON_H__ */ diff --git a/ext/opus/gstopusdec.c b/ext/opus/gstopusdec.c deleted file mode 100644 index 1470ea321..000000000 --- a/ext/opus/gstopusdec.c +++ /dev/null @@ -1,819 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Wim Taymans <wim@fluendo.com> - * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net> - * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk> - * Copyright (C) 2011-2012 Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -/* - * Based on the speexdec element. - */ - -/** - * SECTION:element-opusdec - * @see_also: opusenc, oggdemux - * - * This element decodes a OPUS stream to raw integer audio. - * - * <refsect2> - * <title>Example pipelines</title> - * |[ - * gst-launch-1.0 -v filesrc location=opus.ogg ! oggdemux ! opusdec ! audioconvert ! audioresample ! alsasink - * ]| Decode an Ogg/Opus file. To create an Ogg/Opus file refer to the documentation of opusenc. - * </refsect2> - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <math.h> -#include <string.h> -#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 - -static GstStaticPadTemplate opus_dec_src_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw, " - "format = (string) " GST_AUDIO_NE (S16) ", " - "layout = (string) interleaved, " - "rate = (int) { 48000, 24000, 16000, 12000, 8000 }, " - "channels = (int) [ 1, 8 ] ") - ); - -static GstStaticPadTemplate opus_dec_sink_factory = - GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-opus, " - "channel-mapping-family = (int) 0; " - "audio/x-opus, " - "channel-mapping-family = (int) [1, 255], " - "channels = (int) [1, 255], " - "stream-count = (int) [1, 255], " "coupled-count = (int) [0, 255]") - ); - -G_DEFINE_TYPE (GstOpusDec, gst_opus_dec, GST_TYPE_AUDIO_DECODER); - -#define DB_TO_LINEAR(x) pow (10., (x) / 20.) - -#define DEFAULT_USE_INBAND_FEC FALSE -#define DEFAULT_APPLY_GAIN TRUE - -enum -{ - PROP_0, - PROP_USE_INBAND_FEC, - PROP_APPLY_GAIN -}; - - -static GstFlowReturn gst_opus_dec_parse_header (GstOpusDec * dec, - GstBuffer * buf); -static gboolean gst_opus_dec_start (GstAudioDecoder * dec); -static gboolean gst_opus_dec_stop (GstAudioDecoder * dec); -static GstFlowReturn gst_opus_dec_handle_frame (GstAudioDecoder * dec, - GstBuffer * buffer); -static gboolean gst_opus_dec_set_format (GstAudioDecoder * bdec, - GstCaps * caps); -static void gst_opus_dec_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_opus_dec_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); - - -static void -gst_opus_dec_class_init (GstOpusDecClass * klass) -{ - GObjectClass *gobject_class; - GstAudioDecoderClass *adclass; - GstElementClass *element_class; - - gobject_class = (GObjectClass *) klass; - adclass = (GstAudioDecoderClass *) klass; - element_class = (GstElementClass *) klass; - - gobject_class->set_property = gst_opus_dec_set_property; - gobject_class->get_property = gst_opus_dec_get_property; - - adclass->start = GST_DEBUG_FUNCPTR (gst_opus_dec_start); - adclass->stop = GST_DEBUG_FUNCPTR (gst_opus_dec_stop); - adclass->handle_frame = GST_DEBUG_FUNCPTR (gst_opus_dec_handle_frame); - adclass->set_format = GST_DEBUG_FUNCPTR (gst_opus_dec_set_format); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&opus_dec_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&opus_dec_sink_factory)); - gst_element_class_set_static_metadata (element_class, "Opus audio decoder", - "Codec/Decoder/Audio", - "decode opus streams to audio", - "Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>"); - g_object_class_install_property (gobject_class, PROP_USE_INBAND_FEC, - g_param_spec_boolean ("use-inband-fec", "Use in-band FEC", - "Use forward error correction if available (needs PLC enabled)", - DEFAULT_USE_INBAND_FEC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_APPLY_GAIN, - g_param_spec_boolean ("apply-gain", "Apply gain", - "Apply gain if any is specified in the header", DEFAULT_APPLY_GAIN, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - GST_DEBUG_CATEGORY_INIT (opusdec_debug, "opusdec", 0, - "opus decoding element"); -} - -static void -gst_opus_dec_reset (GstOpusDec * dec) -{ - dec->packetno = 0; - if (dec->state) { - opus_multistream_decoder_destroy (dec->state); - dec->state = NULL; - } - - gst_buffer_replace (&dec->streamheader, NULL); - gst_buffer_replace (&dec->vorbiscomment, NULL); - gst_buffer_replace (&dec->last_buffer, NULL); - dec->primed = FALSE; - - dec->pre_skip = 0; - dec->r128_gain = 0; - dec->sample_rate = 0; - dec->n_channels = 0; - dec->leftover_plc_duration = 0; -} - -static void -gst_opus_dec_init (GstOpusDec * dec) -{ - dec->use_inband_fec = FALSE; - dec->apply_gain = DEFAULT_APPLY_GAIN; - - gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (dec), TRUE); - gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST - (dec), TRUE); - GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (dec)); - - gst_opus_dec_reset (dec); -} - -static gboolean -gst_opus_dec_start (GstAudioDecoder * dec) -{ - GstOpusDec *odec = GST_OPUS_DEC (dec); - - gst_opus_dec_reset (odec); - - /* we know about concealment */ - gst_audio_decoder_set_plc_aware (dec, TRUE); - - if (odec->use_inband_fec) { - /* opusdec outputs samples directly from an input buffer, except if - * FEC is on, in which case it buffers one buffer in case one buffer - * goes missing. - */ - gst_audio_decoder_set_latency (dec, 120 * GST_MSECOND, 120 * GST_MSECOND); - } - - return TRUE; -} - -static gboolean -gst_opus_dec_stop (GstAudioDecoder * dec) -{ - GstOpusDec *odec = GST_OPUS_DEC (dec); - - gst_opus_dec_reset (odec); - - return TRUE; -} - -static double -gst_opus_dec_get_r128_gain (gint16 r128_gain) -{ - return r128_gain / (double) (1 << 8); -} - -static double -gst_opus_dec_get_r128_volume (gint16 r128_gain) -{ - return DB_TO_LINEAR (gst_opus_dec_get_r128_gain (r128_gain)); -} - -static void -gst_opus_dec_negotiate (GstOpusDec * dec, const GstAudioChannelPosition * pos) -{ - GstCaps *caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dec)); - GstStructure *s; - 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); - - if (gst_structure_has_field (s, "rate")) - 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", &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", &channels); - dec->n_channels = channels; - - gst_caps_unref (caps); - } - - if (dec->n_channels == 0) { - GST_DEBUG_OBJECT (dec, "Using a default of 2 channels"); - dec->n_channels = 2; - pos = NULL; - } - - if (dec->sample_rate == 0) { - GST_DEBUG_OBJECT (dec, "Using a default of 48kHz sample rate"); - dec->sample_rate = 48000; - } - - GST_INFO_OBJECT (dec, "Negotiated %d channels, %d Hz", dec->n_channels, - dec->sample_rate); - - /* pass valid order to audio info */ - 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); - } - - /* set up source format */ - gst_audio_info_init (&info); - gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, - dec->sample_rate, dec->n_channels, pos ? dec->opus_pos : NULL); - gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dec), &info); - - /* but we still need the opus order for later reordering */ - if (pos) { - memcpy (dec->opus_pos, pos, sizeof (pos[0]) * dec->n_channels); - } else { - dec->opus_pos[0] = GST_AUDIO_CHANNEL_POSITION_INVALID; - } - - dec->info = info; -} - -static GstFlowReturn -gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf) -{ - GstAudioChannelPosition pos[64]; - const GstAudioChannelPosition *posn = NULL; - - if (!gst_opus_header_is_id_header (buf)) { - GST_ERROR_OBJECT (dec, "Header is not an Opus ID header"); - return GST_FLOW_ERROR; - } - - 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); - - 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); - } - - gst_opus_dec_negotiate (dec, posn); - - return GST_FLOW_OK; -} - - -static GstFlowReturn -gst_opus_dec_parse_comments (GstOpusDec * dec, GstBuffer * buf) -{ - return GST_FLOW_OK; -} - -static GstFlowReturn -opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) -{ - GstFlowReturn res = GST_FLOW_OK; - gsize size; - guint8 *data; - GstBuffer *outbuf, *bufd; - gint16 *out_data; - int n, err; - int samples; - unsigned int packet_size; - GstBuffer *buf; - GstMapInfo map, omap; - GstAudioClippingMeta *cmeta = NULL; - - if (dec->state == NULL) { - /* If we did not get any headers, default to 2 channels */ - if (dec->n_channels == 0) { - GST_INFO_OBJECT (dec, "No header, assuming single stream"); - dec->n_channels = 2; - dec->sample_rate = 48000; - /* 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; - - gst_opus_dec_negotiate (dec, NULL); - } - - GST_DEBUG_OBJECT (dec, "Creating decoder with %d channels, %d Hz", - dec->n_channels, dec->sample_rate); -#ifndef GST_DISABLE_GST_DEBUG - gst_opus_common_log_channel_mapping_table (GST_ELEMENT (dec), opusdec_debug, - "Mapping table", dec->n_channels, dec->channel_mapping); -#endif - - GST_DEBUG_OBJECT (dec, "%d streams, %d stereo", dec->n_streams, - dec->n_stereo_streams); - dec->state = - opus_multistream_decoder_create (dec->sample_rate, dec->n_channels, - dec->n_streams, dec->n_stereo_streams, dec->channel_mapping, &err); - if (!dec->state || err != OPUS_OK) - goto creation_failed; - } - - if (buffer) { - GST_DEBUG_OBJECT (dec, "Received buffer of size %" G_GSIZE_FORMAT, - gst_buffer_get_size (buffer)); - } else { - GST_DEBUG_OBJECT (dec, "Received missing buffer"); - } - - /* if using in-band FEC, we introdude one extra frame's delay as we need - to potentially wait for next buffer to decode a missing buffer */ - if (dec->use_inband_fec && !dec->primed) { - GST_DEBUG_OBJECT (dec, "First buffer received in FEC mode, early out"); - gst_buffer_replace (&dec->last_buffer, buffer); - dec->primed = TRUE; - goto done; - } - - /* That's the buffer we'll be sending to the opus decoder. */ - buf = (dec->use_inband_fec - && gst_buffer_get_size (dec->last_buffer) > - 0) ? dec->last_buffer : buffer; - - /* That's the buffer we get duration from */ - bufd = dec->use_inband_fec ? dec->last_buffer : buffer; - - if (buf && gst_buffer_get_size (buf) > 0) { - gst_buffer_map (buf, &map, GST_MAP_READ); - data = map.data; - size = map.size; - GST_DEBUG_OBJECT (dec, "Using buffer of size %" G_GSIZE_FORMAT, size); - } else { - /* concealment data, pass NULL as the bits parameters */ - GST_DEBUG_OBJECT (dec, "Using NULL buffer"); - data = NULL; - size = 0; - } - - if (gst_buffer_get_size (bufd) == 0) { - GstClockTime const opus_plc_alignment = 2500 * GST_USECOND; - GstClockTime aligned_missing_duration; - GstClockTime missing_duration = GST_BUFFER_DURATION (bufd); - - GST_DEBUG_OBJECT (dec, - "missing buffer, doing PLC duration %" GST_TIME_FORMAT - " plus leftover %" GST_TIME_FORMAT, GST_TIME_ARGS (missing_duration), - GST_TIME_ARGS (dec->leftover_plc_duration)); - - /* add the leftover PLC duration to that of the buffer */ - missing_duration += dec->leftover_plc_duration; - - /* align the combined buffer and leftover PLC duration to multiples - * of 2.5ms, rounding to nearest, and store excess duration for later */ - aligned_missing_duration = - ((missing_duration + - opus_plc_alignment / 2) / opus_plc_alignment) * opus_plc_alignment; - dec->leftover_plc_duration = missing_duration - aligned_missing_duration; - - /* Opus' PLC cannot operate with less than 2.5ms; skip PLC - * and accumulate the missing duration in the leftover_plc_duration - * for the next PLC attempt */ - if (aligned_missing_duration < opus_plc_alignment) { - GST_DEBUG_OBJECT (dec, - "current duration %" GST_TIME_FORMAT - " of missing data not enough for PLC (minimum needed: %" - GST_TIME_FORMAT ") - skipping", GST_TIME_ARGS (missing_duration), - GST_TIME_ARGS (opus_plc_alignment)); - goto done; - } - - /* convert the duration (in nanoseconds) to sample count */ - samples = - gst_util_uint64_scale_int (aligned_missing_duration, dec->sample_rate, - GST_SECOND); - - GST_DEBUG_OBJECT (dec, - "calculated PLC frame length: %" GST_TIME_FORMAT - " num frame samples: %d new leftover: %" GST_TIME_FORMAT, - GST_TIME_ARGS (aligned_missing_duration), samples, - GST_TIME_ARGS (dec->leftover_plc_duration)); - } else { - /* use maximum size (120 ms) as the number of returned samples is - not constant over the stream. */ - samples = 120 * dec->sample_rate / 1000; - } - - packet_size = samples * dec->n_channels * 2; - - outbuf = - gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (dec), - packet_size); - if (!outbuf) { - goto buffer_failed; - } - - gst_buffer_map (outbuf, &omap, GST_MAP_WRITE); - out_data = (gint16 *) omap.data; - - if (dec->use_inband_fec) { - if (gst_buffer_get_size (dec->last_buffer) > 0) { - /* normal delayed decode */ - GST_LOG_OBJECT (dec, "FEC enabled, decoding last delayed buffer"); - n = opus_multistream_decode (dec->state, data, size, out_data, samples, - 0); - } else { - /* FEC reconstruction decode */ - GST_LOG_OBJECT (dec, "FEC enabled, reconstructing last buffer"); - n = opus_multistream_decode (dec->state, data, size, out_data, samples, - 1); - } - } else { - /* normal decode */ - GST_LOG_OBJECT (dec, "FEC disabled, decoding buffer"); - n = opus_multistream_decode (dec->state, data, size, out_data, samples, 0); - } - gst_buffer_unmap (outbuf, &omap); - if (data != NULL) - gst_buffer_unmap (buf, &map); - - if (n < 0) { - GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Decoding error: %d", n), (NULL)); - gst_buffer_unref (outbuf); - return GST_FLOW_ERROR; - } - GST_DEBUG_OBJECT (dec, "decoded %d samples", n); - gst_buffer_set_size (outbuf, n * 2 * dec->n_channels); - - cmeta = gst_buffer_get_audio_clipping_meta (buf); - - g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT); - - /* Skip any samples that need skipping */ - if (cmeta && cmeta->start) { - guint pre_skip = cmeta->start; - guint scaled_pre_skip = pre_skip * dec->sample_rate / 48000; - guint skip = scaled_pre_skip > n ? n : scaled_pre_skip; - guint scaled_skip = skip * 48000 / dec->sample_rate; - - gst_buffer_resize (outbuf, skip * 2 * dec->n_channels, -1); - - GST_INFO_OBJECT (dec, - "Skipping %u samples at the beginning (%u at 48000 Hz)", - skip, scaled_skip); - } - - if (cmeta && cmeta->end) { - guint post_skip = cmeta->end; - guint scaled_post_skip = post_skip * dec->sample_rate / 48000; - guint skip = scaled_post_skip > n ? n : scaled_post_skip; - guint scaled_skip = skip * 48000 / dec->sample_rate; - guint outsize = gst_buffer_get_size (outbuf); - guint skip_bytes = skip * 2 * dec->n_channels; - - if (outsize > skip_bytes) - outsize -= skip_bytes; - else - outsize = 0; - - gst_buffer_resize (outbuf, 0, outsize); - - GST_INFO_OBJECT (dec, - "Skipping %u samples at the end (%u at 48000 Hz)", skip, scaled_skip); - } - - if (gst_buffer_get_size (outbuf) == 0) { - gst_buffer_unref (outbuf); - outbuf = NULL; - } else if (dec->opus_pos[0] != GST_AUDIO_CHANNEL_POSITION_INVALID) { - gst_audio_buffer_reorder_channels (outbuf, GST_AUDIO_FORMAT_S16, - dec->n_channels, dec->opus_pos, dec->info.position); - } - - /* Apply gain */ - /* Would be better off leaving this to a volume element, as this is - a naive conversion that does too many int/float conversions. - However, we don't have control over the pipeline... - So make it optional if the user program wants to use a volume, - but do it by default so the correct volume goes out by default */ - if (dec->apply_gain && outbuf && dec->r128_gain) { - gsize rsize; - unsigned int i, nsamples; - double volume = dec->r128_gain_volume; - gint16 *samples; - - gst_buffer_map (outbuf, &omap, GST_MAP_READWRITE); - samples = (gint16 *) omap.data; - rsize = omap.size; - GST_DEBUG_OBJECT (dec, "Applying gain: volume %f", volume); - nsamples = rsize / 2; - for (i = 0; i < nsamples; ++i) { - int sample = (int) (samples[i] * volume + 0.5); - samples[i] = sample < -32768 ? -32768 : sample > 32767 ? 32767 : sample; - } - gst_buffer_unmap (outbuf, &omap); - } - - if (dec->use_inband_fec) { - gst_buffer_replace (&dec->last_buffer, buffer); - } - - res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1); - - if (res != GST_FLOW_OK) - GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res)); - -done: - return res; - -creation_failed: - GST_ERROR_OBJECT (dec, "Failed to create Opus decoder: %d", err); - return GST_FLOW_ERROR; - -buffer_failed: - GST_ERROR_OBJECT (dec, "Failed to create %u byte buffer", packet_size); - return GST_FLOW_ERROR; -} - -static gboolean -gst_opus_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps) -{ - GstOpusDec *dec = GST_OPUS_DEC (bdec); - gboolean ret = TRUE; - GstStructure *s; - const GValue *streamheader; - GstCaps *old_caps; - - GST_DEBUG_OBJECT (dec, "set_format: %" GST_PTR_FORMAT, caps); - - if ((old_caps = gst_pad_get_current_caps (GST_AUDIO_DECODER_SINK_PAD (bdec)))) { - if (gst_caps_is_equal (caps, old_caps)) { - gst_caps_unref (old_caps); - GST_DEBUG_OBJECT (dec, "caps didn't change"); - goto done; - } - - GST_DEBUG_OBJECT (dec, "caps have changed, resetting decoder"); - gst_opus_dec_reset (dec); - gst_caps_unref (old_caps); - } - - s = gst_caps_get_structure (caps, 0); - if ((streamheader = gst_structure_get_value (s, "streamheader")) && - G_VALUE_HOLDS (streamheader, GST_TYPE_ARRAY) && - gst_value_array_get_size (streamheader) >= 2) { - const GValue *header, *vorbiscomment; - GstBuffer *buf; - GstFlowReturn res = GST_FLOW_OK; - - header = gst_value_array_get_value (streamheader, 0); - 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) { - ret = FALSE; - goto done; - } - gst_buffer_replace (&dec->streamheader, buf); - } - - vorbiscomment = gst_value_array_get_value (streamheader, 1); - 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) { - ret = FALSE; - goto done; - } - gst_buffer_replace (&dec->vorbiscomment, buf); - } - } else { - const GstAudioChannelPosition *posn = NULL; - - 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; - } - - if (dec->channel_mapping_family == 1 && dec->n_channels <= 8) - posn = gst_opus_channel_positions[dec->n_channels - 1]; - - gst_opus_dec_negotiate (dec, posn); - } - -done: - return ret; -} - -static gboolean -memcmp_buffers (GstBuffer * buf1, GstBuffer * buf2) -{ - gsize size1, size2; - gboolean res; - GstMapInfo map; - - size1 = gst_buffer_get_size (buf1); - size2 = gst_buffer_get_size (buf2); - - if (size1 != size2) - return FALSE; - - gst_buffer_map (buf1, &map, GST_MAP_READ); - res = gst_buffer_memcmp (buf2, 0, map.data, map.size) == 0; - gst_buffer_unmap (buf1, &map); - - return res; -} - -static GstFlowReturn -gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf) -{ - GstFlowReturn res; - GstOpusDec *dec; - - /* no fancy draining */ - if (G_UNLIKELY (!buf)) - return GST_FLOW_OK; - - dec = GST_OPUS_DEC (adec); - GST_LOG_OBJECT (dec, - "Got buffer ts %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - - /* If we have the streamheader and vorbiscomment from the caps already - * ignore them here */ - if (dec->streamheader && dec->vorbiscomment) { - if (memcmp_buffers (dec->streamheader, buf)) { - GST_DEBUG_OBJECT (dec, "found streamheader"); - gst_audio_decoder_finish_frame (adec, NULL, 1); - res = GST_FLOW_OK; - } else if (memcmp_buffers (dec->vorbiscomment, buf)) { - GST_DEBUG_OBJECT (dec, "found vorbiscomments"); - gst_audio_decoder_finish_frame (adec, NULL, 1); - res = GST_FLOW_OK; - } else { - res = opus_dec_chain_parse_data (dec, buf); - } - } else { - /* Otherwise fall back to packet counting and assume that the - * first two packets might be the headers, checking magic. */ - switch (dec->packetno) { - case 0: - if (gst_opus_header_is_header (buf, "OpusHead", 8)) { - GST_DEBUG_OBJECT (dec, "found streamheader"); - res = gst_opus_dec_parse_header (dec, buf); - gst_audio_decoder_finish_frame (adec, NULL, 1); - } else { - res = opus_dec_chain_parse_data (dec, buf); - } - break; - case 1: - if (gst_opus_header_is_header (buf, "OpusTags", 8)) { - GST_DEBUG_OBJECT (dec, "counted vorbiscomments"); - res = gst_opus_dec_parse_comments (dec, buf); - gst_audio_decoder_finish_frame (adec, NULL, 1); - } else { - res = opus_dec_chain_parse_data (dec, buf); - } - break; - default: - { - res = opus_dec_chain_parse_data (dec, buf); - break; - } - } - } - - dec->packetno++; - - return res; -} - -static void -gst_opus_dec_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstOpusDec *dec = GST_OPUS_DEC (object); - - switch (prop_id) { - case PROP_USE_INBAND_FEC: - g_value_set_boolean (value, dec->use_inband_fec); - break; - case PROP_APPLY_GAIN: - g_value_set_boolean (value, dec->apply_gain); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_opus_dec_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstOpusDec *dec = GST_OPUS_DEC (object); - - switch (prop_id) { - case PROP_USE_INBAND_FEC: - dec->use_inband_fec = g_value_get_boolean (value); - break; - case PROP_APPLY_GAIN: - dec->apply_gain = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff --git a/ext/opus/gstopusdec.h b/ext/opus/gstopusdec.h deleted file mode 100644 index df52cfb6f..000000000 --- a/ext/opus/gstopusdec.h +++ /dev/null @@ -1,86 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> - * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk> - * Copyright (C) <2011-2012> Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __GST_OPUS_DEC_H__ -#define __GST_OPUS_DEC_H__ - -#include <gst/gst.h> -#include <gst/audio/gstaudiodecoder.h> -#include <opus_multistream.h> - -G_BEGIN_DECLS - -#define GST_TYPE_OPUS_DEC \ - (gst_opus_dec_get_type()) -#define GST_OPUS_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OPUS_DEC,GstOpusDec)) -#define GST_OPUS_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OPUS_DEC,GstOpusDecClass)) -#define GST_IS_OPUS_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OPUS_DEC)) -#define GST_IS_OPUS_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OPUS_DEC)) - -typedef struct _GstOpusDec GstOpusDec; -typedef struct _GstOpusDecClass GstOpusDecClass; - -struct _GstOpusDec { - GstAudioDecoder element; - - OpusMSDecoder *state; - - guint64 packetno; - - GstBuffer *streamheader; - GstBuffer *vorbiscomment; - - guint32 sample_rate; - guint8 n_channels; - guint16 pre_skip; - gint16 r128_gain; - - GstAudioChannelPosition opus_pos[64]; - GstAudioInfo info; - - guint8 n_streams; - guint8 n_stereo_streams; - guint8 channel_mapping_family; - guint8 channel_mapping[256]; - - gboolean apply_gain; - double r128_gain_volume; - - gboolean use_inband_fec; - GstBuffer *last_buffer; - gboolean primed; - - guint64 leftover_plc_duration; -}; - -struct _GstOpusDecClass { - GstAudioDecoderClass parent_class; -}; - -GType gst_opus_dec_get_type (void); - -G_END_DECLS - -#endif /* __GST_OPUS_DEC_H__ */ diff --git a/ext/opus/gstopusenc.c b/ext/opus/gstopusenc.c deleted file mode 100644 index 7737bf575..000000000 --- a/ext/opus/gstopusenc.c +++ /dev/null @@ -1,1282 +0,0 @@ -/* GStreamer Opus Encoder - * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> - * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk> - * Copyright (C) <2011> Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -/* - * Based on the speexenc element - */ - -/** - * SECTION:element-opusenc - * @see_also: opusdec, oggmux - * - * This element encodes raw audio to OPUS. - * - * <refsect2> - * <title>Example pipelines</title> - * |[ - * gst-launch-1.0 -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! opusenc ! oggmux ! filesink location=sine.ogg - * ]| Encode a test sine signal to Ogg/OPUS. - * </refsect2> - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <math.h> -#include <opus.h> - -#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" -#include "gstopusenc.h" - -GST_DEBUG_CATEGORY_STATIC (opusenc_debug); -#define GST_CAT_DEFAULT opusenc_debug - -/* Some arbitrary bounds beyond which it really doesn't make sense. - The spec mentions 6 kb/s to 510 kb/s, so 4000 and 650000 ought to be - safe as property bounds. */ -#define LOWEST_BITRATE 4000 -#define HIGHEST_BITRATE 650000 - -#define GST_OPUS_ENC_TYPE_BANDWIDTH (gst_opus_enc_bandwidth_get_type()) -static GType -gst_opus_enc_bandwidth_get_type (void) -{ - static const GEnumValue values[] = { - {OPUS_BANDWIDTH_NARROWBAND, "Narrow band", "narrowband"}, - {OPUS_BANDWIDTH_MEDIUMBAND, "Medium band", "mediumband"}, - {OPUS_BANDWIDTH_WIDEBAND, "Wide band", "wideband"}, - {OPUS_BANDWIDTH_SUPERWIDEBAND, "Super wide band", "superwideband"}, - {OPUS_BANDWIDTH_FULLBAND, "Full band", "fullband"}, - {OPUS_AUTO, "Auto", "auto"}, - {0, NULL, NULL} - }; - static volatile GType id = 0; - - if (g_once_init_enter ((gsize *) & id)) { - GType _id; - - _id = g_enum_register_static ("GstOpusEncBandwidth", values); - - g_once_init_leave ((gsize *) & id, _id); - } - - return id; -} - -#define GST_OPUS_ENC_TYPE_FRAME_SIZE (gst_opus_enc_frame_size_get_type()) -static GType -gst_opus_enc_frame_size_get_type (void) -{ - static const GEnumValue values[] = { - {2, "2.5", "2.5"}, - {5, "5", "5"}, - {10, "10", "10"}, - {20, "20", "20"}, - {40, "40", "40"}, - {60, "60", "60"}, - {0, NULL, NULL} - }; - static volatile GType id = 0; - - if (g_once_init_enter ((gsize *) & id)) { - GType _id; - - _id = g_enum_register_static ("GstOpusEncFrameSize", values); - - g_once_init_leave ((gsize *) & id, _id); - } - - return id; -} - -#define GST_OPUS_ENC_TYPE_AUDIO_TYPE (gst_opus_enc_audio_type_get_type()) -static GType -gst_opus_enc_audio_type_get_type (void) -{ - static const GEnumValue values[] = { - {OPUS_APPLICATION_AUDIO, "Generic audio", "generic"}, - {OPUS_APPLICATION_VOIP, "Voice", "voice"}, - {0, NULL, NULL} - }; - static volatile GType id = 0; - - if (g_once_init_enter ((gsize *) & id)) { - GType _id; - - _id = g_enum_register_static ("GstOpusEncAudioType", values); - - g_once_init_leave ((gsize *) & id, _id); - } - - return id; -} - -#define GST_OPUS_ENC_TYPE_BITRATE_TYPE (gst_opus_enc_bitrate_type_get_type()) -static GType -gst_opus_enc_bitrate_type_get_type (void) -{ - static const GEnumValue values[] = { - {BITRATE_TYPE_CBR, "CBR", "cbr"}, - {BITRATE_TYPE_VBR, "VBR", "vbr"}, - {BITRATE_TYPE_CONSTRAINED_VBR, "Constrained VBR", "constrained-vbr"}, - {0, NULL, NULL} - }; - static volatile GType id = 0; - - if (g_once_init_enter ((gsize *) & id)) { - GType _id; - - _id = g_enum_register_static ("GstOpusEncBitrateType", values); - - g_once_init_leave ((gsize *) & id, _id); - } - - return id; -} - -#define FORMAT_STR GST_AUDIO_NE(S16) -static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw, " - "format = (string) " FORMAT_STR ", " - "layout = (string) interleaved, " - "rate = (int) 48000, " - "channels = (int) [ 1, 8 ]; " - "audio/x-raw, " - "format = (string) " FORMAT_STR ", " - "layout = (string) interleaved, " - "rate = (int) { 8000, 12000, 16000, 24000 }, " - "channels = (int) [ 1, 8 ] ") - ); - -static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-opus") - ); - -#define DEFAULT_AUDIO TRUE -#define DEFAULT_AUDIO_TYPE OPUS_APPLICATION_AUDIO -#define DEFAULT_BITRATE 64000 -#define DEFAULT_BANDWIDTH OPUS_BANDWIDTH_FULLBAND -#define DEFAULT_FRAMESIZE 20 -#define DEFAULT_CBR TRUE -#define DEFAULT_CONSTRAINED_VBR TRUE -#define DEFAULT_BITRATE_TYPE BITRATE_TYPE_CBR -#define DEFAULT_COMPLEXITY 10 -#define DEFAULT_INBAND_FEC FALSE -#define DEFAULT_DTX FALSE -#define DEFAULT_PACKET_LOSS_PERCENT 0 -#define DEFAULT_MAX_PAYLOAD_SIZE 4000 - -enum -{ - PROP_0, - PROP_AUDIO, - PROP_AUDIO_TYPE, - PROP_BITRATE, - PROP_BANDWIDTH, - PROP_FRAME_SIZE, - PROP_CBR, - PROP_CONSTRAINED_VBR, - PROP_BITRATE_TYPE, - PROP_COMPLEXITY, - PROP_INBAND_FEC, - PROP_DTX, - PROP_PACKET_LOSS_PERCENT, - PROP_MAX_PAYLOAD_SIZE -}; - -static void gst_opus_enc_finalize (GObject * object); - -static gboolean gst_opus_enc_sink_event (GstAudioEncoder * benc, - GstEvent * event); -static GstCaps *gst_opus_enc_sink_getcaps (GstAudioEncoder * benc, - GstCaps * filter); -static gboolean gst_opus_enc_setup (GstOpusEnc * enc); - -static void gst_opus_enc_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_opus_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); - -static void gst_opus_enc_set_tags (GstOpusEnc * enc); -static gboolean gst_opus_enc_start (GstAudioEncoder * benc); -static gboolean gst_opus_enc_stop (GstAudioEncoder * benc); -static gboolean gst_opus_enc_set_format (GstAudioEncoder * benc, - GstAudioInfo * info); -static GstFlowReturn gst_opus_enc_handle_frame (GstAudioEncoder * benc, - GstBuffer * buf); -static gint64 gst_opus_enc_get_latency (GstOpusEnc * enc); - -static GstFlowReturn gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buffer); - -#define gst_opus_enc_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstOpusEnc, gst_opus_enc, GST_TYPE_AUDIO_ENCODER, - G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL); - G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL)); - -static void -gst_opus_enc_set_tags (GstOpusEnc * enc) -{ - GstTagList *taglist; - - /* create a taglist and add a bitrate tag to it */ - taglist = gst_tag_list_new_empty (); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_BITRATE, enc->bitrate, NULL); - - gst_audio_encoder_merge_tags (GST_AUDIO_ENCODER (enc), taglist, - GST_TAG_MERGE_REPLACE); - - gst_tag_list_unref (taglist); -} - -static void -gst_opus_enc_class_init (GstOpusEncClass * klass) -{ - GObjectClass *gobject_class; - GstAudioEncoderClass *base_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - base_class = (GstAudioEncoderClass *) klass; - gstelement_class = (GstElementClass *) klass; - - gobject_class->set_property = gst_opus_enc_set_property; - gobject_class->get_property = gst_opus_enc_get_property; - - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&src_factory)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&sink_factory)); - gst_element_class_set_static_metadata (gstelement_class, "Opus audio encoder", - "Codec/Encoder/Audio", - "Encodes audio in Opus format", - "Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>"); - - base_class->start = GST_DEBUG_FUNCPTR (gst_opus_enc_start); - base_class->stop = GST_DEBUG_FUNCPTR (gst_opus_enc_stop); - base_class->set_format = GST_DEBUG_FUNCPTR (gst_opus_enc_set_format); - base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_opus_enc_handle_frame); - base_class->sink_event = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_event); - base_class->getcaps = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_getcaps); - - g_object_class_install_property (gobject_class, PROP_AUDIO, - g_param_spec_boolean ("audio", - "Audio or voice", - "Audio or voice (DEPRECATED: use audio-type)", DEFAULT_AUDIO, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED)); - g_object_class_install_property (gobject_class, PROP_AUDIO_TYPE, - g_param_spec_enum ("audio-type", "What type of audio to optimize for", - "What type of audio to optimize for", GST_OPUS_ENC_TYPE_AUDIO_TYPE, - DEFAULT_AUDIO_TYPE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE, - g_param_spec_int ("bitrate", "Encoding Bit-rate", - "Specify an encoding bit-rate (in bps).", LOWEST_BITRATE, - HIGHEST_BITRATE, DEFAULT_BITRATE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_PLAYING)); - g_object_class_install_property (gobject_class, PROP_BANDWIDTH, - g_param_spec_enum ("bandwidth", "Band Width", "Audio Band Width", - GST_OPUS_ENC_TYPE_BANDWIDTH, DEFAULT_BANDWIDTH, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_PLAYING)); - g_object_class_install_property (gobject_class, PROP_FRAME_SIZE, - g_param_spec_enum ("frame-size", "Frame Size", - "The duration of an audio frame, in ms", GST_OPUS_ENC_TYPE_FRAME_SIZE, - DEFAULT_FRAMESIZE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_PLAYING)); - g_object_class_install_property (gobject_class, PROP_CBR, - g_param_spec_boolean ("cbr", "Constant bit rate", - "Constant bit rate (DEPRECATED: use bitrate-type)", DEFAULT_CBR, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING - | G_PARAM_DEPRECATED)); - g_object_class_install_property (gobject_class, PROP_CONSTRAINED_VBR, - g_param_spec_boolean ("constrained-vbr", "Constrained VBR", - "Constrained VBR (DEPRECATED: use bitrate-type)", - DEFAULT_CONSTRAINED_VBR, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING - | G_PARAM_DEPRECATED)); - g_object_class_install_property (gobject_class, PROP_BITRATE_TYPE, - g_param_spec_enum ("bitrate-type", "Bitrate type", "Bitrate type", - GST_OPUS_ENC_TYPE_BITRATE_TYPE, DEFAULT_BITRATE_TYPE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_PLAYING)); - g_object_class_install_property (gobject_class, PROP_COMPLEXITY, - g_param_spec_int ("complexity", "Complexity", "Complexity", 0, 10, - DEFAULT_COMPLEXITY, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_PLAYING)); - g_object_class_install_property (gobject_class, PROP_INBAND_FEC, - g_param_spec_boolean ("inband-fec", "In-band FEC", - "Enable forward error correction", DEFAULT_INBAND_FEC, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_PLAYING)); - g_object_class_install_property (gobject_class, PROP_DTX, - g_param_spec_boolean ("dtx", "DTX", "DTX", DEFAULT_DTX, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_PLAYING)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - PROP_PACKET_LOSS_PERCENT, g_param_spec_int ("packet-loss-percentage", - "Loss percentage", "Packet loss percentage", 0, 100, - DEFAULT_PACKET_LOSS_PERCENT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_PLAYING)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - PROP_MAX_PAYLOAD_SIZE, g_param_spec_uint ("max-payload-size", - "Max payload size", "Maximum payload size in bytes", 2, 4000, - DEFAULT_MAX_PAYLOAD_SIZE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_PLAYING)); - - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_opus_enc_finalize); - - GST_DEBUG_CATEGORY_INIT (opusenc_debug, "opusenc", 0, "Opus encoder"); -} - -static void -gst_opus_enc_finalize (GObject * object) -{ - GstOpusEnc *enc; - - enc = GST_OPUS_ENC (object); - - g_mutex_clear (&enc->property_lock); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_opus_enc_init (GstOpusEnc * enc) -{ - GST_DEBUG_OBJECT (enc, "init"); - - GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (enc)); - - g_mutex_init (&enc->property_lock); - - enc->n_channels = -1; - enc->sample_rate = -1; - enc->frame_samples = 0; - - enc->bitrate = DEFAULT_BITRATE; - enc->bandwidth = DEFAULT_BANDWIDTH; - enc->frame_size = DEFAULT_FRAMESIZE; - enc->bitrate_type = DEFAULT_BITRATE_TYPE; - enc->complexity = DEFAULT_COMPLEXITY; - enc->inband_fec = DEFAULT_INBAND_FEC; - enc->dtx = DEFAULT_DTX; - enc->packet_loss_percentage = DEFAULT_PACKET_LOSS_PERCENT; - enc->max_payload_size = DEFAULT_MAX_PAYLOAD_SIZE; - enc->audio_type = DEFAULT_AUDIO_TYPE; -} - -static gboolean -gst_opus_enc_start (GstAudioEncoder * benc) -{ - GstOpusEnc *enc = GST_OPUS_ENC (benc); - - GST_DEBUG_OBJECT (enc, "start"); - enc->encoded_samples = 0; - enc->consumed_samples = 0; - - return TRUE; -} - -static gboolean -gst_opus_enc_stop (GstAudioEncoder * benc) -{ - GstOpusEnc *enc = GST_OPUS_ENC (benc); - - GST_DEBUG_OBJECT (enc, "stop"); - if (enc->state) { - opus_multistream_encoder_destroy (enc->state); - enc->state = NULL; - } - gst_tag_setter_reset_tags (GST_TAG_SETTER (enc)); - - return TRUE; -} - -static gint64 -gst_opus_enc_get_latency (GstOpusEnc * enc) -{ - gint64 latency = gst_util_uint64_scale (enc->frame_samples, GST_SECOND, - enc->sample_rate); - GST_DEBUG_OBJECT (enc, "Latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); - return latency; -} - -static void -gst_opus_enc_setup_base_class (GstOpusEnc * enc, GstAudioEncoder * benc) -{ - gst_audio_encoder_set_latency (benc, - gst_opus_enc_get_latency (enc), gst_opus_enc_get_latency (enc)); - gst_audio_encoder_set_frame_samples_min (benc, enc->frame_samples); - gst_audio_encoder_set_frame_samples_max (benc, enc->frame_samples); - gst_audio_encoder_set_frame_max (benc, 1); -} - -static gint -gst_opus_enc_get_frame_samples (GstOpusEnc * enc) -{ - gint frame_samples = 0; - switch (enc->frame_size) { - case 2: - frame_samples = enc->sample_rate / 400; - break; - case 5: - frame_samples = enc->sample_rate / 200; - break; - case 10: - frame_samples = enc->sample_rate / 100; - break; - case 20: - frame_samples = enc->sample_rate / 50; - break; - case 40: - frame_samples = enc->sample_rate / 25; - break; - case 60: - frame_samples = 3 * enc->sample_rate / 50; - break; - default: - GST_WARNING_OBJECT (enc, "Unsupported frame size: %d", enc->frame_size); - frame_samples = 0; - break; - } - return frame_samples; -} - -static void -gst_opus_enc_setup_trivial_mapping (GstOpusEnc * enc, guint8 mapping[256]) -{ - int n; - - for (n = 0; n < 255; ++n) - mapping[n] = n; -} - -static int -gst_opus_enc_find_channel_position (GstOpusEnc * enc, const GstAudioInfo * info, - GstAudioChannelPosition position) -{ - int n; - for (n = 0; n < enc->n_channels; ++n) { - if (GST_AUDIO_INFO_POSITION (info, n) == position) { - return n; - } - } - return -1; -} - -static int -gst_opus_enc_find_channel_position_in_vorbis_order (GstOpusEnc * enc, - GstAudioChannelPosition position) -{ - int c; - - for (c = 0; c < enc->n_channels; ++c) { - if (gst_opus_channel_positions[enc->n_channels - 1][c] == position) { - GST_INFO_OBJECT (enc, - "Channel position %s maps to index %d in Vorbis order", - gst_opus_channel_names[position], c); - return c; - } - } - GST_WARNING_OBJECT (enc, - "Channel position %s is not representable in Vorbis order", - gst_opus_channel_names[position]); - return -1; -} - -static void -gst_opus_enc_setup_channel_mappings (GstOpusEnc * enc, - const GstAudioInfo * info) -{ -#define MAPS(idx,pos) (GST_AUDIO_INFO_POSITION (info, (idx)) == GST_AUDIO_CHANNEL_POSITION_##pos) - - int n; - - GST_DEBUG_OBJECT (enc, "Setting up channel mapping for %d channels", - enc->n_channels); - - /* Start by setting up a default trivial mapping */ - enc->n_stereo_streams = 0; - gst_opus_enc_setup_trivial_mapping (enc, enc->encoding_channel_mapping); - gst_opus_enc_setup_trivial_mapping (enc, enc->decoding_channel_mapping); - - /* For one channel, use the basic RTP mapping */ - if (enc->n_channels == 1) { - GST_INFO_OBJECT (enc, "Mono, trivial RTP mapping"); - enc->channel_mapping_family = 0; - /* implicit mapping for family 0 */ - return; - } - - /* For two channels, use the basic RTP mapping if the channels are - mapped as left/right. */ - if (enc->n_channels == 2) { - 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 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]; - static const GstAudioChannelPosition pairs[][2] = { - {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, - {GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, - {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, - {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, - 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; - - GST_DEBUG_OBJECT (enc, - "In range for the Vorbis mapping, building channel mapping tables"); - - enc->n_stereo_streams = 0; - mapped = 0; - for (n = 0; n < 256; ++n) - positions_done[n] = FALSE; - - /* First, find any natural pairs, and move them to the front */ - for (pair = 0; pair < G_N_ELEMENTS (pairs); ++pair) { - GstAudioChannelPosition p0 = pairs[pair][0]; - GstAudioChannelPosition p1 = pairs[pair][1]; - c0 = gst_opus_enc_find_channel_position (enc, info, p0); - c1 = gst_opus_enc_find_channel_position (enc, info, p1); - if (c0 >= 0 && c1 >= 0) { - /* We found a natural pair */ - GST_DEBUG_OBJECT (enc, "Natural pair '%s/%s' found at %d %d", - gst_opus_channel_names[p0], gst_opus_channel_names[p1], c0, c1); - /* Find where they map in Vorbis order */ - c0v = gst_opus_enc_find_channel_position_in_vorbis_order (enc, p0); - c1v = gst_opus_enc_find_channel_position_in_vorbis_order (enc, p1); - if (c0v < 0 || c1v < 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; - } - - enc->encoding_channel_mapping[mapped] = c0; - enc->encoding_channel_mapping[mapped + 1] = c1; - enc->decoding_channel_mapping[c0v] = mapped; - enc->decoding_channel_mapping[c1v] = mapped + 1; - enc->n_stereo_streams++; - mapped += 2; - positions_done[p0] = positions_done[p1] = TRUE; - } - } - - /* Now add all other input channels as mono streams */ - for (n = 0; n < enc->n_channels; ++n) { - GstAudioChannelPosition position = GST_AUDIO_INFO_POSITION (info, n); - - /* if we already mapped it while searching for pairs, nothing else - needs to be done */ - if (!positions_done[position]) { - int cv; - 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) - g_assert_not_reached (); - enc->encoding_channel_mapping[mapped] = n; - enc->decoding_channel_mapping[cv] = mapped; - mapped++; - } - } - -#ifndef GST_DISABLE_GST_DEBUG - GST_INFO_OBJECT (enc, - "Mapping tables built: %d channels, %d stereo streams", enc->n_channels, - enc->n_stereo_streams); - gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug, - "Encoding mapping table", enc->n_channels, - enc->encoding_channel_mapping); - gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug, - "Decoding mapping table", enc->n_channels, - enc->decoding_channel_mapping); -#endif - - enc->channel_mapping_family = 1; - return; - } - - /* More than 8 channels, if future mappings are added for those */ - - /* For other cases, we use undefined, with the default trivial mapping - and all mono streams */ - GST_WARNING_OBJECT (enc, "Unknown mapping"); - enc->channel_mapping_family = 255; - enc->n_stereo_streams = 0; - -#undef MAPS -} - -static gboolean -gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info) -{ - GstOpusEnc *enc; - - enc = GST_OPUS_ENC (benc); - - g_mutex_lock (&enc->property_lock); - - enc->n_channels = GST_AUDIO_INFO_CHANNELS (info); - enc->sample_rate = GST_AUDIO_INFO_RATE (info); - gst_opus_enc_setup_channel_mappings (enc, info); - GST_DEBUG_OBJECT (benc, "Setup with %d channels, %d Hz", enc->n_channels, - enc->sample_rate); - - /* handle reconfigure */ - if (enc->state) { - opus_multistream_encoder_destroy (enc->state); - enc->state = NULL; - } - if (!gst_opus_enc_setup (enc)) { - g_mutex_unlock (&enc->property_lock); - return FALSE; - } - - /* update the tags */ - gst_opus_enc_set_tags (enc); - - enc->frame_samples = gst_opus_enc_get_frame_samples (enc); - - /* feedback to base class */ - gst_opus_enc_setup_base_class (enc, benc); - - g_mutex_unlock (&enc->property_lock); - - return TRUE; -} - -static gboolean -gst_opus_enc_setup (GstOpusEnc * enc) -{ - int error = OPUS_OK; - GstCaps *caps; - gboolean ret; - gint32 lookahead; - const GstTagList *tags; - GstTagList *empty_tags = NULL; - GstBuffer *header, *comments; - -#ifndef GST_DISABLE_GST_DEBUG - GST_DEBUG_OBJECT (enc, - "setup: %d Hz, %d channels, %d stereo streams, family %d", - enc->sample_rate, enc->n_channels, enc->n_stereo_streams, - enc->channel_mapping_family); - GST_INFO_OBJECT (enc, "Mapping tables built: %d channels, %d stereo streams", - enc->n_channels, enc->n_stereo_streams); - gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug, - "Encoding mapping table", enc->n_channels, enc->encoding_channel_mapping); - gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug, - "Decoding mapping table", enc->n_channels, enc->decoding_channel_mapping); -#endif - - enc->state = opus_multistream_encoder_create (enc->sample_rate, - enc->n_channels, enc->n_channels - enc->n_stereo_streams, - enc->n_stereo_streams, enc->encoding_channel_mapping, - enc->audio_type, &error); - if (!enc->state || error != OPUS_OK) - goto encoder_creation_failed; - - opus_multistream_encoder_ctl (enc->state, OPUS_SET_BITRATE (enc->bitrate), 0); - opus_multistream_encoder_ctl (enc->state, OPUS_SET_BANDWIDTH (enc->bandwidth), - 0); - opus_multistream_encoder_ctl (enc->state, - OPUS_SET_VBR (enc->bitrate_type != BITRATE_TYPE_CBR), 0); - opus_multistream_encoder_ctl (enc->state, - OPUS_SET_VBR_CONSTRAINT (enc->bitrate_type == - BITRATE_TYPE_CONSTRAINED_VBR), 0); - opus_multistream_encoder_ctl (enc->state, - OPUS_SET_COMPLEXITY (enc->complexity), 0); - opus_multistream_encoder_ctl (enc->state, - OPUS_SET_INBAND_FEC (enc->inband_fec), 0); - opus_multistream_encoder_ctl (enc->state, OPUS_SET_DTX (enc->dtx), 0); - opus_multistream_encoder_ctl (enc->state, - OPUS_SET_PACKET_LOSS_PERC (enc->packet_loss_percentage), 0); - - opus_multistream_encoder_ctl (enc->state, OPUS_GET_LOOKAHEAD (&lookahead), 0); - - GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size, - lookahead); - - /* lookahead is samples, the Opus header wants it in 48kHz samples */ - lookahead = lookahead * 48000 / enc->sample_rate; - enc->lookahead = enc->pending_lookahead = lookahead; - - 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)); - if (!tags) - tags = empty_tags = gst_tag_list_new_empty (); - 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); - if (empty_tags) - gst_tag_list_unref (empty_tags); - gst_buffer_unref (header); - gst_buffer_unref (comments); - - /* negotiate with these caps */ - GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps); - - ret = gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps); - gst_caps_unref (caps); - - return ret; - -encoder_creation_failed: - GST_ERROR_OBJECT (enc, "Encoder creation failed"); - return FALSE; -} - -static gboolean -gst_opus_enc_sink_event (GstAudioEncoder * benc, GstEvent * event) -{ - GstOpusEnc *enc; - - enc = GST_OPUS_ENC (benc); - - GST_DEBUG_OBJECT (enc, "sink event: %s", GST_EVENT_TYPE_NAME (event)); - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_TAG: - { - GstTagList *list; - GstTagSetter *setter = GST_TAG_SETTER (enc); - const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter); - - gst_event_parse_tag (event, &list); - gst_tag_setter_merge_tags (setter, list, mode); - break; - } - case GST_EVENT_SEGMENT: - enc->encoded_samples = 0; - enc->consumed_samples = 0; - break; - - default: - break; - } - - return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, 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; - - enc = GST_OPUS_ENC (benc); - - GST_DEBUG_OBJECT (enc, "sink getcaps"); - - 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; -} - -static GstFlowReturn -gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) -{ - guint8 *bdata = NULL, *data, *mdata = NULL; - gsize bsize, size; - gsize bytes; - gint ret = GST_FLOW_OK; - GstMapInfo map; - GstMapInfo omap; - gint outsize; - GstBuffer *outbuf; - GstSegment *segment; - GstClockTime duration; - guint64 trim_start = 0, trim_end = 0; - - guint max_payload_size; - gint frame_samples, input_samples, output_samples; - - g_mutex_lock (&enc->property_lock); - - bytes = enc->frame_samples * enc->n_channels * 2; - max_payload_size = enc->max_payload_size; - frame_samples = input_samples = enc->frame_samples; - - g_mutex_unlock (&enc->property_lock); - - if (G_LIKELY (buf)) { - gst_buffer_map (buf, &map, GST_MAP_READ); - bdata = map.data; - bsize = map.size; - - if (G_UNLIKELY (bsize % bytes)) { - gint64 diff; - - GST_DEBUG_OBJECT (enc, "draining; adding silence samples"); - g_assert (bsize < bytes); - - /* If encoding part of a frame, and we have no set stop time on - * the output segment, we update the segment stop time to reflect - * the last sample. This will let oggmux set the last page's - * granpos to tell a decoder the dummy samples should be clipped. - */ - input_samples = bsize / (enc->n_channels * 2); - segment = &GST_AUDIO_ENCODER_OUTPUT_SEGMENT (enc); - if (!GST_CLOCK_TIME_IS_VALID (segment->stop)) { - GST_DEBUG_OBJECT (enc, - "No stop time and partial frame, updating segment"); - duration = - gst_util_uint64_scale_ceil (enc->consumed_samples + input_samples, - GST_SECOND, enc->sample_rate); - segment->stop = segment->start + duration; - GST_DEBUG_OBJECT (enc, "new output segment %" GST_SEGMENT_FORMAT, - segment); - gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (enc), - gst_event_new_segment (segment)); - } - - diff = - (enc->encoded_samples + frame_samples) - (enc->consumed_samples + - input_samples); - if (diff >= 0) { - GST_DEBUG_OBJECT (enc, - "%" G_GINT64_FORMAT " extra samples of padding in this frame", - diff); - output_samples = frame_samples - diff; - trim_end = diff * 48000 / enc->sample_rate; - } else { - GST_DEBUG_OBJECT (enc, - "Need to add %" G_GINT64_FORMAT " extra samples in the next frame", - -diff); - output_samples = frame_samples; - } - - size = ((bsize / bytes) + 1) * bytes; - mdata = g_malloc0 (size); - /* FIXME: Instead of silence, use LPC with the last real samples. - * Otherwise we will create a discontinuity here, which will distort the - * last few encoded samples - */ - memcpy (mdata, bdata, bsize); - data = mdata; - } else { - data = bdata; - size = bsize; - - /* Adjust for lookahead here */ - if (enc->pending_lookahead) { - guint scaled_lookahead = - enc->pending_lookahead * enc->sample_rate / 48000; - - if (input_samples > scaled_lookahead) { - output_samples = input_samples - scaled_lookahead; - trim_start = enc->pending_lookahead; - enc->pending_lookahead = 0; - } else { - trim_start = ((guint64) input_samples) * 48000 / enc->sample_rate; - enc->pending_lookahead -= trim_start; - output_samples = 0; - } - } else { - output_samples = input_samples; - } - } - } else { - if (enc->encoded_samples < enc->consumed_samples) { - /* FIXME: Instead of silence, use LPC with the last real samples. - * Otherwise we will create a discontinuity here, which will distort the - * last few encoded samples - */ - data = mdata = g_malloc0 (bytes); - size = bytes; - output_samples = enc->consumed_samples - enc->encoded_samples; - input_samples = 0; - GST_DEBUG_OBJECT (enc, "draining %d samples", output_samples); - trim_end = - ((guint64) frame_samples - output_samples) * 48000 / enc->sample_rate; - } else if (enc->encoded_samples == enc->consumed_samples) { - GST_DEBUG_OBJECT (enc, "nothing to drain"); - goto done; - } else { - g_assert_not_reached (); - goto done; - } - } - - g_assert (size == bytes); - - outbuf = - gst_audio_encoder_allocate_output_buffer (GST_AUDIO_ENCODER (enc), - max_payload_size * enc->n_channels); - if (!outbuf) - goto done; - - GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", - frame_samples, (int) bytes); - - if (trim_start || trim_end) { - GST_DEBUG_OBJECT (enc, - "Adding trim-start %" G_GUINT64_FORMAT " trim-end %" G_GUINT64_FORMAT, - trim_start, trim_end); - gst_buffer_add_audio_clipping_meta (outbuf, GST_FORMAT_DEFAULT, trim_start, - trim_end); - } - - gst_buffer_map (outbuf, &omap, GST_MAP_WRITE); - - outsize = - opus_multistream_encode (enc->state, (const gint16 *) data, - frame_samples, omap.data, max_payload_size * enc->n_channels); - - gst_buffer_unmap (outbuf, &omap); - - if (outsize < 0) { - GST_ERROR_OBJECT (enc, "Encoding failed: %d", outsize); - ret = GST_FLOW_ERROR; - goto done; - } else if (outsize > max_payload_size) { - GST_WARNING_OBJECT (enc, - "Encoded size %d is higher than max payload size (%d bytes)", - outsize, max_payload_size); - ret = GST_FLOW_ERROR; - goto done; - } - - GST_DEBUG_OBJECT (enc, "Output packet is %u bytes", outsize); - gst_buffer_set_size (outbuf, outsize); - - - ret = - gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc), outbuf, - output_samples); - enc->encoded_samples += output_samples; - enc->consumed_samples += input_samples; - -done: - - if (bdata) - gst_buffer_unmap (buf, &map); - - g_free (mdata); - - return ret; -} - -static GstFlowReturn -gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf) -{ - GstOpusEnc *enc; - GstFlowReturn ret = GST_FLOW_OK; - - enc = GST_OPUS_ENC (benc); - GST_DEBUG_OBJECT (enc, "handle_frame"); - GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf, - buf ? gst_buffer_get_size (buf) : 0); - - ret = gst_opus_enc_encode (enc, buf); - - return ret; -} - -static void -gst_opus_enc_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstOpusEnc *enc; - - enc = GST_OPUS_ENC (object); - - g_mutex_lock (&enc->property_lock); - - switch (prop_id) { - case PROP_AUDIO: - g_value_set_boolean (value, - enc->audio_type == OPUS_APPLICATION_AUDIO ? TRUE : FALSE); - break; - case PROP_AUDIO_TYPE: - g_value_set_enum (value, enc->audio_type); - break; - case PROP_BITRATE: - g_value_set_int (value, enc->bitrate); - break; - case PROP_BANDWIDTH: - g_value_set_enum (value, enc->bandwidth); - break; - case PROP_FRAME_SIZE: - g_value_set_enum (value, enc->frame_size); - break; - case PROP_CBR: - GST_WARNING_OBJECT (enc, - "cbr property is deprecated; use bitrate-type instead"); - g_value_set_boolean (value, enc->bitrate_type == BITRATE_TYPE_CBR); - break; - case PROP_CONSTRAINED_VBR: - GST_WARNING_OBJECT (enc, - "constrained-vbr property is deprecated; use bitrate-type instead"); - g_value_set_boolean (value, - enc->bitrate_type == BITRATE_TYPE_CONSTRAINED_VBR); - break; - case PROP_BITRATE_TYPE: - g_value_set_enum (value, enc->bitrate_type); - break; - case PROP_COMPLEXITY: - g_value_set_int (value, enc->complexity); - break; - case PROP_INBAND_FEC: - g_value_set_boolean (value, enc->inband_fec); - break; - case PROP_DTX: - g_value_set_boolean (value, enc->dtx); - break; - case PROP_PACKET_LOSS_PERCENT: - g_value_set_int (value, enc->packet_loss_percentage); - break; - case PROP_MAX_PAYLOAD_SIZE: - g_value_set_uint (value, enc->max_payload_size); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - g_mutex_unlock (&enc->property_lock); -} - -static void -gst_opus_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstOpusEnc *enc; - - enc = GST_OPUS_ENC (object); - -#define GST_OPUS_UPDATE_PROPERTY(prop,type,ctl) do { \ - g_mutex_lock (&enc->property_lock); \ - enc->prop = g_value_get_##type (value); \ - if (enc->state) { \ - opus_multistream_encoder_ctl (enc->state, OPUS_SET_##ctl (enc->prop)); \ - } \ - g_mutex_unlock (&enc->property_lock); \ -} while(0) - - switch (prop_id) { - case PROP_AUDIO: - enc->audio_type = - g_value_get_boolean (value) ? OPUS_APPLICATION_AUDIO : - OPUS_APPLICATION_VOIP; - break; - case PROP_AUDIO_TYPE: - enc->audio_type = g_value_get_enum (value); - break; - case PROP_BITRATE: - GST_OPUS_UPDATE_PROPERTY (bitrate, int, BITRATE); - break; - case PROP_BANDWIDTH: - GST_OPUS_UPDATE_PROPERTY (bandwidth, enum, BANDWIDTH); - break; - case PROP_FRAME_SIZE: - g_mutex_lock (&enc->property_lock); - enc->frame_size = g_value_get_enum (value); - enc->frame_samples = gst_opus_enc_get_frame_samples (enc); - gst_opus_enc_setup_base_class (enc, GST_AUDIO_ENCODER (enc)); - g_mutex_unlock (&enc->property_lock); - break; - case PROP_CBR: - GST_WARNING_OBJECT (enc, - "cbr property is deprecated; use bitrate-type instead"); - g_warning ("cbr property is deprecated; use bitrate-type instead"); - g_mutex_lock (&enc->property_lock); - enc->bitrate_type = BITRATE_TYPE_CBR; - if (enc->state) { - opus_multistream_encoder_ctl (enc->state, OPUS_SET_VBR (FALSE)); - opus_multistream_encoder_ctl (enc->state, - OPUS_SET_VBR_CONSTRAINT (FALSE), 0); - } - g_mutex_unlock (&enc->property_lock); - break; - case PROP_CONSTRAINED_VBR: - GST_WARNING_OBJECT (enc, - "constrained-vbr property is deprecated; use bitrate-type instead"); - g_warning - ("constrained-vbr property is deprecated; use bitrate-type instead"); - g_mutex_lock (&enc->property_lock); - enc->bitrate_type = BITRATE_TYPE_CONSTRAINED_VBR; - if (enc->state) { - opus_multistream_encoder_ctl (enc->state, OPUS_SET_VBR (TRUE)); - opus_multistream_encoder_ctl (enc->state, - OPUS_SET_VBR_CONSTRAINT (TRUE), 0); - } - g_mutex_unlock (&enc->property_lock); - break; - case PROP_BITRATE_TYPE: - /* this one has an opposite meaning to the opus ctl... */ - g_mutex_lock (&enc->property_lock); - enc->bitrate_type = g_value_get_enum (value); - if (enc->state) { - opus_multistream_encoder_ctl (enc->state, - OPUS_SET_VBR (enc->bitrate_type != BITRATE_TYPE_CBR)); - opus_multistream_encoder_ctl (enc->state, - OPUS_SET_VBR_CONSTRAINT (enc->bitrate_type == - BITRATE_TYPE_CONSTRAINED_VBR), 0); - } - g_mutex_unlock (&enc->property_lock); - break; - case PROP_COMPLEXITY: - GST_OPUS_UPDATE_PROPERTY (complexity, int, COMPLEXITY); - break; - case PROP_INBAND_FEC: - GST_OPUS_UPDATE_PROPERTY (inband_fec, boolean, INBAND_FEC); - break; - case PROP_DTX: - GST_OPUS_UPDATE_PROPERTY (dtx, boolean, DTX); - break; - case PROP_PACKET_LOSS_PERCENT: - GST_OPUS_UPDATE_PROPERTY (packet_loss_percentage, int, PACKET_LOSS_PERC); - break; - case PROP_MAX_PAYLOAD_SIZE: - g_mutex_lock (&enc->property_lock); - enc->max_payload_size = g_value_get_uint (value); - g_mutex_unlock (&enc->property_lock); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - -#undef GST_OPUS_UPDATE_PROPERTY - -} diff --git a/ext/opus/gstopusenc.h b/ext/opus/gstopusenc.h deleted file mode 100644 index f447292af..000000000 --- a/ext/opus/gstopusenc.h +++ /dev/null @@ -1,102 +0,0 @@ -/* GStreamer Opus Encoder - * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> - * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk> - * Copyright (C) <2011-2012> Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - - -#ifndef __GST_OPUS_ENC_H__ -#define __GST_OPUS_ENC_H__ - - -#include <gst/gst.h> -#include <gst/audio/gstaudioencoder.h> - -#include <opus_multistream.h> - -G_BEGIN_DECLS - -#define GST_TYPE_OPUS_ENC \ - (gst_opus_enc_get_type()) -#define GST_OPUS_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OPUS_ENC,GstOpusEnc)) -#define GST_OPUS_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OPUS_ENC,GstOpusEncClass)) -#define GST_IS_OPUS_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OPUS_ENC)) -#define GST_IS_OPUS_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OPUS_ENC)) - -#define MAX_FRAME_SIZE 2000*2 -#define MAX_FRAME_BYTES 2000 - -typedef enum -{ - BITRATE_TYPE_CBR, - BITRATE_TYPE_VBR, - BITRATE_TYPE_CONSTRAINED_VBR, -} GstOpusEncBitrateType; - -typedef struct _GstOpusEnc GstOpusEnc; -typedef struct _GstOpusEncClass GstOpusEncClass; - -struct _GstOpusEnc { - GstAudioEncoder element; - - OpusMSEncoder *state; - - /* Locks those properties which may be changed at play time */ - GMutex property_lock; - - /* properties */ - gint audio_type; - gint bitrate; - gint bandwidth; - gint frame_size; - GstOpusEncBitrateType bitrate_type; - gint complexity; - gboolean inband_fec; - gboolean dtx; - gint packet_loss_percentage; - guint max_payload_size; - - gint frame_samples; - gint n_channels; - gint sample_rate; - - guint64 encoded_samples, consumed_samples; - guint16 lookahead, pending_lookahead; - - guint8 channel_mapping_family; - guint8 encoding_channel_mapping[256]; - guint8 decoding_channel_mapping[256]; - guint8 n_stereo_streams; -}; - -struct _GstOpusEncClass { - GstAudioEncoderClass parent_class; - - /* signals */ - void (*frame_encoded) (GstElement *element); -}; - -GType gst_opus_enc_get_type (void); - -G_END_DECLS - -#endif /* __GST_OPUS_ENC_H__ */ |