Blame ext/opus/gstopusenc.c

Packit 971217
/* GStreamer Opus Encoder
Packit 971217
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
Packit 971217
 * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
Packit 971217
 * Copyright (C) <2011> Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
Packit 971217
/*
Packit 971217
 * Based on the speexenc element
Packit 971217
 */
Packit 971217
Packit 971217
/**
Packit 971217
 * SECTION:element-opusenc
Packit 971217
 * @title: opusenc
Packit 971217
 * @see_also: opusdec, oggmux
Packit 971217
 *
Packit 971217
 * This element encodes raw audio to OPUS.
Packit 971217
 *
Packit 971217
 * ## Example pipelines
Packit 971217
 * |[
Packit 971217
 * gst-launch-1.0 -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! opusenc ! oggmux ! filesink location=sine.ogg
Packit 971217
 * ]|
Packit 971217
 * Encode a test sine signal to Ogg/OPUS.
Packit 971217
 *
Packit 971217
 */
Packit 971217
Packit 971217
#ifdef HAVE_CONFIG_H
Packit 971217
#include "config.h"
Packit 971217
#endif
Packit 971217
#include <stdlib.h>
Packit 971217
#include <string.h>
Packit 971217
#include <time.h>
Packit 971217
#include <math.h>
Packit 971217
#include <opus.h>
Packit 971217
Packit 971217
#include <gst/gsttagsetter.h>
Packit 971217
#include <gst/audio/audio.h>
Packit 971217
#include <gst/pbutils/pbutils.h>
Packit 971217
#include <gst/tag/tag.h>
Packit 971217
#include <gst/glib-compat-private.h>
Packit 971217
#include "gstopusheader.h"
Packit 971217
#include "gstopuscommon.h"
Packit 971217
#include "gstopusenc.h"
Packit 971217
Packit 971217
GST_DEBUG_CATEGORY_STATIC (opusenc_debug);
Packit 971217
#define GST_CAT_DEFAULT opusenc_debug
Packit 971217
Packit 971217
/* Some arbitrary bounds beyond which it really doesn't make sense.
Packit 971217
   The spec mentions 6 kb/s to 510 kb/s, so 4000 and 650000 ought to be
Packit 971217
   safe as property bounds. */
Packit 971217
#define LOWEST_BITRATE 4000
Packit 971217
#define HIGHEST_BITRATE 650000
Packit 971217
Packit 971217
#define GST_OPUS_ENC_TYPE_BANDWIDTH (gst_opus_enc_bandwidth_get_type())
Packit 971217
static GType
Packit 971217
gst_opus_enc_bandwidth_get_type (void)
Packit 971217
{
Packit 971217
  static const GEnumValue values[] = {
Packit 971217
    {OPUS_BANDWIDTH_NARROWBAND, "Narrow band", "narrowband"},
Packit 971217
    {OPUS_BANDWIDTH_MEDIUMBAND, "Medium band", "mediumband"},
Packit 971217
    {OPUS_BANDWIDTH_WIDEBAND, "Wide band", "wideband"},
Packit 971217
    {OPUS_BANDWIDTH_SUPERWIDEBAND, "Super wide band", "superwideband"},
Packit 971217
    {OPUS_BANDWIDTH_FULLBAND, "Full band", "fullband"},
Packit 971217
    {OPUS_AUTO, "Auto", "auto"},
Packit 971217
    {0, NULL, NULL}
Packit 971217
  };
Packit 971217
  static volatile GType id = 0;
Packit 971217
Packit 971217
  if (g_once_init_enter ((gsize *) & id)) {
Packit 971217
    GType _id;
Packit 971217
Packit 971217
    _id = g_enum_register_static ("GstOpusEncBandwidth", values);
Packit 971217
Packit 971217
    g_once_init_leave ((gsize *) & id, _id);
Packit 971217
  }
Packit 971217
Packit 971217
  return id;
Packit 971217
}
Packit 971217
Packit 971217
#define GST_OPUS_ENC_TYPE_FRAME_SIZE (gst_opus_enc_frame_size_get_type())
Packit 971217
static GType
Packit 971217
gst_opus_enc_frame_size_get_type (void)
Packit 971217
{
Packit 971217
  static const GEnumValue values[] = {
Packit 971217
    {2, "2.5", "2.5"},
Packit 971217
    {5, "5", "5"},
Packit 971217
    {10, "10", "10"},
Packit 971217
    {20, "20", "20"},
Packit 971217
    {40, "40", "40"},
Packit 971217
    {60, "60", "60"},
Packit 971217
    {0, NULL, NULL}
Packit 971217
  };
Packit 971217
  static volatile GType id = 0;
Packit 971217
Packit 971217
  if (g_once_init_enter ((gsize *) & id)) {
Packit 971217
    GType _id;
Packit 971217
Packit 971217
    _id = g_enum_register_static ("GstOpusEncFrameSize", values);
Packit 971217
Packit 971217
    g_once_init_leave ((gsize *) & id, _id);
Packit 971217
  }
Packit 971217
Packit 971217
  return id;
Packit 971217
}
Packit 971217
Packit 971217
#define GST_OPUS_ENC_TYPE_AUDIO_TYPE (gst_opus_enc_audio_type_get_type())
Packit 971217
static GType
Packit 971217
gst_opus_enc_audio_type_get_type (void)
Packit 971217
{
Packit 971217
  static const GEnumValue values[] = {
Packit 971217
    {OPUS_APPLICATION_AUDIO, "Generic audio", "generic"},
Packit 971217
    {OPUS_APPLICATION_VOIP, "Voice", "voice"},
Packit 971217
    {0, NULL, NULL}
Packit 971217
  };
Packit 971217
  static volatile GType id = 0;
Packit 971217
Packit 971217
  if (g_once_init_enter ((gsize *) & id)) {
Packit 971217
    GType _id;
Packit 971217
Packit 971217
    _id = g_enum_register_static ("GstOpusEncAudioType", values);
Packit 971217
Packit 971217
    g_once_init_leave ((gsize *) & id, _id);
Packit 971217
  }
Packit 971217
Packit 971217
  return id;
Packit 971217
}
Packit 971217
Packit 971217
#define GST_OPUS_ENC_TYPE_BITRATE_TYPE (gst_opus_enc_bitrate_type_get_type())
Packit 971217
static GType
Packit 971217
gst_opus_enc_bitrate_type_get_type (void)
Packit 971217
{
Packit 971217
  static const GEnumValue values[] = {
Packit 971217
    {BITRATE_TYPE_CBR, "CBR", "cbr"},
Packit 971217
    {BITRATE_TYPE_VBR, "VBR", "vbr"},
Packit 971217
    {BITRATE_TYPE_CONSTRAINED_VBR, "Constrained VBR", "constrained-vbr"},
Packit 971217
    {0, NULL, NULL}
Packit 971217
  };
Packit 971217
  static volatile GType id = 0;
Packit 971217
Packit 971217
  if (g_once_init_enter ((gsize *) & id)) {
Packit 971217
    GType _id;
Packit 971217
Packit 971217
    _id = g_enum_register_static ("GstOpusEncBitrateType", values);
Packit 971217
Packit 971217
    g_once_init_leave ((gsize *) & id, _id);
Packit 971217
  }
Packit 971217
Packit 971217
  return id;
Packit 971217
}
Packit 971217
Packit 971217
#define FORMAT_STR GST_AUDIO_NE(S16)
Packit 971217
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
Packit 971217
    GST_PAD_SINK,
Packit 971217
    GST_PAD_ALWAYS,
