Blame ext/vorbis/gstvorbisenc.c

Packit 0652a1
/* GStreamer
Packit 0652a1
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
Packit 0652a1
 *
Packit 0652a1
 * This library is free software; you can redistribute it and/or
Packit 0652a1
 * modify it under the terms of the GNU Library General Public
Packit 0652a1
 * License as published by the Free Software Foundation; either
Packit 0652a1
 * version 2 of the License, or (at your option) any later version.
Packit 0652a1
 *
Packit 0652a1
 * This library is distributed in the hope that it will be useful,
Packit 0652a1
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 0652a1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 0652a1
 * Library General Public License for more details.
Packit 0652a1
 *
Packit 0652a1
 * You should have received a copy of the GNU Library General Public
Packit 0652a1
 * License along with this library; if not, write to the
Packit 0652a1
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 0652a1
 * Boston, MA 02110-1301, USA.
Packit 0652a1
 */
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * SECTION:element-vorbisenc
Packit 0652a1
 * @title: vorbisenc
Packit 0652a1
 * @see_also: vorbisdec, oggmux
Packit 0652a1
 *
Packit 0652a1
 * This element encodes raw float audio into a Vorbis stream.
Packit 0652a1
 * <ulink url="http://www.vorbis.com/">Vorbis</ulink> is a royalty-free
Packit 0652a1
 * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
Packit 0652a1
 * Foundation</ulink>.
Packit 0652a1
 *
Packit 0652a1
 * ## Example pipelines
Packit 0652a1
 * |[
Packit 0652a1
 * gst-launch-1.0 -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! vorbisenc ! oggmux ! filesink location=sine.ogg
Packit 0652a1
 * ]|
Packit 0652a1
 *  Encode a test sine signal to Ogg/Vorbis.  Note that the resulting file
Packit 0652a1
 * will be really small because a sine signal compresses very well.
Packit 0652a1
 * |[
Packit 0652a1
 * gst-launch-1.0 -v autoaudiosrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
Packit 0652a1
 * ]|
Packit 0652a1
 *  Record from a sound card and encode to Ogg/Vorbis.
Packit 0652a1
 *
Packit 0652a1
 */
Packit 0652a1
#ifdef HAVE_CONFIG_H
Packit 0652a1
#include "config.h"
Packit 0652a1
#endif
Packit 0652a1
Packit 0652a1
#include <stdlib.h>
Packit 0652a1
#include <string.h>
Packit 0652a1
#include <time.h>
Packit 0652a1
#include <vorbis/vorbisenc.h>
Packit 0652a1
Packit 0652a1
#include <gst/gsttagsetter.h>
Packit 0652a1
#include <gst/tag/tag.h>
Packit 0652a1
#include <gst/audio/audio.h>
Packit 0652a1
#include "gstvorbisenc.h"
Packit 0652a1
Packit 0652a1
#include "gstvorbiscommon.h"
Packit 0652a1
Packit 0652a1
GST_DEBUG_CATEGORY_EXTERN (vorbisenc_debug);
Packit 0652a1
#define GST_CAT_DEFAULT vorbisenc_debug
Packit 0652a1
Packit 0652a1
static GstStaticPadTemplate vorbis_enc_src_factory =
Packit 0652a1
GST_STATIC_PAD_TEMPLATE ("src",
Packit 0652a1
    GST_PAD_SRC,
Packit 0652a1
    GST_PAD_ALWAYS,
Packit 0652a1
    GST_STATIC_CAPS ("audio/x-vorbis, "
Packit 0652a1
        "rate = (int) [ 1, 200000 ], " "channels = (int) [ 1, 255 ]")
Packit 0652a1
    );
Packit 0652a1
Packit 0652a1
enum
Packit 0652a1
{
Packit 0652a1
  ARG_0,
Packit 0652a1
  ARG_MAX_BITRATE,
Packit 0652a1
  ARG_BITRATE,
Packit 0652a1
  ARG_MIN_BITRATE,
Packit 0652a1
  ARG_QUALITY,
Packit 0652a1
  ARG_MANAGED,
Packit 0652a1
  ARG_LAST_MESSAGE
Packit 0652a1
};
Packit 0652a1
Packit 0652a1
static GstFlowReturn gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc);
Packit 0652a1
static GstCaps *gst_vorbis_enc_generate_sink_caps (void);
Packit 0652a1
Packit 0652a1
Packit 0652a1
#define MAX_BITRATE_DEFAULT     -1
Packit 0652a1
#define BITRATE_DEFAULT         -1
Packit 0652a1
#define MIN_BITRATE_DEFAULT     -1
Packit 0652a1
#define QUALITY_DEFAULT         0.3
Packit 0652a1
#define LOWEST_BITRATE          6000    /* lowest allowed for a 8 kHz stream */
Packit 0652a1
#define HIGHEST_BITRATE         250001  /* highest allowed for a 44 kHz stream */
Packit 0652a1
Packit 0652a1
static gboolean gst_vorbis_enc_start (GstAudioEncoder * enc);
Packit 0652a1
static gboolean gst_vorbis_enc_stop (GstAudioEncoder * enc);
Packit 0652a1
static gboolean gst_vorbis_enc_set_format (GstAudioEncoder * enc,
Packit 0652a1
    GstAudioInfo * info);
Packit 0652a1
static GstFlowReturn gst_vorbis_enc_handle_frame (GstAudioEncoder * enc,
Packit 0652a1
    GstBuffer * in_buf);
Packit 0652a1
static gboolean gst_vorbis_enc_sink_event (GstAudioEncoder * enc,
Packit 0652a1
    GstEvent * event);
Packit 0652a1
Packit 0652a1
static gboolean gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc);
Packit 0652a1
Packit 0652a1
static void gst_vorbis_enc_dispose (GObject * object);
Packit 0652a1
static void gst_vorbis_enc_get_property (GObject * object, guint prop_id,
Packit 0652a1
    GValue * value, GParamSpec * pspec);
Packit 0652a1
static void gst_vorbis_enc_set_property (GObject * object, guint prop_id,
Packit 0652a1
    const GValue * value, GParamSpec * pspec);