Packit 971217
    GST_STATIC_CAPS ("audio/x-raw, "
Packit 971217
        "format = (string) " FORMAT_STR ", "
Packit 971217
        "layout = (string) interleaved, "
Packit 971217
        "rate = (int) 48000, "
Packit 971217
        "channels = (int) [ 1, 8 ]; "
Packit 971217
        "audio/x-raw, "
Packit 971217
        "format = (string) " FORMAT_STR ", "
Packit 971217
        "layout = (string) interleaved, "
Packit 971217
        "rate = (int) { 8000, 12000, 16000, 24000 }, "
Packit 971217
        "channels = (int) [ 1, 8 ] ")
Packit 971217
    );
Packit 971217
Packit 971217
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
Packit 971217
    GST_PAD_SRC,
Packit 971217
    GST_PAD_ALWAYS,
Packit 971217
    GST_STATIC_CAPS ("audio/x-opus")
Packit 971217
    );
Packit 971217
Packit 971217
#define DEFAULT_AUDIO           TRUE
Packit 971217
#define DEFAULT_AUDIO_TYPE      OPUS_APPLICATION_AUDIO
Packit 971217
#define DEFAULT_BITRATE         64000
Packit 971217
#define DEFAULT_BANDWIDTH       OPUS_BANDWIDTH_FULLBAND
Packit 971217
#define DEFAULT_FRAMESIZE       20
Packit 971217
#define DEFAULT_CBR             TRUE
Packit 971217
#define DEFAULT_CONSTRAINED_VBR TRUE
Packit 971217
#define DEFAULT_BITRATE_TYPE    BITRATE_TYPE_CBR
Packit 971217
#define DEFAULT_COMPLEXITY      10
Packit 971217
#define DEFAULT_INBAND_FEC      FALSE
Packit 971217
#define DEFAULT_DTX             FALSE
Packit 971217
#define DEFAULT_PACKET_LOSS_PERCENT 0
Packit 971217
#define DEFAULT_MAX_PAYLOAD_SIZE 4000
Packit 971217
Packit 971217
enum
Packit 971217
{
Packit 971217
  PROP_0,
Packit 971217
  PROP_AUDIO_TYPE,
Packit 971217
  PROP_BITRATE,
Packit 971217
  PROP_BANDWIDTH,
Packit 971217
  PROP_FRAME_SIZE,
Packit 971217
  PROP_BITRATE_TYPE,
Packit 971217
  PROP_COMPLEXITY,
Packit 971217
  PROP_INBAND_FEC,
Packit 971217
  PROP_DTX,
Packit 971217
  PROP_PACKET_LOSS_PERCENT,
Packit 971217
  PROP_MAX_PAYLOAD_SIZE
Packit 971217
};
Packit 971217
Packit 971217
static void gst_opus_enc_finalize (GObject * object);
Packit 971217
Packit 971217
static gboolean gst_opus_enc_sink_event (GstAudioEncoder * benc,
Packit 971217
    GstEvent * event);
Packit 971217
static GstCaps *gst_opus_enc_sink_getcaps (GstAudioEncoder * benc,
Packit 971217
    GstCaps * filter);
Packit 971217
static gboolean gst_opus_enc_setup (GstOpusEnc * enc);
Packit 971217
Packit 971217
static void gst_opus_enc_get_property (GObject * object, guint prop_id,
Packit 971217
    GValue * value, GParamSpec * pspec);
Packit 971217
static void gst_opus_enc_set_property (GObject * object, guint prop_id,
Packit 971217
    const GValue * value, GParamSpec * pspec);
Packit 971217
Packit 971217
static void gst_opus_enc_set_tags (GstOpusEnc * enc);
Packit 971217
static gboolean gst_opus_enc_start (GstAudioEncoder * benc);
Packit 971217
static gboolean gst_opus_enc_stop (GstAudioEncoder * benc);
Packit 971217
static gboolean gst_opus_enc_set_format (GstAudioEncoder * benc,
Packit 971217
    GstAudioInfo * info);
Packit 971217
static GstFlowReturn gst_opus_enc_handle_frame (GstAudioEncoder * benc,
Packit 971217
    GstBuffer * buf);
Packit 971217
static gint64 gst_opus_enc_get_latency (GstOpusEnc * enc);
Packit 971217
Packit 971217
static GstFlowReturn gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buffer);
Packit 971217
Packit 971217
#define gst_opus_enc_parent_class parent_class
Packit 971217
G_DEFINE_TYPE_WITH_CODE (GstOpusEnc, gst_opus_enc, GST_TYPE_AUDIO_ENCODER,
Packit 971217
    G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
Packit 971217
    G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
Packit 971217
Packit 971217
static void
Packit 971217
gst_opus_enc_set_tags (GstOpusEnc * enc)
Packit 971217
{
Packit 971217
  GstTagList *taglist;
Packit 971217
Packit 971217
  /* create a taglist and add a bitrate tag to it */
Packit 971217
  taglist = gst_tag_list_new_empty ();
Packit 971217
  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
Packit 971217
      GST_TAG_BITRATE, enc->bitrate, NULL);
Packit 971217
Packit 971217
  gst_audio_encoder_merge_tags (GST_AUDIO_ENCODER (enc), taglist,
Packit 971217
      GST_TAG_MERGE_REPLACE);
Packit 971217
Packit 971217
  gst_tag_list_unref (taglist);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_opus_enc_class_init (GstOpusEncClass * klass)
Packit 971217
{
Packit 971217
  GObjectClass *gobject_class;
Packit 971217
  GstAudioEncoderClass *base_class;
Packit 971217
  GstElementClass *gstelement_class;
Packit 971217
Packit 971217
  gobject_class = (GObjectClass *) klass;
Packit 971217
  base_class = (GstAudioEncoderClass *) klass;
Packit 971217
  gstelement_class = (GstElementClass *) klass;
Packit 971217
Packit 971217
  gobject_class->set_property = gst_opus_enc_set_property;
Packit 971217
  gobject_class->get_property = gst_opus_enc_get_property;
Packit 971217
Packit 971217
  gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
Packit 971217
  gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
Packit 971217
  gst_element_class_set_static_metadata (gstelement_class, "Opus audio encoder",
Packit 971217
      "Codec/Encoder/Audio",
Packit 971217
      "Encodes audio in Opus format",
Packit 971217
      "Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>");
Packit 971217
Packit 971217
  base_class->start = GST_DEBUG_FUNCPTR (gst_opus_enc_start);
Packit 971217
  base_class->stop = GST_DEBUG_FUNCPTR (gst_opus_enc_stop);
Packit 971217
  base_class->set_format = GST_DEBUG_FUNCPTR (gst_opus_enc_set_format);
Packit 971217
  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_opus_enc_handle_frame);
Packit 971217
  base_class->sink_event = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_event);
Packit 971217
  base_class->getcaps = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_getcaps);
Packit 971217
Packit 971217
  g_object_class_install_property (gobject_class, PROP_AUDIO_TYPE,
Packit 971217
      g_param_spec_enum ("audio-type", "What type of audio to optimize for",
Packit 971217
          "What type of audio to optimize for", GST_OPUS_ENC_TYPE_AUDIO_TYPE,
Packit 971217
          DEFAULT_AUDIO_TYPE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
Packit 971217
      g_param_spec_int ("bitrate", "Encoding Bit-rate",
Packit 971217
          "Specify an encoding bit-rate (in bps).", LOWEST_BITRATE,
Packit 971217
          HIGHEST_BITRATE, DEFAULT_BITRATE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
Packit 971217
          GST_PARAM_MUTABLE_PLAYING));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_BANDWIDTH,
Packit 971217
      g_param_spec_enum ("bandwidth", "Band Width", "Audio Band Width",
Packit 971217
          GST_OPUS_ENC_TYPE_BANDWIDTH, DEFAULT_BANDWIDTH,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
Packit 971217
          GST_PARAM_MUTABLE_PLAYING));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_FRAME_SIZE,