Packit 0652a1
static void gst_vorbis_enc_flush (GstAudioEncoder * vorbisenc);
Packit 0652a1
Packit 0652a1
#define gst_vorbis_enc_parent_class parent_class
Packit 0652a1
G_DEFINE_TYPE_WITH_CODE (GstVorbisEnc, gst_vorbis_enc,
Packit 0652a1
    GST_TYPE_AUDIO_ENCODER, G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_vorbis_enc_class_init (GstVorbisEncClass * klass)
Packit 0652a1
{
Packit 0652a1
  GObjectClass *gobject_class;
Packit 0652a1
  GstElementClass *gstelement_class;
Packit 0652a1
  GstAudioEncoderClass *base_class;
Packit 0652a1
  GstCaps *sink_caps;
Packit 0652a1
  GstPadTemplate *sink_templ;
Packit 0652a1
Packit 0652a1
  gobject_class = (GObjectClass *) klass;
Packit 0652a1
  gstelement_class = (GstElementClass *) klass;
Packit 0652a1
  base_class = (GstAudioEncoderClass *) (klass);
Packit 0652a1
Packit 0652a1
  gobject_class->set_property = gst_vorbis_enc_set_property;
Packit 0652a1
  gobject_class->get_property = gst_vorbis_enc_get_property;
Packit 0652a1
  gobject_class->dispose = gst_vorbis_enc_dispose;
Packit 0652a1
Packit 0652a1
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE,
Packit 0652a1
      g_param_spec_int ("max-bitrate", "Maximum Bitrate",
Packit 0652a1
          "Specify a maximum bitrate (in bps). Useful for streaming "
Packit 0652a1
          "applications. (-1 == disabled)",
Packit 0652a1
          -1, HIGHEST_BITRATE, MAX_BITRATE_DEFAULT,
Packit 0652a1
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 0652a1
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
Packit 0652a1
      g_param_spec_int ("bitrate", "Target Bitrate",
Packit 0652a1
          "Attempt to encode at a bitrate averaging this (in bps). "
Packit 0652a1
          "This uses the bitrate management engine, and is not recommended for most users. "
Packit 0652a1
          "Quality is a better alternative. (-1 == disabled)", -1,
Packit 0652a1
          HIGHEST_BITRATE, BITRATE_DEFAULT,
Packit 0652a1
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 0652a1
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MIN_BITRATE,
Packit 0652a1
      g_param_spec_int ("min-bitrate", "Minimum Bitrate",
Packit 0652a1
          "Specify a minimum bitrate (in bps). Useful for encoding for a "
Packit 0652a1
          "fixed-size channel. (-1 == disabled)", -1, HIGHEST_BITRATE,
Packit 0652a1
          MIN_BITRATE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 0652a1
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
Packit 0652a1
      g_param_spec_float ("quality", "Quality",
Packit 0652a1
          "Specify quality instead of specifying a particular bitrate.", -0.1,
Packit 0652a1
          1.0, QUALITY_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 0652a1
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED,
Packit 0652a1
      g_param_spec_boolean ("managed", "Managed",
Packit 0652a1
          "Enable bitrate management engine", FALSE,
Packit 0652a1
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 0652a1
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
Packit 0652a1
      g_param_spec_string ("last-message", "last-message",
Packit 0652a1
          "The last status message", NULL,
Packit 0652a1
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Packit 0652a1
Packit 0652a1
  sink_caps = gst_vorbis_enc_generate_sink_caps ();
Packit 0652a1
  sink_templ = gst_pad_template_new ("sink",
Packit 0652a1
      GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
Packit 0652a1
  gst_element_class_add_pad_template (gstelement_class, sink_templ);
Packit 0652a1
  gst_caps_unref (sink_caps);
Packit 0652a1
Packit 0652a1
  gst_element_class_add_static_pad_template (gstelement_class,
Packit 0652a1
      &vorbis_enc_src_factory);
Packit 0652a1
Packit 0652a1
  gst_element_class_set_static_metadata (gstelement_class,
Packit 0652a1
      "Vorbis audio encoder", "Codec/Encoder/Audio",
Packit 0652a1
      "Encodes audio in Vorbis format",
Packit 0652a1
      "Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>");
Packit 0652a1
Packit 0652a1
  base_class->start = GST_DEBUG_FUNCPTR (gst_vorbis_enc_start);
Packit 0652a1
  base_class->stop = GST_DEBUG_FUNCPTR (gst_vorbis_enc_stop);
Packit 0652a1
  base_class->set_format = GST_DEBUG_FUNCPTR (gst_vorbis_enc_set_format);
Packit 0652a1
  base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vorbis_enc_handle_frame);
Packit 0652a1
  base_class->sink_event = GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_event);
Packit 0652a1
  base_class->flush = GST_DEBUG_FUNCPTR (gst_vorbis_enc_flush);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_vorbis_enc_init (GstVorbisEnc * vorbisenc)
Packit 0652a1
{
Packit 0652a1
  GstAudioEncoder *enc = GST_AUDIO_ENCODER (vorbisenc);
Packit 0652a1
Packit 0652a1
  GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (enc));
Packit 0652a1
Packit 0652a1
  vorbisenc->channels = -1;
Packit 0652a1
  vorbisenc->frequency = -1;
Packit 0652a1
Packit 0652a1
  vorbisenc->managed = FALSE;
Packit 0652a1
  vorbisenc->max_bitrate = MAX_BITRATE_DEFAULT;
Packit 0652a1
  vorbisenc->bitrate = BITRATE_DEFAULT;
Packit 0652a1
  vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT;
Packit 0652a1
  vorbisenc->quality = QUALITY_DEFAULT;
Packit 0652a1
  vorbisenc->quality_set = FALSE;
Packit 0652a1
  vorbisenc->last_message = NULL;
Packit 0652a1
Packit 0652a1
  /* arrange granulepos marking (and required perfect ts) */
Packit 0652a1
  gst_audio_encoder_set_mark_granule (enc, TRUE);
Packit 0652a1
  gst_audio_encoder_set_perfect_timestamp (enc, TRUE);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_vorbis_enc_dispose (GObject * object)
Packit 0652a1
{
Packit 0652a1
  GstVorbisEnc *vorbisenc = GST_VORBISENC (object);
Packit 0652a1
Packit 0652a1
  if (vorbisenc->sinkcaps) {
Packit 0652a1
    gst_caps_unref (vorbisenc->sinkcaps);
Packit 0652a1
    vorbisenc->sinkcaps = NULL;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  G_OBJECT_CLASS (parent_class)->dispose (object);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static gboolean
Packit 0652a1
gst_vorbis_enc_start (GstAudioEncoder * enc)
Packit 0652a1
{
Packit 0652a1
  GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (enc, "start");
Packit 0652a1
  vorbisenc->tags = gst_tag_list_new_empty ();
Packit 0652a1
  vorbisenc->header_sent = FALSE;
Packit 0652a1
  vorbisenc->last_size = 0;
Packit 0652a1
Packit 0652a1
  return TRUE;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static gboolean
Packit 0652a1
gst_vorbis_enc_stop (GstAudioEncoder * enc)
Packit 0652a1
{
Packit 0652a1
  GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (enc, "stop");
Packit 0652a1
  vorbis_block_clear (&vorbisenc->vb);
Packit 0652a1
  vorbis_dsp_clear (&vorbisenc->vd);
Packit 0652a1
  vorbis_info_clear (&vorbisenc->vi);
Packit 0652a1
  g_free (vorbisenc->last_message);
Packit 0652a1
  vorbisenc->last_message = NULL;
Packit 0652a1
  gst_tag_list_unref (vorbisenc->tags);
Packit 0652a1
  vorbisenc->tags = NULL;
Packit 0652a1
Packit 0652a1
  gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
Packit 0652a1
Packit 0652a1
  return TRUE;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static GstCaps *
Packit 0652a1
gst_vorbis_enc_generate_sink_caps (void)
Packit 0652a1
{
Packit 0652a1
  GstCaps *caps = gst_caps_new_empty ();
Packit 0652a1
  int i, c;
Packit 0652a1
Packit 0652a1
  gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw",
Packit 0652a1
          "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
Packit 0652a1
          "layout", G_TYPE_STRING, "interleaved",
Packit 0652a1
          "rate", GST_TYPE_INT_RANGE, 1, 200000,
Packit 0652a1
          "channels", G_TYPE_INT, 1, NULL));
Packit 0652a1
Packit 0652a1
  for (i = 2; i <= 8; i++) {
Packit 0652a1
    GstStructure *structure;
Packit 0652a1
    guint64 channel_mask = 0;
Packit 0652a1
    const GstAudioChannelPosition *pos = gst_vorbis_channel_positions[i - 1];
Packit 0652a1
Packit 0652a1
    for (c = 0; c < i; c++) {
Packit 0652a1
      channel_mask |= G_GUINT64_CONSTANT (1) << pos[c];
Packit 0652a1
    }
Packit 0652a1
Packit 0652a1
    structure = gst_structure_new ("audio/x-raw",
Packit 0652a1
        "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
Packit 0652a1
        "layout", G_TYPE_STRING, "interleaved",
Packit 0652a1
        "rate", GST_TYPE_INT_RANGE, 1, 200000, "channels", G_TYPE_INT, i,
Packit 0652a1
        "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL);
Packit 0652a1
Packit 0652a1
    gst_caps_append_structure (caps, structure);
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw",
Packit 0652a1
          "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
Packit 0652a1
          "layout", G_TYPE_STRING, "interleaved",
Packit 0652a1
          "rate", GST_TYPE_INT_RANGE, 1, 200000,
Packit 0652a1
          "channels", GST_TYPE_INT_RANGE, 9, 255,
Packit 0652a1
          "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL));
Packit 0652a1
Packit 0652a1
  return caps;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static gint64
Packit 0652a1
gst_vorbis_enc_get_latency (GstVorbisEnc * vorbisenc)
Packit 0652a1
{
Packit 0652a1
  /* FIXME, this probably depends on the bitrate and other setting but for now
Packit 0652a1
   * we return this value, which was obtained by totally unscientific
Packit 0652a1
   * measurements */
Packit 0652a1
  return 58 * GST_MSECOND;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static gboolean
Packit 0652a1
gst_vorbis_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
Packit 0652a1
{
Packit 0652a1
  GstVorbisEnc *vorbisenc;
Packit 0652a1
Packit 0652a1
  vorbisenc = GST_VORBISENC (enc);
Packit 0652a1
Packit 0652a1
  vorbisenc->channels = GST_AUDIO_INFO_CHANNELS (info);
Packit 0652a1
  vorbisenc->frequency = GST_AUDIO_INFO_RATE (info);
Packit 0652a1
Packit 0652a1
  /* if re-configured, we were drained and cleared already */
Packit 0652a1
  vorbisenc->header_sent = FALSE;
Packit 0652a1
  if (!gst_vorbis_enc_setup (vorbisenc))
Packit 0652a1
    return FALSE;
Packit 0652a1
Packit 0652a1
  /* feedback to base class */
Packit 0652a1
  gst_audio_encoder_set_latency (enc,
Packit 0652a1
      gst_vorbis_enc_get_latency (vorbisenc),
Packit 0652a1
      gst_vorbis_enc_get_latency (vorbisenc));
Packit 0652a1
Packit 0652a1
  return TRUE;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_vorbis_enc_metadata_set1 (const GstTagList * list, const gchar * tag,
Packit 0652a1
    gpointer vorbisenc)
Packit 0652a1
{
Packit 0652a1
  GstVorbisEnc *enc = GST_VORBISENC (vorbisenc);
Packit 0652a1
  GList *vc_list, *l;
Packit 0652a1
Packit 0652a1
  vc_list = gst_tag_to_vorbis_comments (list, tag);
Packit 0652a1
Packit 0652a1
  for (l = vc_list; l != NULL; l = l->next) {
Packit 0652a1
    const gchar *vc_string = (const gchar *) l->data;
Packit 0652a1
    gchar *key = NULL, *val = NULL;
Packit 0652a1
Packit 0652a1
    GST_LOG_OBJECT (vorbisenc, "vorbis comment: %s", vc_string);
Packit 0652a1
    if (gst_tag_parse_extended_comment (vc_string, &key, NULL, &val, TRUE)) {
Packit 0652a1
      vorbis_comment_add_tag (&enc->vc, key, val);
Packit 0652a1
      g_free (key);
Packit 0652a1
      g_free (val);
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  g_list_foreach (vc_list, (GFunc) g_free, NULL);
Packit 0652a1
  g_list_free (vc_list);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_vorbis_enc_set_metadata (GstVorbisEnc * enc)
Packit 0652a1
{
Packit 0652a1
  GstTagList *merged_tags;
Packit 0652a1
  const GstTagList *user_tags;
Packit 0652a1
Packit 0652a1
  vorbis_comment_init (&enc->vc);
Packit 0652a1
Packit 0652a1
  user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
Packit 0652a1
  GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
Packit 0652a1
Packit 0652a1
  /* gst_tag_list_merge() will handle NULL for either or both lists fine */
Packit 0652a1
  merged_tags = gst_tag_list_merge (user_tags, enc->tags,
Packit 0652a1
      gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
Packit 0652a1
Packit 0652a1
  if (merged_tags) {
Packit 0652a1
    GST_DEBUG_OBJECT (enc, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
Packit 0652a1
    gst_tag_list_foreach (merged_tags, gst_vorbis_enc_metadata_set1, enc);
Packit 0652a1
    gst_tag_list_unref (merged_tags);
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static gchar *
Packit 0652a1
get_constraints_string (GstVorbisEnc * vorbisenc)
Packit 0652a1
{
Packit 0652a1
  gint min = vorbisenc->min_bitrate;
Packit 0652a1
  gint max = vorbisenc->max_bitrate;
Packit 0652a1
  gchar *result;
Packit 0652a1
Packit 0652a1
  if (min > 0 && max > 0)
Packit 0652a1
    result = g_strdup_printf ("(min %d bps, max %d bps)", min, max);
Packit 0652a1
  else if (min > 0)
Packit 0652a1
    result = g_strdup_printf ("(min %d bps, no max)", min);
Packit 0652a1
  else if (max > 0)
Packit 0652a1
    result = g_strdup_printf ("(no min, max %d bps)", max);
Packit 0652a1
  else
Packit 0652a1
    result = g_strdup_printf ("(no min or max)");
Packit 0652a1
Packit 0652a1
  return result;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
update_start_message (GstVorbisEnc * vorbisenc)
Packit 0652a1
{
Packit 0652a1
  gchar *constraints;
Packit 0652a1
Packit 0652a1
  g_free (vorbisenc->last_message);
Packit 0652a1
Packit 0652a1
  if (vorbisenc->bitrate > 0) {
Packit 0652a1
    if (vorbisenc->managed) {
Packit 0652a1
      constraints = get_constraints_string (vorbisenc);
Packit 0652a1
      vorbisenc->last_message =
Packit 0652a1
          g_strdup_printf ("encoding at average bitrate %d bps %s",
Packit 0652a1
          vorbisenc->bitrate, constraints);
Packit 0652a1
      g_free (constraints);
Packit 0652a1
    } else {
Packit 0652a1
      vorbisenc->last_message =
Packit 0652a1
          g_strdup_printf
Packit 0652a1
          ("encoding at approximate bitrate %d bps (VBR encoding enabled)",
Packit 0652a1
          vorbisenc->bitrate);
Packit 0652a1
    }
Packit 0652a1
  } else {
Packit 0652a1
    if (vorbisenc->quality_set) {
Packit 0652a1
      if (vorbisenc->managed) {
Packit 0652a1
        constraints = get_constraints_string (vorbisenc);
Packit 0652a1
        vorbisenc->last_message =
Packit 0652a1
            g_strdup_printf
Packit 0652a1
            ("encoding at quality level %2.2f using constrained VBR %s",
Packit 0652a1
            vorbisenc->quality, constraints);
Packit 0652a1
        g_free (constraints);
Packit 0652a1
      } else {
Packit 0652a1
        vorbisenc->last_message =
Packit 0652a1
            g_strdup_printf ("encoding at quality level %2.2f",
Packit 0652a1
            vorbisenc->quality);
Packit 0652a1
      }
Packit 0652a1
    } else {
Packit 0652a1
      constraints = get_constraints_string (vorbisenc);
Packit 0652a1
      vorbisenc->last_message =
Packit 0652a1
          g_strdup_printf ("encoding using bitrate management %s", constraints);
Packit 0652a1
      g_free (constraints);
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  g_object_notify (G_OBJECT (vorbisenc), "last_message");
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static gboolean
Packit 0652a1
gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc)
Packit 0652a1
{
Packit 0652a1
Packit 0652a1
  GST_LOG_OBJECT (vorbisenc, "setup");
Packit 0652a1
Packit 0652a1
  if (vorbisenc->bitrate < 0 && vorbisenc->min_bitrate < 0
Packit 0652a1
      && vorbisenc->max_bitrate < 0) {
Packit 0652a1
    vorbisenc->quality_set = TRUE;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  update_start_message (vorbisenc);
Packit 0652a1
Packit 0652a1
  /* choose an encoding mode */
Packit 0652a1
  /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */
Packit 0652a1
  vorbis_info_init (&vorbisenc->vi);
Packit 0652a1
Packit 0652a1
  if (vorbisenc->quality_set) {
Packit 0652a1
    if (vorbis_encode_setup_vbr (&vorbisenc->vi,
Packit 0652a1
            vorbisenc->channels, vorbisenc->frequency,
Packit 0652a1
            vorbisenc->quality) != 0) {
Packit 0652a1
      GST_ERROR_OBJECT (vorbisenc,
Packit 0652a1
          "vorbisenc: initialisation failed: invalid parameters for quality");
Packit 0652a1
      vorbis_info_clear (&vorbisenc->vi);
Packit 0652a1
      return FALSE;
Packit 0652a1
    }
Packit 0652a1
Packit 0652a1
    /* do we have optional hard quality restrictions? */
Packit 0652a1
    if (vorbisenc->max_bitrate > 0 || vorbisenc->min_bitrate > 0) {
Packit 0652a1
      struct ovectl_ratemanage_arg ai;
Packit 0652a1
Packit 0652a1
      vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_GET, &ai;;
Packit 0652a1
Packit 0652a1
      ai.bitrate_hard_min = vorbisenc->min_bitrate;
Packit 0652a1
      ai.bitrate_hard_max = vorbisenc->max_bitrate;
Packit 0652a1
      ai.management_active = 1;
Packit 0652a1
Packit 0652a1
      vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, &ai;;
Packit 0652a1
    }
Packit 0652a1
  } else {
Packit 0652a1
    long min_bitrate, max_bitrate;
Packit 0652a1
Packit 0652a1
    min_bitrate = vorbisenc->min_bitrate > 0 ? vorbisenc->min_bitrate : -1;
Packit 0652a1
    max_bitrate = vorbisenc->max_bitrate > 0 ? vorbisenc->max_bitrate : -1;
Packit 0652a1
Packit 0652a1
    if (vorbis_encode_setup_managed (&vorbisenc->vi,
Packit 0652a1
            vorbisenc->channels,
Packit 0652a1
            vorbisenc->frequency,
Packit 0652a1
            max_bitrate, vorbisenc->bitrate, min_bitrate) != 0) {
Packit 0652a1
      GST_ERROR_OBJECT (vorbisenc,
Packit 0652a1
          "vorbis_encode_setup_managed "
Packit 0652a1
          "(c %d, rate %d, max br %ld, br %d, min br %ld) failed",
Packit 0652a1
          vorbisenc->channels, vorbisenc->frequency, max_bitrate,
Packit 0652a1
          vorbisenc->bitrate, min_bitrate);
Packit 0652a1
      vorbis_info_clear (&vorbisenc->vi);
Packit 0652a1
      return FALSE;
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  if (vorbisenc->managed && vorbisenc->bitrate < 0) {
Packit 0652a1
    vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_AVG, NULL);
Packit 0652a1
  } else if (!vorbisenc->managed) {
Packit 0652a1
    /* Turn off management entirely (if it was turned on). */
Packit 0652a1
    vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, NULL);
Packit 0652a1
  }
Packit 0652a1
  vorbis_encode_setup_init (&vorbisenc->vi);
Packit 0652a1
Packit 0652a1
  /* set up the analysis state and auxiliary encoding storage */
Packit 0652a1
  vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi);
Packit 0652a1
  vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb);
Packit 0652a1
Packit 0652a1
  /* samples == granulepos start at 0 again */
Packit 0652a1
  vorbisenc->samples_out = 0;
Packit 0652a1
Packit 0652a1
  /* fresh encoder available */
Packit 0652a1
  vorbisenc->setup = TRUE;
Packit 0652a1
Packit 0652a1
  return TRUE;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static GstFlowReturn
Packit 0652a1
gst_vorbis_enc_clear (GstVorbisEnc * vorbisenc)
Packit 0652a1
{
Packit 0652a1
  GstFlowReturn ret = GST_FLOW_OK;
Packit 0652a1
Packit 0652a1
  if (vorbisenc->setup) {
Packit 0652a1
    vorbis_analysis_wrote (&vorbisenc->vd, 0);
Packit 0652a1
    ret = gst_vorbis_enc_output_buffers (vorbisenc);
Packit 0652a1
Packit 0652a1
    /* marked EOS to encoder, recreate if needed */
Packit 0652a1
    vorbisenc->setup = FALSE;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  /* clean up and exit.  vorbis_info_clear() must be called last */
Packit 0652a1
  vorbis_block_clear (&vorbisenc->vb);
Packit 0652a1
  vorbis_dsp_clear (&vorbisenc->vd);
Packit 0652a1
  vorbis_info_clear (&vorbisenc->vi);
Packit 0652a1
Packit 0652a1
  return ret;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_vorbis_enc_flush (GstAudioEncoder * enc)
Packit 0652a1
{
Packit 0652a1
  GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);
Packit 0652a1
Packit 0652a1
  gst_vorbis_enc_clear (vorbisenc);
Packit 0652a1
  vorbisenc->header_sent = FALSE;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/* copied and adapted from ext/ogg/gstoggstream.c */
Packit 0652a1
static gint64
Packit 0652a1
packet_duration_vorbis (GstVorbisEnc * enc, ogg_packet * packet)
Packit 0652a1
{
Packit 0652a1
  int mode;
Packit 0652a1
  int size;
Packit 0652a1
  int duration;
Packit 0652a1
Packit 0652a1
  if (packet->bytes == 0 || packet->packet[0] & 1)
Packit 0652a1
    return 0;
Packit 0652a1
Packit 0652a1
  mode = (packet->packet[0] >> 1) & ((1 << enc->vorbis_log2_num_modes) - 1);
Packit 0652a1
  size = enc->vorbis_mode_sizes[mode] ? enc->long_size : enc->short_size;
Packit 0652a1
Packit 0652a1
  if (enc->last_size == 0) {
Packit 0652a1
    duration = 0;
Packit 0652a1
  } else {
Packit 0652a1
    duration = enc->last_size / 4 + size / 4;
Packit 0652a1
  }
Packit 0652a1
  enc->last_size = size;
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (enc, "duration %d", (int) duration);
Packit 0652a1
Packit 0652a1
  return duration;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/* copied and adapted from ext/ogg/gstoggstream.c */
Packit 0652a1
static void
Packit 0652a1
parse_vorbis_header_packet (GstVorbisEnc * enc, ogg_packet * packet)
Packit 0652a1
{
Packit 0652a1
  /*
Packit 0652a1
   * on the first (b_o_s) packet, determine the long and short sizes,
Packit 0652a1
   * and then calculate l/2, l/4 - s/4, 3 * l/4 - s/4, l/2 - s/2 and s/2
Packit 0652a1
   */
Packit 0652a1
Packit 0652a1
  enc->long_size = 1 << (packet->packet[28] >> 4);
Packit 0652a1
  enc->short_size = 1 << (packet->packet[28] & 0xF);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/* copied and adapted from ext/ogg/gstoggstream.c */
Packit 0652a1
static void
Packit 0652a1
parse_vorbis_codebooks_packet (GstVorbisEnc * enc, ogg_packet * op)
Packit 0652a1
{
Packit 0652a1
  /*
Packit 0652a1
   * the code pages, a whole bunch of other fairly useless stuff, AND,
Packit 0652a1
   * RIGHT AT THE END (of a bunch of variable-length compressed rubbish that
Packit 0652a1
   * basically has only one actual set of values that everyone uses BUT YOU
Packit 0652a1
   * CAN'T BE SURE OF THAT, OH NO YOU CAN'T) is the only piece of data that's
Packit 0652a1
   * actually useful to us - the packet modes (because it's inconceivable to
Packit 0652a1
   * think people might want _just that_ and nothing else, you know, for
Packit 0652a1
   * seeking and stuff).
Packit 0652a1
   *
Packit 0652a1
   * Fortunately, because of the mandate that non-used bits must be zero
Packit 0652a1
   * at the end of the packet, we might be able to sneakily work backwards
Packit 0652a1
   * and find out the information we need (namely a mapping of modes to
Packit 0652a1
   * packet sizes)
Packit 0652a1
   */
Packit 0652a1
  unsigned char *current_pos = &op->packet[op->bytes - 1];
Packit 0652a1
  int offset;
Packit 0652a1
  int size;
Packit 0652a1
  int size_check;
Packit 0652a1
  int *mode_size_ptr;
Packit 0652a1
  int i;
Packit 0652a1
  int ii;
Packit 0652a1
Packit 0652a1
  /*
Packit 0652a1
   * This is the format of the mode data at the end of the packet for all
Packit 0652a1
   * Vorbis Version 1 :
Packit 0652a1
   *
Packit 0652a1
   * [ 6:number_of_modes ]
Packit 0652a1
   * [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
Packit 0652a1
   * [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
Packit 0652a1
   * [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
Packit 0652a1
   * [ 1:framing(1) ]
Packit 0652a1
   *
Packit 0652a1
   * e.g.:
Packit 0652a1
   *
Packit 0652a1
   *              <-
Packit 0652a1
   * 0 0 0 0 0 1 0 0
Packit 0652a1
   * 0 0 1 0 0 0 0 0
Packit 0652a1
   * 0 0 1 0 0 0 0 0
Packit 0652a1
   * 0 0 1|0 0 0 0 0
Packit 0652a1
   * 0 0 0 0|0|0 0 0
Packit 0652a1
   * 0 0 0 0 0 0 0 0
Packit 0652a1
   * 0 0 0 0|0 0 0 0
Packit 0652a1
   * 0 0 0 0 0 0 0 0
Packit 0652a1
   * 0 0 0 0|0 0 0 0
Packit 0652a1
   * 0 0 0|1|0 0 0 0 |
Packit 0652a1
   * 0 0 0 0 0 0 0 0 V
Packit 0652a1
   * 0 0 0|0 0 0 0 0
Packit 0652a1
   * 0 0 0 0 0 0 0 0
Packit 0652a1
   * 0 0 1|0 0 0 0 0
Packit 0652a1
   * 0 0|1|0 0 0 0 0
Packit 0652a1
   *
Packit 0652a1
   *
Packit 0652a1
   * i.e. each entry is an important bit, 32 bits of 0, 8 bits of blah, a
Packit 0652a1
   * bit of 1.
Packit 0652a1
   * Let's find our last 1 bit first.
Packit 0652a1
   *
Packit 0652a1
   */
Packit 0652a1
Packit 0652a1
  size = 0;
Packit 0652a1
Packit 0652a1
  offset = 8;
Packit 0652a1
  while (!((1 << --offset) & *current_pos)) {
Packit 0652a1
    if (offset == 0) {
Packit 0652a1
      offset = 8;
Packit 0652a1
      current_pos -= 1;
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  while (1) {
Packit 0652a1
Packit 0652a1
    /*
Packit 0652a1
     * from current_pos-5:(offset+1) to current_pos-1:(offset+1) should
Packit 0652a1
     * be zero
Packit 0652a1
     */
Packit 0652a1
    offset = (offset + 7) % 8;
Packit 0652a1
    if (offset == 7)
Packit 0652a1
      current_pos -= 1;
Packit 0652a1
Packit 0652a1
    if (((current_pos[-5] & ~((1 << (offset + 1)) - 1)) != 0)
Packit 0652a1
        ||
Packit 0652a1
        current_pos[-4] != 0
Packit 0652a1
        ||
Packit 0652a1
        current_pos[-3] != 0
Packit 0652a1
        ||
Packit 0652a1
        current_pos[-2] != 0
Packit 0652a1
        || ((current_pos[-1] & ((1 << (offset + 1)) - 1)) != 0)
Packit 0652a1
        ) {
Packit 0652a1
      break;
Packit 0652a1
    }
Packit 0652a1
Packit 0652a1
    size += 1;
Packit 0652a1
Packit 0652a1
    current_pos -= 5;
Packit 0652a1
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  /* Give ourselves a chance to recover if we went back too far by using
Packit 0652a1
   * the size check. */
Packit 0652a1
  for (ii = 0; ii < 2; ii++) {
Packit 0652a1
    if (offset > 4) {
Packit 0652a1
      size_check = (current_pos[0] >> (offset - 5)) & 0x3F;
Packit 0652a1
    } else {
Packit 0652a1
      /* mask part of byte from current_pos */
Packit 0652a1
      size_check = (current_pos[0] & ((1 << (offset + 1)) - 1));
Packit 0652a1
      /* shift to appropriate position */
Packit 0652a1
      size_check <<= (5 - offset);
Packit 0652a1
      /* or in part of byte from current_pos - 1 */
Packit 0652a1
      size_check |= (current_pos[-1] & ~((1 << (offset + 3)) - 1)) >>
Packit 0652a1
          (offset + 3);
Packit 0652a1
    }
Packit 0652a1
Packit 0652a1
    size_check += 1;
Packit 0652a1
    if (size_check == size) {
Packit 0652a1
      break;
Packit 0652a1
    }
Packit 0652a1
    offset = (offset + 1) % 8;
Packit 0652a1
    if (offset == 0)
Packit 0652a1
      current_pos += 1;
Packit 0652a1
    current_pos += 5;
Packit 0652a1
    size -= 1;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  /* Store mode size information in our info struct */
Packit 0652a1
  i = -1;
Packit 0652a1
  while ((1 << (++i)) < size);
Packit 0652a1
  enc->vorbis_log2_num_modes = i;
Packit 0652a1
Packit 0652a1
  mode_size_ptr = enc->vorbis_mode_sizes;
Packit 0652a1
Packit 0652a1
  for (i = 0; i < size; i++) {
Packit 0652a1
    offset = (offset + 1) % 8;
Packit 0652a1
    if (offset == 0)
Packit 0652a1
      current_pos += 1;
Packit 0652a1
    *mode_size_ptr++ = (current_pos[0] >> offset) & 0x1;
Packit 0652a1
    current_pos += 5;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static GstBuffer *
Packit 0652a1
gst_vorbis_enc_buffer_from_header_packet (GstVorbisEnc * vorbisenc,
Packit 0652a1
    ogg_packet * packet)
Packit 0652a1
{
Packit 0652a1
  GstBuffer *outbuf;
Packit 0652a1
Packit 0652a1
  if (packet->bytes > 0 && packet->packet[0] == '\001') {
Packit 0652a1
    parse_vorbis_header_packet (vorbisenc, packet);
Packit 0652a1
  } else if (packet->bytes > 0 && packet->packet[0] == '\005') {
Packit 0652a1
    parse_vorbis_codebooks_packet (vorbisenc, packet);
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  outbuf =
Packit 0652a1
      gst_audio_encoder_allocate_output_buffer (GST_AUDIO_ENCODER (vorbisenc),
Packit 0652a1
      packet->bytes);
Packit 0652a1
  gst_buffer_fill (outbuf, 0, packet->packet, packet->bytes);
Packit 0652a1
  GST_BUFFER_OFFSET (outbuf) = 0;
Packit 0652a1
  GST_BUFFER_OFFSET_END (outbuf) = 0;
Packit 0652a1
  GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
Packit 0652a1
  GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
Packit 0652a1
  GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_HEADER);
Packit 0652a1
Packit 0652a1
  GST_DEBUG ("created header packet buffer, %" G_GSIZE_FORMAT " bytes",
Packit 0652a1
      gst_buffer_get_size (outbuf));
Packit 0652a1
  return outbuf;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static gboolean
Packit 0652a1
gst_vorbis_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
Packit 0652a1
{
Packit 0652a1
  GstVorbisEnc *vorbisenc;
Packit 0652a1
Packit 0652a1
  vorbisenc = GST_VORBISENC (enc);
Packit 0652a1
Packit 0652a1
  switch (GST_EVENT_TYPE (event)) {
Packit 0652a1
    case GST_EVENT_TAG:
Packit 0652a1
      if (vorbisenc->tags) {
Packit 0652a1
        GstTagList *list;
Packit 0652a1
Packit 0652a1
        gst_event_parse_tag (event, &list);
Packit 0652a1
        gst_tag_list_insert (vorbisenc->tags, list,
Packit 0652a1
            gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc)));
Packit 0652a1
      } else {
Packit 0652a1
        g_assert_not_reached ();
Packit 0652a1
      }
Packit 0652a1
      break;
Packit 0652a1
      /* fall through */
Packit 0652a1
    default:
Packit 0652a1
      break;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  /* we only peeked, let base class handle it */
Packit 0652a1
  return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/*
Packit 0652a1
 * (really really) FIXME: move into core (dixit tpm)
Packit 0652a1
 */
Packit 0652a1
/*
Packit 0652a1
 * _gst_caps_set_buffer_array:
Packit 0652a1
 * @caps: (transfer full): a #GstCaps
Packit 0652a1
 * @field: field in caps to set
Packit 0652a1
 * @buf: header buffers
Packit 0652a1
 *
Packit 0652a1
 * Adds given buffers to an array of buffers set as the given @field
Packit 0652a1
 * on the given @caps.  List of buffer arguments must be NULL-terminated.
Packit 0652a1
 *
Packit 0652a1
 * Returns: (transfer full): input caps with a streamheader field added, or NULL
Packit 0652a1
 *     if some error occurred
Packit 0652a1
 */
Packit 0652a1
static GstCaps *
Packit 0652a1
_gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
Packit 0652a1
    GstBuffer * buf, ...)
Packit 0652a1
{
Packit 0652a1
  GstStructure *structure = NULL;
Packit 0652a1
  va_list va;
Packit 0652a1
  GValue array = { 0 };
Packit 0652a1
  GValue value = { 0 };
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (caps != NULL, NULL);
Packit 0652a1
  g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
Packit 0652a1
  g_return_val_if_fail (field != NULL, NULL);
Packit 0652a1
Packit 0652a1
  caps = gst_caps_make_writable (caps);
Packit 0652a1
  structure = gst_caps_get_structure (caps, 0);
Packit 0652a1
Packit 0652a1
  g_value_init (&array, GST_TYPE_ARRAY);
Packit 0652a1
Packit 0652a1
  va_start (va, buf);
Packit 0652a1
  /* put buffers in a fixed list */
Packit 0652a1
  while (buf) {
Packit 0652a1
    g_value_init (&value, GST_TYPE_BUFFER);
Packit 0652a1
    gst_value_set_buffer (&value, buf);
Packit 0652a1
    gst_value_array_append_value (&array, &value);
Packit 0652a1
    g_value_unset (&value);
Packit 0652a1
Packit 0652a1
    buf = va_arg (va, GstBuffer *);
Packit 0652a1
  }
Packit 0652a1
  va_end (va);
Packit 0652a1
Packit 0652a1
  gst_structure_take_value (structure, field, &array);
Packit 0652a1
Packit 0652a1
  return caps;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static GstFlowReturn
Packit 0652a1
gst_vorbis_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
Packit 0652a1
{
Packit 0652a1
  GstVorbisEnc *vorbisenc;
Packit 0652a1
  GstFlowReturn ret = GST_FLOW_OK;
Packit 0652a1
  GstMapInfo map;
Packit 0652a1
  gfloat *ptr;
Packit 0652a1
  gulong size;
Packit 0652a1
  gulong i, j;
Packit 0652a1
  float **vorbis_buffer;
Packit 0652a1
  GstBuffer *buf1, *buf2, *buf3;
Packit 0652a1
Packit 0652a1
  vorbisenc = GST_VORBISENC (enc);
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!vorbisenc->setup)) {
Packit 0652a1
    if (buffer) {
Packit 0652a1
      GST_DEBUG_OBJECT (vorbisenc, "forcing setup");
Packit 0652a1
      /* should not fail, as setup before same way */
Packit 0652a1
      if (!gst_vorbis_enc_setup (vorbisenc))
Packit 0652a1
        return GST_FLOW_ERROR;
Packit 0652a1
    } else {
Packit 0652a1
      /* end draining */
Packit 0652a1
      GST_LOG_OBJECT (vorbisenc, "already drained");
Packit 0652a1
      return GST_FLOW_OK;
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  if (!vorbisenc->header_sent) {
Packit 0652a1
    /* Vorbis streams begin with three headers; the initial header (with
Packit 0652a1
       most of the codec setup parameters) which is mandated by the Ogg
Packit 0652a1
       bitstream spec.  The second header holds any comment fields.  The
Packit 0652a1
       third header holds the bitstream codebook.  We merely need to
Packit 0652a1
       make the headers, then pass them to libvorbis one at a time;
Packit 0652a1
       libvorbis handles the additional Ogg bitstream constraints */
Packit 0652a1
    ogg_packet header;
Packit 0652a1
    ogg_packet header_comm;
Packit 0652a1
    ogg_packet header_code;
Packit 0652a1
    GstCaps *caps;
Packit 0652a1
    GList *headers;
Packit 0652a1
Packit 0652a1
    GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets");
Packit 0652a1
    gst_vorbis_enc_set_metadata (vorbisenc);
Packit 0652a1
    vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header,
Packit 0652a1
        &header_comm, &header_code);
Packit 0652a1
    vorbis_comment_clear (&vorbisenc->vc);
Packit 0652a1
Packit 0652a1
    /* create header buffers */
Packit 0652a1
    buf1 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header);
Packit 0652a1
    buf2 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_comm);
Packit 0652a1
    buf3 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_code);
Packit 0652a1
Packit 0652a1
    /* mark and put on caps */
Packit 0652a1
    caps = gst_caps_new_simple ("audio/x-vorbis",
Packit 0652a1
        "rate", G_TYPE_INT, vorbisenc->frequency,
Packit 0652a1
        "channels", G_TYPE_INT, vorbisenc->channels, NULL);
Packit 0652a1
    caps = _gst_caps_set_buffer_array (caps, "streamheader",
Packit 0652a1
        buf1, buf2, buf3, NULL);
Packit 0652a1
Packit 0652a1
    /* negotiate with these caps */
Packit 0652a1
    GST_DEBUG_OBJECT (vorbisenc, "here are the caps: %" GST_PTR_FORMAT, caps);
Packit 0652a1
    gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (vorbisenc), caps);
Packit 0652a1
    gst_caps_unref (caps);
Packit 0652a1
Packit 0652a1
    /* store buffers for later pre_push sending */
Packit 0652a1
    headers = NULL;
Packit 0652a1
    GST_DEBUG_OBJECT (vorbisenc, "storing header buffers");
Packit 0652a1
    headers = g_list_prepend (headers, buf3);
Packit 0652a1
    headers = g_list_prepend (headers, buf2);
Packit 0652a1
    headers = g_list_prepend (headers, buf1);
Packit 0652a1
    gst_audio_encoder_set_headers (enc, headers);
Packit 0652a1
Packit 0652a1
    vorbisenc->header_sent = TRUE;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  if (!buffer)
Packit 0652a1
    return gst_vorbis_enc_clear (vorbisenc);
Packit 0652a1
Packit 0652a1
  gst_buffer_map (buffer, &map, GST_MAP_READ);
Packit 0652a1
Packit 0652a1
  /* data to encode */
Packit 0652a1
  size = map.size / (vorbisenc->channels * sizeof (float));
Packit 0652a1
  ptr = (gfloat *) map.data;
Packit 0652a1
Packit 0652a1
  /* expose the buffer to submit data */
Packit 0652a1
  vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);
Packit 0652a1
Packit 0652a1
  /* deinterleave samples, write the buffer data */
Packit 0652a1
  if (vorbisenc->channels < 2 || vorbisenc->channels > 8) {
Packit 0652a1
    for (i = 0; i < size; i++) {
Packit 0652a1
      for (j = 0; j < vorbisenc->channels; j++) {
Packit 0652a1
        vorbis_buffer[j][i] = *ptr++;
Packit 0652a1
      }
Packit 0652a1
    }
Packit 0652a1
  } else {
Packit 0652a1
    gint i, j;
Packit 0652a1
Packit 0652a1
    /* Reorder */
Packit 0652a1
    for (i = 0; i < size; i++) {
Packit 0652a1
      for (j = 0; j < vorbisenc->channels; j++) {
Packit 0652a1
        vorbis_buffer[gst_vorbis_reorder_map[vorbisenc->channels - 1][j]][i] =
Packit 0652a1
            ptr[j];
Packit 0652a1
      }
Packit 0652a1
      ptr += vorbisenc->channels;
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  /* tell the library how much we actually submitted */
Packit 0652a1
  vorbis_analysis_wrote (&vorbisenc->vd, size);
Packit 0652a1
  gst_buffer_unmap (buffer, &map);
Packit 0652a1
Packit 0652a1
  GST_LOG_OBJECT (vorbisenc, "wrote %lu samples to vorbis", size);
Packit 0652a1
Packit 0652a1
  ret = gst_vorbis_enc_output_buffers (vorbisenc);
Packit 0652a1
Packit 0652a1
  return ret;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static GstFlowReturn
Packit 0652a1
gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc)
Packit 0652a1
{
Packit 0652a1
  GstFlowReturn ret;
Packit 0652a1
  gint64 duration;
Packit 0652a1
Packit 0652a1
  /* vorbis does some data preanalysis, then divides up blocks for
Packit 0652a1
     more involved (potentially parallel) processing.  Get a single
Packit 0652a1
     block for encoding now */
Packit 0652a1
  while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) {
Packit 0652a1
    ogg_packet op;
Packit 0652a1
Packit 0652a1
    GST_LOG_OBJECT (vorbisenc, "analysed to a block");
Packit 0652a1
Packit 0652a1
    /* analysis */
Packit 0652a1
    vorbis_analysis (&vorbisenc->vb, NULL);
Packit 0652a1
    vorbis_bitrate_addblock (&vorbisenc->vb);
Packit 0652a1
Packit 0652a1
    while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) {
Packit 0652a1
      GstBuffer *buf;
Packit 0652a1
Packit 0652a1
      GST_LOG_OBJECT (vorbisenc, "pushing out a data packet");
Packit 0652a1
      buf =
Packit 0652a1
          gst_audio_encoder_allocate_output_buffer (GST_AUDIO_ENCODER
Packit 0652a1
          (vorbisenc), op.bytes);
Packit 0652a1
      gst_buffer_fill (buf, 0, op.packet, op.bytes);
Packit 0652a1
Packit 0652a1
      /* we have to call this every packet, not just on e_o_s, since
Packit 0652a1
         each packet's duration depends on the previous one's */
Packit 0652a1
      duration = packet_duration_vorbis (vorbisenc, &op);
Packit 0652a1
      if (op.e_o_s) {
Packit 0652a1
        gint64 samples = op.granulepos - vorbisenc->samples_out;
Packit 0652a1
        if (samples < duration) {
Packit 0652a1
          gint64 trim_end = duration - samples;
Packit 0652a1
          GST_DEBUG_OBJECT (vorbisenc,
Packit 0652a1
              "Adding trim-end %" G_GUINT64_FORMAT, trim_end);
Packit 0652a1
          gst_buffer_add_audio_clipping_meta (buf, GST_FORMAT_DEFAULT, 0,
Packit 0652a1
              trim_end);
Packit 0652a1
        }
Packit 0652a1
      }
Packit 0652a1
      /* tracking granulepos should tell us samples accounted for */
Packit 0652a1
      ret =
Packit 0652a1
          gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER
Packit 0652a1
          (vorbisenc), buf, op.granulepos - vorbisenc->samples_out);
Packit 0652a1
      vorbisenc->samples_out = op.granulepos;
Packit 0652a1
Packit 0652a1
      if (ret != GST_FLOW_OK)
Packit 0652a1
        return ret;
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  return GST_FLOW_OK;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_vorbis_enc_get_property (GObject * object, guint prop_id, GValue * value,
Packit 0652a1
    GParamSpec * pspec)
Packit 0652a1
{
Packit 0652a1
  GstVorbisEnc *vorbisenc;
Packit 0652a1
Packit 0652a1
  g_return_if_fail (GST_IS_VORBISENC (object));
Packit 0652a1
Packit 0652a1
  vorbisenc = GST_VORBISENC (object);
Packit 0652a1
Packit 0652a1
  switch (prop_id) {
Packit 0652a1
    case ARG_MAX_BITRATE:
Packit 0652a1
      g_value_set_int (value, vorbisenc->max_bitrate);
Packit 0652a1
      break;
Packit 0652a1
    case ARG_BITRATE:
Packit 0652a1
      g_value_set_int (value, vorbisenc->bitrate);
Packit 0652a1
      break;
Packit 0652a1
    case ARG_MIN_BITRATE:
Packit 0652a1
      g_value_set_int (value, vorbisenc->min_bitrate);
Packit 0652a1
      break;
Packit 0652a1
    case ARG_QUALITY:
Packit 0652a1
      g_value_set_float (value, vorbisenc->quality);
Packit 0652a1
      break;
Packit 0652a1
    case ARG_MANAGED:
Packit 0652a1
      g_value_set_boolean (value, vorbisenc->managed);
Packit 0652a1
      break;
Packit 0652a1
    case ARG_LAST_MESSAGE:
Packit 0652a1
      g_value_set_string (value, vorbisenc->last_message);
Packit 0652a1
      break;
Packit 0652a1
    default:
Packit 0652a1
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 0652a1
      break;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_vorbis_enc_set_property (GObject * object, guint prop_id,
Packit 0652a1
    const GValue * value, GParamSpec * pspec)
Packit 0652a1
{
Packit 0652a1
  GstVorbisEnc *vorbisenc;
Packit 0652a1
Packit 0652a1
  g_return_if_fail (GST_IS_VORBISENC (object));
Packit 0652a1
Packit 0652a1
  vorbisenc = GST_VORBISENC (object);
Packit 0652a1
Packit 0652a1
  switch (prop_id) {
Packit 0652a1
    case ARG_MAX_BITRATE:
Packit 0652a1
    {
Packit 0652a1
      gboolean old_value = vorbisenc->managed;
Packit 0652a1
Packit 0652a1
      vorbisenc->max_bitrate = g_value_get_int (value);
Packit 0652a1
      if (vorbisenc->max_bitrate >= 0
Packit 0652a1
          && vorbisenc->max_bitrate < LOWEST_BITRATE) {
Packit 0652a1
        g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
Packit 0652a1
        vorbisenc->max_bitrate = LOWEST_BITRATE;
Packit 0652a1
      }
Packit 0652a1
      if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
Packit 0652a1
        vorbisenc->managed = TRUE;
Packit 0652a1
      else
Packit 0652a1
        vorbisenc->managed = FALSE;
Packit 0652a1
Packit 0652a1
      if (old_value != vorbisenc->managed)
Packit 0652a1
        g_object_notify (object, "managed");
Packit 0652a1
      break;
Packit 0652a1
    }
Packit 0652a1
    case ARG_BITRATE:
Packit 0652a1
      vorbisenc->bitrate = g_value_get_int (value);
Packit 0652a1
      if (vorbisenc->bitrate >= 0 && vorbisenc->bitrate < LOWEST_BITRATE) {
Packit 0652a1
        g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
Packit 0652a1
        vorbisenc->bitrate = LOWEST_BITRATE;
Packit 0652a1
      }
Packit 0652a1
      break;
Packit 0652a1
    case ARG_MIN_BITRATE:
Packit 0652a1
    {
Packit 0652a1
      gboolean old_value = vorbisenc->managed;
Packit 0652a1
Packit 0652a1
      vorbisenc->min_bitrate = g_value_get_int (value);
Packit 0652a1
      if (vorbisenc->min_bitrate >= 0
Packit 0652a1
          && vorbisenc->min_bitrate < LOWEST_BITRATE) {
Packit 0652a1
        g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
Packit 0652a1
        vorbisenc->min_bitrate = LOWEST_BITRATE;
Packit 0652a1
      }
Packit 0652a1
      if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
Packit 0652a1
        vorbisenc->managed = TRUE;
Packit 0652a1
      else
Packit 0652a1
        vorbisenc->managed = FALSE;
Packit 0652a1
Packit 0652a1
      if (old_value != vorbisenc->managed)
Packit 0652a1
        g_object_notify (object, "managed");
Packit 0652a1
      break;
Packit 0652a1
    }
Packit 0652a1
    case ARG_QUALITY:
Packit 0652a1
      vorbisenc->quality = g_value_get_float (value);
Packit 0652a1
      if (vorbisenc->quality >= 0.0)
Packit 0652a1
        vorbisenc->quality_set = TRUE;
Packit 0652a1
      else
Packit 0652a1
        vorbisenc->quality_set = FALSE;
Packit 0652a1
      break;
Packit 0652a1
    case ARG_MANAGED:
Packit 0652a1
      vorbisenc->managed = g_value_get_boolean (value);
Packit 0652a1
      break;
Packit 0652a1
    default:
Packit 0652a1
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 0652a1
      break;
Packit 0652a1
  }
Packit 0652a1
}