Packit 971217
      g_param_spec_enum ("frame-size", "Frame Size",
Packit 971217
          "The duration of an audio frame, in ms", GST_OPUS_ENC_TYPE_FRAME_SIZE,
Packit 971217
          DEFAULT_FRAMESIZE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
Packit 971217
          GST_PARAM_MUTABLE_PLAYING));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_BITRATE_TYPE,
Packit 971217
      g_param_spec_enum ("bitrate-type", "Bitrate type", "Bitrate type",
Packit 971217
          GST_OPUS_ENC_TYPE_BITRATE_TYPE, DEFAULT_BITRATE_TYPE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
Packit 971217
          GST_PARAM_MUTABLE_PLAYING));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_COMPLEXITY,
Packit 971217
      g_param_spec_int ("complexity", "Complexity", "Complexity", 0, 10,
Packit 971217
          DEFAULT_COMPLEXITY,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
Packit 971217
          GST_PARAM_MUTABLE_PLAYING));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_INBAND_FEC,
Packit 971217
      g_param_spec_boolean ("inband-fec", "In-band FEC",
Packit 971217
          "Enable forward error correction", DEFAULT_INBAND_FEC,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
Packit 971217
          GST_PARAM_MUTABLE_PLAYING));
Packit 971217
  g_object_class_install_property (gobject_class, PROP_DTX,
Packit 971217
      g_param_spec_boolean ("dtx", "DTX", "DTX", DEFAULT_DTX,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
Packit 971217
          GST_PARAM_MUTABLE_PLAYING));
Packit 971217
  g_object_class_install_property (G_OBJECT_CLASS (klass),
Packit 971217
      PROP_PACKET_LOSS_PERCENT, g_param_spec_int ("packet-loss-percentage",
Packit 971217
          "Loss percentage", "Packet loss percentage", 0, 100,
Packit 971217
          DEFAULT_PACKET_LOSS_PERCENT,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
Packit 971217
          GST_PARAM_MUTABLE_PLAYING));
Packit 971217
  g_object_class_install_property (G_OBJECT_CLASS (klass),
Packit 971217
      PROP_MAX_PAYLOAD_SIZE, g_param_spec_uint ("max-payload-size",
Packit 971217
          "Max payload size", "Maximum payload size in bytes", 2, 4000,
Packit 971217
          DEFAULT_MAX_PAYLOAD_SIZE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
Packit 971217
          GST_PARAM_MUTABLE_PLAYING));
Packit 971217
Packit 971217
  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_opus_enc_finalize);
Packit 971217
Packit 971217
  GST_DEBUG_CATEGORY_INIT (opusenc_debug, "opusenc", 0, "Opus encoder");
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_opus_enc_finalize (GObject * object)
Packit 971217
{
Packit 971217
  GstOpusEnc *enc;
Packit 971217
Packit 971217
  enc = GST_OPUS_ENC (object);
Packit 971217
Packit 971217
  g_mutex_clear (&enc->property_lock);
Packit 971217
Packit 971217
  G_OBJECT_CLASS (parent_class)->finalize (object);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_opus_enc_init (GstOpusEnc * enc)
Packit 971217
{
Packit 971217
  GST_DEBUG_OBJECT (enc, "init");
Packit 971217
Packit 971217
  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (enc));
Packit 971217
Packit 971217
  g_mutex_init (&enc->property_lock);
Packit 971217
Packit 971217
  enc->n_channels = -1;
Packit 971217
  enc->sample_rate = -1;
Packit 971217
  enc->frame_samples = 0;
Packit 971217
  enc->unpositioned = FALSE;
Packit 971217
Packit 971217
  enc->bitrate = DEFAULT_BITRATE;
Packit 971217
  enc->bandwidth = DEFAULT_BANDWIDTH;
Packit 971217
  enc->frame_size = DEFAULT_FRAMESIZE;
Packit 971217
  enc->bitrate_type = DEFAULT_BITRATE_TYPE;
Packit 971217
  enc->complexity = DEFAULT_COMPLEXITY;
Packit 971217
  enc->inband_fec = DEFAULT_INBAND_FEC;
Packit 971217
  enc->dtx = DEFAULT_DTX;
Packit 971217
  enc->packet_loss_percentage = DEFAULT_PACKET_LOSS_PERCENT;
Packit 971217
  enc->max_payload_size = DEFAULT_MAX_PAYLOAD_SIZE;
Packit 971217
  enc->audio_type = DEFAULT_AUDIO_TYPE;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_opus_enc_start (GstAudioEncoder * benc)
Packit 971217
{
Packit 971217
  GstOpusEnc *enc = GST_OPUS_ENC (benc);
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (enc, "start");
Packit 971217
  enc->encoded_samples = 0;
Packit 971217
  enc->consumed_samples = 0;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_opus_enc_stop (GstAudioEncoder * benc)
Packit 971217
{
Packit 971217
  GstOpusEnc *enc = GST_OPUS_ENC (benc);
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (enc, "stop");
Packit 971217
  if (enc->state) {
Packit 971217
    opus_multistream_encoder_destroy (enc->state);
Packit 971217
    enc->state = NULL;
Packit 971217
  }
Packit 971217
  gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
static gint64
Packit 971217
gst_opus_enc_get_latency (GstOpusEnc * enc)
Packit 971217
{
Packit 971217
  gint64 latency = gst_util_uint64_scale (enc->frame_samples, GST_SECOND,
Packit 971217
      enc->sample_rate);
Packit 971217
  GST_DEBUG_OBJECT (enc, "Latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
Packit 971217
  return latency;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_opus_enc_setup_base_class (GstOpusEnc * enc, GstAudioEncoder * benc)
Packit 971217
{
Packit 971217
  gst_audio_encoder_set_latency (benc,
Packit 971217
      gst_opus_enc_get_latency (enc), gst_opus_enc_get_latency (enc));
Packit 971217
  gst_audio_encoder_set_frame_samples_min (benc, enc->frame_samples);
Packit 971217
  gst_audio_encoder_set_frame_samples_max (benc, enc->frame_samples);
Packit 971217
  gst_audio_encoder_set_frame_max (benc, 1);
Packit 971217
}
Packit 971217
Packit 971217
static gint
Packit 971217
gst_opus_enc_get_frame_samples (GstOpusEnc * enc)
Packit 971217
{
Packit 971217
  gint frame_samples = 0;
Packit 971217
  switch (enc->frame_size) {
Packit 971217
    case 2:
Packit 971217
      frame_samples = enc->sample_rate / 400;
Packit 971217
      break;
Packit 971217
    case 5:
Packit 971217
      frame_samples = enc->sample_rate / 200;
Packit 971217
      break;
Packit 971217
    case 10:
Packit 971217
      frame_samples = enc->sample_rate / 100;
Packit 971217
      break;
Packit 971217
    case 20:
Packit 971217
      frame_samples = enc->sample_rate / 50;
Packit 971217
      break;
Packit 971217
    case 40:
Packit 971217
      frame_samples = enc->sample_rate / 25;
Packit 971217
      break;
Packit 971217
    case 60:
Packit 971217
      frame_samples = 3 * enc->sample_rate / 50;
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      GST_WARNING_OBJECT (enc, "Unsupported frame size: %d", enc->frame_size);
Packit 971217
      frame_samples = 0;
Packit 971217
      break;
Packit 971217
  }
Packit 971217
  return frame_samples;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_opus_enc_setup_trivial_mapping (GstOpusEnc * enc, guint8 mapping[256])
Packit 971217
{
Packit 971217
  int n;
Packit 971217
Packit 971217
  for (n = 0; n < 255; ++n)
Packit 971217
    mapping[n] = n;
Packit 971217
}
Packit 971217
Packit 971217
static int
Packit 971217
gst_opus_enc_find_channel_position (GstOpusEnc * enc, const GstAudioInfo * info,
Packit 971217
    GstAudioChannelPosition position)
Packit 971217
{
Packit 971217
  int n;
Packit 971217
  for (n = 0; n < enc->n_channels; ++n) {
Packit 971217
    if (GST_AUDIO_INFO_POSITION (info, n) == position) {
Packit 971217
      return n;
Packit 971217
    }
Packit 971217
  }
Packit 971217
  return -1;
Packit 971217
}
Packit 971217
Packit 971217
static int
Packit 971217
gst_opus_enc_find_channel_position_in_vorbis_order (GstOpusEnc * enc,
Packit 971217
    GstAudioChannelPosition position)
Packit 971217
{
Packit 971217
  int c;
Packit 971217
Packit 971217
  for (c = 0; c < enc->n_channels; ++c) {
Packit 971217
    if (gst_opus_channel_positions[enc->n_channels - 1][c] == position) {
Packit 971217
      GST_INFO_OBJECT (enc,
Packit 971217
          "Channel position %s maps to index %d in Vorbis order",
Packit 971217
          gst_opus_channel_names[position], c);
Packit 971217
      return c;
Packit 971217
    }
Packit 971217
  }
Packit 971217
  GST_WARNING_OBJECT (enc,
Packit 971217
      "Channel position %s is not representable in Vorbis order",
Packit 971217
      gst_opus_channel_names[position]);
Packit 971217
  return -1;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_opus_enc_setup_channel_mappings (GstOpusEnc * enc,
Packit 971217
    const GstAudioInfo * info)
Packit 971217
{
Packit 971217
#define MAPS(idx,pos) (GST_AUDIO_INFO_POSITION (info, (idx)) == GST_AUDIO_CHANNEL_POSITION_##pos)
Packit 971217
Packit 971217
  int n;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (enc, "Setting up channel mapping for %d channels",
Packit 971217
      enc->n_channels);
Packit 971217
Packit 971217
  /* Start by setting up a default trivial mapping */
Packit 971217
  enc->n_stereo_streams = 0;
Packit 971217
  gst_opus_enc_setup_trivial_mapping (enc, enc->encoding_channel_mapping);
Packit 971217
  gst_opus_enc_setup_trivial_mapping (enc, enc->decoding_channel_mapping);
Packit 971217
Packit 971217
  /* For one channel, use the basic RTP mapping */
Packit 971217
  if (enc->n_channels == 1 && !enc->unpositioned) {
Packit 971217
    GST_INFO_OBJECT (enc, "Mono, trivial RTP mapping");
Packit 971217
    enc->channel_mapping_family = 0;
Packit 971217
    /* implicit mapping for family 0 */
Packit 971217
    return;
Packit 971217
  }
Packit 971217
Packit 971217
  /* For two channels, use the basic RTP mapping if the channels are
Packit 971217
     mapped as left/right. */
Packit 971217
  if (enc->n_channels == 2 && !enc->unpositioned) {
Packit 971217
    GST_INFO_OBJECT (enc, "Stereo, trivial RTP mapping");
Packit 971217
    enc->channel_mapping_family = 0;
Packit 971217
    enc->n_stereo_streams = 1;
Packit 971217
    /* implicit mapping for family 0 */
Packit 971217
    return;
Packit 971217
  }
Packit 971217
Packit 971217
  /* For channels between 3 and 8, we use the Vorbis mapping if we can
Packit 971217
     find a permutation that matches it. Mono and stereo will have been taken
Packit 971217
     care of earlier, but this code also handles it. There are two mappings.
Packit 971217
     One maps the input channels to an ordering which has the natural pairs
Packit 971217
     first so they can benefit from the Opus stereo channel coupling, and the
Packit 971217
     other maps this ordering to the Vorbis ordering. */
Packit 971217
  if (enc->n_channels >= 3 && enc->n_channels <= 8 && !enc->unpositioned) {
Packit 971217
    int c0, c1, c0v, c1v;
Packit 971217
    int mapped;
Packit 971217
    gboolean positions_done[256];
Packit 971217
    static const GstAudioChannelPosition pairs[][2] = {
Packit 971217
      {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
Packit 971217
          GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
Packit 971217
      {GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
Packit 971217
          GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
Packit 971217
      {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
Packit 971217
          GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER},
Packit 971217
      {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
Packit 971217
          GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER},
Packit 971217
      {GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
Packit 971217
          GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
Packit 971217
      {GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
Packit 971217
          GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
Packit 971217
    };
Packit 971217
    size_t pair;
Packit 971217
Packit 971217
    GST_DEBUG_OBJECT (enc,
Packit 971217
        "In range for the Vorbis mapping, building channel mapping tables");
Packit 971217
Packit 971217
    enc->n_stereo_streams = 0;
Packit 971217
    mapped = 0;
Packit 971217
    for (n = 0; n < 256; ++n)
Packit 971217
      positions_done[n] = FALSE;
Packit 971217
Packit 971217
    /* First, find any natural pairs, and move them to the front */
Packit 971217
    for (pair = 0; pair < G_N_ELEMENTS (pairs); ++pair) {
Packit 971217
      GstAudioChannelPosition p0 = pairs[pair][0];
Packit 971217
      GstAudioChannelPosition p1 = pairs[pair][1];
Packit 971217
      c0 = gst_opus_enc_find_channel_position (enc, info, p0);
Packit 971217
      c1 = gst_opus_enc_find_channel_position (enc, info, p1);
Packit 971217
      if (c0 >= 0 && c1 >= 0) {
Packit 971217
        /* We found a natural pair */
Packit 971217
        GST_DEBUG_OBJECT (enc, "Natural pair '%s/%s' found at %d %d",
Packit 971217
            gst_opus_channel_names[p0], gst_opus_channel_names[p1], c0, c1);
Packit 971217
        /* Find where they map in Vorbis order */
Packit 971217
        c0v = gst_opus_enc_find_channel_position_in_vorbis_order (enc, p0);
Packit 971217
        c1v = gst_opus_enc_find_channel_position_in_vorbis_order (enc, p1);
Packit 971217
        if (c0v < 0 || c1v < 0) {
Packit 971217
          GST_WARNING_OBJECT (enc,
Packit 971217
              "Cannot map channel positions to Vorbis order, using unknown mapping");
Packit 971217
          enc->channel_mapping_family = 255;
Packit 971217
          enc->n_stereo_streams = 0;
Packit 971217
          return;
Packit 971217
        }
Packit 971217
Packit 971217
        enc->encoding_channel_mapping[mapped] = c0;
Packit 971217
        enc->encoding_channel_mapping[mapped + 1] = c1;
Packit 971217
        enc->decoding_channel_mapping[c0v] = mapped;
Packit 971217
        enc->decoding_channel_mapping[c1v] = mapped + 1;
Packit 971217
        enc->n_stereo_streams++;
Packit 971217
        mapped += 2;
Packit 971217
        positions_done[p0] = positions_done[p1] = TRUE;
Packit 971217
      }
Packit 971217
    }
Packit 971217
Packit 971217
    /* Now add all other input channels as mono streams */
Packit 971217
    for (n = 0; n < enc->n_channels; ++n) {
Packit 971217
      GstAudioChannelPosition position = GST_AUDIO_INFO_POSITION (info, n);
Packit 971217
Packit 971217
      /* if we already mapped it while searching for pairs, nothing else
Packit 971217
         needs to be done */
Packit 971217
      if (!positions_done[position]) {
Packit 971217
        int cv;
Packit 971217
        GST_DEBUG_OBJECT (enc, "Channel position %s is not mapped yet, adding",
Packit 971217
            gst_opus_channel_names[position]);
Packit 971217
        cv = gst_opus_enc_find_channel_position_in_vorbis_order (enc, position);
Packit 971217
        if (cv < 0)
Packit 971217
          g_assert_not_reached ();
Packit 971217
        enc->encoding_channel_mapping[mapped] = n;
Packit 971217
        enc->decoding_channel_mapping[cv] = mapped;
Packit 971217
        mapped++;
Packit 971217
      }
Packit 971217
    }
Packit 971217
Packit 971217
#ifndef GST_DISABLE_GST_DEBUG
Packit 971217
    GST_INFO_OBJECT (enc,
Packit 971217
        "Mapping tables built: %d channels, %d stereo streams", enc->n_channels,
Packit 971217
        enc->n_stereo_streams);
Packit 971217
    gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
Packit 971217
        "Encoding mapping table", enc->n_channels,
Packit 971217
        enc->encoding_channel_mapping);
Packit 971217
    gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
Packit 971217
        "Decoding mapping table", enc->n_channels,
Packit 971217
        enc->decoding_channel_mapping);
Packit 971217
#endif
Packit 971217
Packit 971217
    enc->channel_mapping_family = 1;
Packit 971217
    return;
Packit 971217
  }
Packit 971217
Packit 971217
  /* More than 8 channels, if future mappings are added for those */
Packit 971217
Packit 971217
  /* For other cases, we use undefined, with the default trivial mapping
Packit 971217
     and all mono streams */
Packit 971217
  if (!enc->unpositioned)
Packit 971217
    GST_WARNING_OBJECT (enc, "Unknown mapping");
Packit 971217
  else
Packit 971217
    GST_INFO_OBJECT (enc, "Unpositioned mapping, all channels mono");
Packit 971217
Packit 971217
  enc->channel_mapping_family = 255;
Packit 971217
  enc->n_stereo_streams = 0;
Packit 971217
Packit 971217
#undef MAPS
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
Packit 971217
{
Packit 971217
  GstOpusEnc *enc;
Packit 971217
Packit 971217
  enc = GST_OPUS_ENC (benc);
Packit 971217
Packit 971217
  g_mutex_lock (&enc->property_lock);
Packit 971217
Packit 971217
  enc->n_channels = GST_AUDIO_INFO_CHANNELS (info);
Packit 971217
  enc->unpositioned = GST_AUDIO_INFO_IS_UNPOSITIONED (info);
Packit 971217
  enc->sample_rate = GST_AUDIO_INFO_RATE (info);
Packit 971217
  gst_opus_enc_setup_channel_mappings (enc, info);
Packit 971217
  GST_DEBUG_OBJECT (benc, "Setup with %d channels, %d Hz", enc->n_channels,
Packit 971217
      enc->sample_rate);
Packit 971217
Packit 971217
  /* handle reconfigure */
Packit 971217
  if (enc->state) {
Packit 971217
    opus_multistream_encoder_destroy (enc->state);
Packit 971217
    enc->state = NULL;
Packit 971217
  }
Packit 971217
  if (!gst_opus_enc_setup (enc)) {
Packit 971217
    g_mutex_unlock (&enc->property_lock);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  /* update the tags */
Packit 971217
  gst_opus_enc_set_tags (enc);
Packit 971217
Packit 971217
  enc->frame_samples = gst_opus_enc_get_frame_samples (enc);
Packit 971217
Packit 971217
  /* feedback to base class */
Packit 971217
  gst_opus_enc_setup_base_class (enc, benc);
Packit 971217
Packit 971217
  g_mutex_unlock (&enc->property_lock);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_opus_enc_setup (GstOpusEnc * enc)
Packit 971217
{
Packit 971217
  int error = OPUS_OK;
Packit 971217
  GstCaps *caps;
Packit 971217
  gboolean ret;
Packit 971217
  gint32 lookahead;
Packit 971217
  const GstTagList *tags;
Packit 971217
  GstTagList *empty_tags = NULL;
Packit 971217
  GstBuffer *header, *comments;
Packit 971217
Packit 971217
#ifndef GST_DISABLE_GST_DEBUG
Packit 971217
  GST_DEBUG_OBJECT (enc,
Packit 971217
      "setup: %d Hz, %d channels, %d stereo streams, family %d",
Packit 971217
      enc->sample_rate, enc->n_channels, enc->n_stereo_streams,
Packit 971217
      enc->channel_mapping_family);
Packit 971217
  GST_INFO_OBJECT (enc, "Mapping tables built: %d channels, %d stereo streams",
Packit 971217
      enc->n_channels, enc->n_stereo_streams);
Packit 971217
  gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
Packit 971217
      "Encoding mapping table", enc->n_channels, enc->encoding_channel_mapping);
Packit 971217
  gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
Packit 971217
      "Decoding mapping table", enc->n_channels, enc->decoding_channel_mapping);
Packit 971217
#endif
Packit 971217
Packit 971217
  enc->state = opus_multistream_encoder_create (enc->sample_rate,
Packit 971217
      enc->n_channels, enc->n_channels - enc->n_stereo_streams,
Packit 971217
      enc->n_stereo_streams, enc->encoding_channel_mapping,
Packit 971217
      enc->audio_type, &error);
Packit 971217
  if (!enc->state || error != OPUS_OK)
Packit 971217
    goto encoder_creation_failed;
Packit 971217
Packit 971217
  opus_multistream_encoder_ctl (enc->state, OPUS_SET_BITRATE (enc->bitrate), 0);
Packit 971217
  opus_multistream_encoder_ctl (enc->state, OPUS_SET_BANDWIDTH (enc->bandwidth),
Packit 971217
      0);
Packit 971217
  opus_multistream_encoder_ctl (enc->state,
Packit 971217
      OPUS_SET_VBR (enc->bitrate_type != BITRATE_TYPE_CBR), 0);
Packit 971217
  opus_multistream_encoder_ctl (enc->state,
Packit 971217
      OPUS_SET_VBR_CONSTRAINT (enc->bitrate_type ==
Packit 971217
          BITRATE_TYPE_CONSTRAINED_VBR), 0);
Packit 971217
  opus_multistream_encoder_ctl (enc->state,
Packit 971217
      OPUS_SET_COMPLEXITY (enc->complexity), 0);
Packit 971217
  opus_multistream_encoder_ctl (enc->state,
Packit 971217
      OPUS_SET_INBAND_FEC (enc->inband_fec), 0);
Packit 971217
  opus_multistream_encoder_ctl (enc->state, OPUS_SET_DTX (enc->dtx), 0);
Packit 971217
  opus_multistream_encoder_ctl (enc->state,
Packit 971217
      OPUS_SET_PACKET_LOSS_PERC (enc->packet_loss_percentage), 0);
Packit 971217
Packit 971217
  opus_multistream_encoder_ctl (enc->state, OPUS_GET_LOOKAHEAD (&lookahead), 0);
Packit 971217
Packit 971217
  GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
Packit 971217
      lookahead);
Packit 971217
Packit 971217
  /* lookahead is samples, the Opus header wants it in 48kHz samples */
Packit 971217
  lookahead = lookahead * 48000 / enc->sample_rate;
Packit 971217
  enc->lookahead = enc->pending_lookahead = lookahead;
Packit 971217
Packit 971217
  header = gst_codec_utils_opus_create_header (enc->sample_rate,
Packit 971217
      enc->n_channels, enc->channel_mapping_family,
Packit 971217
      enc->n_channels - enc->n_stereo_streams, enc->n_stereo_streams,
Packit 971217
      enc->decoding_channel_mapping, lookahead, 0);
Packit 971217
  tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
Packit 971217
  if (!tags)
Packit 971217
    tags = empty_tags = gst_tag_list_new_empty ();
Packit 971217
  comments =
Packit 971217
      gst_tag_list_to_vorbiscomment_buffer (tags, (const guint8 *) "OpusTags",
Packit 971217
      8, "Encoded with GStreamer opusenc");
Packit 971217
  caps = gst_codec_utils_opus_create_caps_from_header (header, comments);
Packit 971217
  if (empty_tags)
Packit 971217
    gst_tag_list_unref (empty_tags);
Packit 971217
  gst_buffer_unref (header);
Packit 971217
  gst_buffer_unref (comments);
Packit 971217
Packit 971217
  /* negotiate with these caps */
Packit 971217
  GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
Packit 971217
Packit 971217
  ret = gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
Packit 971217
  gst_caps_unref (caps);
Packit 971217
Packit 971217
  return ret;
Packit 971217
Packit 971217
encoder_creation_failed:
Packit 971217
  GST_ERROR_OBJECT (enc, "Encoder creation failed");
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_opus_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
Packit 971217
{
Packit 971217
  GstOpusEnc *enc;
Packit 971217
Packit 971217
  enc = GST_OPUS_ENC (benc);
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (enc, "sink event: %s", GST_EVENT_TYPE_NAME (event));
Packit 971217
  switch (GST_EVENT_TYPE (event)) {
Packit 971217
    case GST_EVENT_TAG:
Packit 971217
    {
Packit 971217
      GstTagList *list;
Packit 971217
      GstTagSetter *setter = GST_TAG_SETTER (enc);
Packit 971217
      const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
Packit 971217
Packit 971217
      gst_event_parse_tag (event, &list);
Packit 971217
      gst_tag_setter_merge_tags (setter, list, mode);
Packit 971217
      break;
Packit 971217
    }
Packit 971217
    case GST_EVENT_SEGMENT:
Packit 971217
      enc->encoded_samples = 0;
Packit 971217
      enc->consumed_samples = 0;
Packit 971217
      break;
Packit 971217
Packit 971217
    default:
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
Packit 971217
}
Packit 971217
Packit 971217
static GstCaps *
Packit 971217
gst_opus_enc_get_sink_template_caps (void)
Packit 971217
{
Packit 971217
  static volatile gsize init = 0;
Packit 971217
  static GstCaps *caps = NULL;
Packit 971217
Packit 971217
  if (g_once_init_enter (&init)) {
Packit 971217
    GValue rate_array = G_VALUE_INIT;
Packit 971217
    GValue v = G_VALUE_INIT;
Packit 971217
    GstStructure *s1, *s2, *s;
Packit 971217
    gint i, c;
Packit 971217
Packit 971217
    caps = gst_caps_new_empty ();
Packit 971217
Packit 971217
    /* The caps is cached */
Packit 971217
    GST_MINI_OBJECT_FLAG_SET (caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
Packit 971217
Packit 971217
    /* Generate our two template structures */
Packit 971217
    g_value_init (&rate_array, GST_TYPE_LIST);
Packit 971217
    g_value_init (&v, G_TYPE_INT);
Packit 971217
    g_value_set_int (&v, 8000);
Packit 971217
    gst_value_list_append_value (&rate_array, &v);
Packit 971217
    g_value_set_int (&v, 12000);
Packit 971217
    gst_value_list_append_value (&rate_array, &v);
Packit 971217
    g_value_set_int (&v, 16000);
Packit 971217
    gst_value_list_append_value (&rate_array, &v);
Packit 971217
    g_value_set_int (&v, 24000);
Packit 971217
    gst_value_list_append_value (&rate_array, &v);
Packit 971217
Packit 971217
    s1 = gst_structure_new ("audio/x-raw",
Packit 971217
        "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
Packit 971217
        "layout", G_TYPE_STRING, "interleaved",
Packit 971217
        "rate", G_TYPE_INT, 48000, NULL);
Packit 971217
    s2 = gst_structure_new ("audio/x-raw",
Packit 971217
        "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
Packit 971217
        "layout", G_TYPE_STRING, "interleaved", NULL);
Packit 971217
    gst_structure_set_value (s2, "rate", &rate_array);
Packit 971217
    g_value_unset (&rate_array);
Packit 971217
    g_value_unset (&v);
Packit 971217
Packit 971217
    /* Mono */
Packit 971217
    s = gst_structure_copy (s1);
Packit 971217
    gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
Packit 971217
    gst_caps_append_structure (caps, s);
Packit 971217
Packit 971217
    s = gst_structure_copy (s2);
Packit 971217
    gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
Packit 971217
    gst_caps_append_structure (caps, s);
Packit 971217
Packit 971217
    /* Stereo and further */
Packit 971217
    for (i = 2; i <= 8; i++) {
Packit 971217
      guint64 channel_mask = 0;
Packit 971217
      const GstAudioChannelPosition *pos = gst_opus_channel_positions[i - 1];
Packit 971217
Packit 971217
      for (c = 0; c < i; c++) {
Packit 971217
        channel_mask |= G_GUINT64_CONSTANT (1) << pos[c];
Packit 971217
      }
Packit 971217
Packit 971217
      s = gst_structure_copy (s1);
Packit 971217
      gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
Packit 971217
          GST_TYPE_BITMASK, channel_mask, NULL);
Packit 971217
      gst_caps_append_structure (caps, s);
Packit 971217
Packit 971217
      s = gst_structure_copy (s2);
Packit 971217
      gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
Packit 971217
          GST_TYPE_BITMASK, channel_mask, NULL);
Packit 971217
      gst_caps_append_structure (caps, s);
Packit 971217
Packit 971217
      /* We also allow unpositioned channels, input will be
Packit 971217
       * treated as a set of individual mono channels */
Packit 971217
      s = gst_structure_copy (s2);
Packit 971217
      gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
Packit 971217
          GST_TYPE_BITMASK, 0x0, NULL);
Packit 971217
      gst_caps_append_structure (caps, s);
Packit 971217
Packit 971217
      s = gst_structure_copy (s1);
Packit 971217
      gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
Packit 971217
          GST_TYPE_BITMASK, 0x0, NULL);
Packit 971217
      gst_caps_append_structure (caps, s);
Packit 971217
    }
Packit 971217
Packit 971217
    gst_structure_free (s1);
Packit 971217
    gst_structure_free (s2);
Packit 971217
Packit 971217
    g_once_init_leave (&init, 1);
Packit 971217
  }
Packit 971217
Packit 971217
  return caps;
Packit 971217
}
Packit 971217
Packit 971217
static GstCaps *
Packit 971217
gst_opus_enc_sink_getcaps (GstAudioEncoder * benc, GstCaps * filter)
Packit 971217
{
Packit 971217
  GstOpusEnc *enc;
Packit 971217
  GstCaps *caps;
Packit 971217
Packit 971217
  enc = GST_OPUS_ENC (benc);
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (enc, "sink getcaps");
Packit 971217
Packit 971217
  caps = gst_opus_enc_get_sink_template_caps ();
Packit 971217
  caps = gst_audio_encoder_proxy_getcaps (benc, caps, filter);
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (enc, "Returning caps: %" GST_PTR_FORMAT, caps);
Packit 971217
Packit 971217
  return caps;
Packit 971217
}
Packit 971217
Packit 971217
static GstFlowReturn
Packit 971217
gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
Packit 971217
{
Packit 971217
  guint8 *bdata = NULL, *data, *mdata = NULL;
Packit 971217
  gsize bsize, size;
Packit 971217
  gsize bytes;
Packit 971217
  gint ret = GST_FLOW_OK;
Packit 971217
  GstMapInfo map;
Packit 971217
  GstMapInfo omap;
Packit 971217
  gint outsize;
Packit 971217
  GstBuffer *outbuf;
Packit 971217
  guint64 trim_start = 0, trim_end = 0;
Packit 971217
Packit 971217
  guint max_payload_size;
Packit 971217
  gint frame_samples, input_samples, output_samples;
Packit 971217
Packit 971217
  g_mutex_lock (&enc->property_lock);
Packit 971217
Packit 971217
  bytes = enc->frame_samples * enc->n_channels * 2;
Packit 971217
  max_payload_size = enc->max_payload_size;
Packit 971217
  frame_samples = input_samples = enc->frame_samples;
Packit 971217
Packit 971217
  g_mutex_unlock (&enc->property_lock);
Packit 971217
Packit 971217
  if (G_LIKELY (buf)) {
Packit 971217
    gst_buffer_map (buf, &map, GST_MAP_READ);
Packit 971217
    bdata = map.data;
Packit 971217
    bsize = map.size;
Packit 971217
Packit 971217
    if (G_UNLIKELY (bsize % bytes)) {
Packit 971217
      gint64 diff;
Packit 971217
Packit 971217
      GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
Packit 971217
      g_assert (bsize < bytes);
Packit 971217
Packit 971217
      input_samples = bsize / (enc->n_channels * 2);
Packit 971217
      diff =
Packit 971217
          (enc->encoded_samples + frame_samples) - (enc->consumed_samples +
Packit 971217
          input_samples);
Packit 971217
      if (diff >= 0) {
Packit 971217
        GST_DEBUG_OBJECT (enc,
Packit 971217
            "%" G_GINT64_FORMAT " extra samples of padding in this frame",
Packit 971217
            diff);
Packit 971217
        output_samples = frame_samples - diff;
Packit 971217
        trim_end = diff * 48000 / enc->sample_rate;
Packit 971217
      } else {
Packit 971217
        GST_DEBUG_OBJECT (enc,
Packit 971217
            "Need to add %" G_GINT64_FORMAT " extra samples in the next frame",
Packit 971217
            -diff);
Packit 971217
        output_samples = frame_samples;
Packit 971217
      }
Packit 971217
Packit 971217
      size = ((bsize / bytes) + 1) * bytes;
Packit 971217
      mdata = g_malloc0 (size);
Packit 971217
      /* FIXME: Instead of silence, use LPC with the last real samples.
Packit 971217
       * Otherwise we will create a discontinuity here, which will distort the
Packit 971217
       * last few encoded samples
Packit 971217
       */
Packit 971217
      memcpy (mdata, bdata, bsize);
Packit 971217
      data = mdata;
Packit 971217
    } else {
Packit 971217
      data = bdata;
Packit 971217
      size = bsize;
Packit 971217
Packit 971217
      /* Adjust for lookahead here */
Packit 971217
      if (enc->pending_lookahead) {
Packit 971217
        guint scaled_lookahead =
Packit 971217
            enc->pending_lookahead * enc->sample_rate / 48000;
Packit 971217
Packit 971217
        if (input_samples > scaled_lookahead) {
Packit 971217
          output_samples = input_samples - scaled_lookahead;
Packit 971217
          trim_start = enc->pending_lookahead;
Packit 971217
          enc->pending_lookahead = 0;
Packit 971217
        } else {
Packit 971217
          trim_start = ((guint64) input_samples) * 48000 / enc->sample_rate;
Packit 971217
          enc->pending_lookahead -= trim_start;
Packit 971217
          output_samples = 0;
Packit 971217
        }
Packit 971217
      } else {
Packit 971217
        output_samples = input_samples;
Packit 971217
      }
Packit 971217
    }
Packit 971217
  } else {
Packit 971217
    if (enc->encoded_samples < enc->consumed_samples) {
Packit 971217
      /* FIXME: Instead of silence, use LPC with the last real samples.
Packit 971217
       * Otherwise we will create a discontinuity here, which will distort the
Packit 971217
       * last few encoded samples
Packit 971217
       */
Packit 971217
      data = mdata = g_malloc0 (bytes);
Packit 971217
      size = bytes;
Packit 971217
      output_samples = enc->consumed_samples - enc->encoded_samples;
Packit 971217
      input_samples = 0;
Packit 971217
      GST_DEBUG_OBJECT (enc, "draining %d samples", output_samples);
Packit 971217
      trim_end =
Packit 971217
          ((guint64) frame_samples - output_samples) * 48000 / enc->sample_rate;
Packit 971217
    } else if (enc->encoded_samples == enc->consumed_samples) {
Packit 971217
      GST_DEBUG_OBJECT (enc, "nothing to drain");
Packit 971217
      goto done;
Packit 971217
    } else {
Packit 971217
      g_assert_not_reached ();
Packit 971217
      goto done;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  g_assert (size == bytes);
Packit 971217
Packit 971217
  outbuf =
Packit 971217
      gst_audio_encoder_allocate_output_buffer (GST_AUDIO_ENCODER (enc),
Packit 971217
      max_payload_size * enc->n_channels);
Packit 971217
  if (!outbuf)
Packit 971217
    goto done;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)",
Packit 971217
      frame_samples, (int) bytes);
Packit 971217
Packit 971217
  if (trim_start || trim_end) {
Packit 971217
    GST_DEBUG_OBJECT (enc,
Packit 971217
        "Adding trim-start %" G_GUINT64_FORMAT " trim-end %" G_GUINT64_FORMAT,
Packit 971217
        trim_start, trim_end);
Packit 971217
    gst_buffer_add_audio_clipping_meta (outbuf, GST_FORMAT_DEFAULT, trim_start,
Packit 971217
        trim_end);
Packit 971217
  }
Packit 971217
Packit 971217
  gst_buffer_map (outbuf, &omap, GST_MAP_WRITE);
Packit 971217
Packit 971217
  outsize =
Packit 971217
      opus_multistream_encode (enc->state, (const gint16 *) data,
Packit 971217
      frame_samples, omap.data, max_payload_size * enc->n_channels);
Packit 971217
Packit 971217
  gst_buffer_unmap (outbuf, &omap;;
Packit 971217
Packit 971217
  if (outsize < 0) {
Packit 971217
    GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
Packit 971217
        ("Encoding failed (%d): %s", outsize, opus_strerror (outsize)));
Packit 971217
    ret = GST_FLOW_ERROR;
Packit 971217
    goto done;
Packit 971217
  } else if (outsize > max_payload_size) {
Packit 971217
    GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
Packit 971217
        ("Encoded size %d is higher than max payload size (%d bytes)",
Packit 971217
            outsize, max_payload_size));
Packit 971217
    ret = GST_FLOW_ERROR;
Packit 971217
    goto done;
Packit 971217
  }
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (enc, "Output packet is %u bytes", outsize);
Packit 971217
  gst_buffer_set_size (outbuf, outsize);
Packit 971217
Packit 971217
Packit 971217
  ret =
Packit 971217
      gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc), outbuf,
Packit 971217
      output_samples);
Packit 971217
  enc->encoded_samples += output_samples;
Packit 971217
  enc->consumed_samples += input_samples;
Packit 971217
Packit 971217
done:
Packit 971217
Packit 971217
  if (bdata)
Packit 971217
    gst_buffer_unmap (buf, &map);
Packit 971217
Packit 971217
  g_free (mdata);
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
static GstFlowReturn
Packit 971217
gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
Packit 971217
{
Packit 971217
  GstOpusEnc *enc;
Packit 971217
  GstFlowReturn ret = GST_FLOW_OK;
Packit 971217
Packit 971217
  enc = GST_OPUS_ENC (benc);
Packit 971217
  GST_DEBUG_OBJECT (enc, "handle_frame");
Packit 971217
  GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
Packit 971217
      buf ? gst_buffer_get_size (buf) : 0);
Packit 971217
Packit 971217
  ret = gst_opus_enc_encode (enc, buf);
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_opus_enc_get_property (GObject * object, guint prop_id, GValue * value,
Packit 971217
    GParamSpec * pspec)
Packit 971217
{
Packit 971217
  GstOpusEnc *enc;
Packit 971217
Packit 971217
  enc = GST_OPUS_ENC (object);
Packit 971217
Packit 971217
  g_mutex_lock (&enc->property_lock);
Packit 971217
Packit 971217
  switch (prop_id) {
Packit 971217
    case PROP_AUDIO_TYPE:
Packit 971217
      g_value_set_enum (value, enc->audio_type);
Packit 971217
      break;
Packit 971217
    case PROP_BITRATE:
Packit 971217
      g_value_set_int (value, enc->bitrate);
Packit 971217
      break;
Packit 971217
    case PROP_BANDWIDTH:
Packit 971217
      g_value_set_enum (value, enc->bandwidth);
Packit 971217
      break;
Packit 971217
    case PROP_FRAME_SIZE:
Packit 971217
      g_value_set_enum (value, enc->frame_size);
Packit 971217
      break;
Packit 971217
    case PROP_BITRATE_TYPE:
Packit 971217
      g_value_set_enum (value, enc->bitrate_type);
Packit 971217
      break;
Packit 971217
    case PROP_COMPLEXITY:
Packit 971217
      g_value_set_int (value, enc->complexity);
Packit 971217
      break;
Packit 971217
    case PROP_INBAND_FEC:
Packit 971217
      g_value_set_boolean (value, enc->inband_fec);
Packit 971217
      break;
Packit 971217
    case PROP_DTX:
Packit 971217
      g_value_set_boolean (value, enc->dtx);
Packit 971217
      break;
Packit 971217
    case PROP_PACKET_LOSS_PERCENT:
Packit 971217
      g_value_set_int (value, enc->packet_loss_percentage);
Packit 971217
      break;
Packit 971217
    case PROP_MAX_PAYLOAD_SIZE:
Packit 971217
      g_value_set_uint (value, enc->max_payload_size);
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  g_mutex_unlock (&enc->property_lock);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_opus_enc_set_property (GObject * object, guint prop_id,
Packit 971217
    const GValue * value, GParamSpec * pspec)
Packit 971217
{
Packit 971217
  GstOpusEnc *enc;
Packit 971217
Packit 971217
  enc = GST_OPUS_ENC (object);
Packit 971217
Packit 971217
#define GST_OPUS_UPDATE_PROPERTY(prop,type,ctl) do { \
Packit 971217
  g_mutex_lock (&enc->property_lock); \
Packit 971217
  enc->prop = g_value_get_##type (value); \
Packit 971217
  if (enc->state) { \
Packit 971217
    opus_multistream_encoder_ctl (enc->state, OPUS_SET_##ctl (enc->prop)); \
Packit 971217
  } \
Packit 971217
  g_mutex_unlock (&enc->property_lock); \
Packit 971217
} while(0)
Packit 971217
Packit 971217
  switch (prop_id) {
Packit 971217
    case PROP_AUDIO_TYPE:
Packit 971217
      enc->audio_type = g_value_get_enum (value);
Packit 971217
      break;
Packit 971217
    case PROP_BITRATE:
Packit 971217
      GST_OPUS_UPDATE_PROPERTY (bitrate, int, BITRATE);
Packit 971217
      break;
Packit 971217
    case PROP_BANDWIDTH:
Packit 971217
      GST_OPUS_UPDATE_PROPERTY (bandwidth, enum, BANDWIDTH);
Packit 971217
      break;
Packit 971217
    case PROP_FRAME_SIZE:
Packit 971217
      g_mutex_lock (&enc->property_lock);
Packit 971217
      enc->frame_size = g_value_get_enum (value);
Packit 971217
      enc->frame_samples = gst_opus_enc_get_frame_samples (enc);
Packit 971217
      gst_opus_enc_setup_base_class (enc, GST_AUDIO_ENCODER (enc));
Packit 971217
      g_mutex_unlock (&enc->property_lock);
Packit 971217
      break;
Packit 971217
    case PROP_BITRATE_TYPE:
Packit 971217
      /* this one has an opposite meaning to the opus ctl... */
Packit 971217
      g_mutex_lock (&enc->property_lock);
Packit 971217
      enc->bitrate_type = g_value_get_enum (value);
Packit 971217
      if (enc->state) {
Packit 971217
        opus_multistream_encoder_ctl (enc->state,
Packit 971217
            OPUS_SET_VBR (enc->bitrate_type != BITRATE_TYPE_CBR));
Packit 971217
        opus_multistream_encoder_ctl (enc->state,
Packit 971217
            OPUS_SET_VBR_CONSTRAINT (enc->bitrate_type ==
Packit 971217
                BITRATE_TYPE_CONSTRAINED_VBR), 0);
Packit 971217
      }
Packit 971217
      g_mutex_unlock (&enc->property_lock);
Packit 971217
      break;
Packit 971217
    case PROP_COMPLEXITY:
Packit 971217
      GST_OPUS_UPDATE_PROPERTY (complexity, int, COMPLEXITY);
Packit 971217
      break;
Packit 971217
    case PROP_INBAND_FEC:
Packit 971217
      GST_OPUS_UPDATE_PROPERTY (inband_fec, boolean, INBAND_FEC);
Packit 971217
      break;
Packit 971217
    case PROP_DTX:
Packit 971217
      GST_OPUS_UPDATE_PROPERTY (dtx, boolean, DTX);
Packit 971217
      break;
Packit 971217
    case PROP_PACKET_LOSS_PERCENT:
Packit 971217
      GST_OPUS_UPDATE_PROPERTY (packet_loss_percentage, int, PACKET_LOSS_PERC);
Packit 971217
      break;
Packit 971217
    case PROP_MAX_PAYLOAD_SIZE:
Packit 971217
      g_mutex_lock (&enc->property_lock);
Packit 971217
      enc->max_payload_size = g_value_get_uint (value);
Packit 971217
      g_mutex_unlock (&enc->property_lock);
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
#undef GST_OPUS_UPDATE_PROPERTY
Packit 971217
Packit 971217
}