コード例 #1
0
static GstFlowReturn
gst_vorbis_enc_pre_push (GstAudioEncoder * enc, GstBuffer ** buffer)
{
  GstVorbisEnc *vorbisenc;
  GstFlowReturn ret = GST_FLOW_OK;

  vorbisenc = GST_VORBISENC (enc);

  /* FIXME 0.11 ? get rid of this special ogg stuff and have it
   * put and use 'codec data' in caps like anything else,
   * with all the usual out-of-band advantage etc */
  if (G_UNLIKELY (vorbisenc->headers)) {
    GSList *header = vorbisenc->headers;

    /* try to push all of these, if we lose one, might as well lose all */
    while (header) {
      if (ret == GST_FLOW_OK)
        ret = gst_vorbis_enc_push_header (vorbisenc, header->data);
      else
        gst_vorbis_enc_push_header (vorbisenc, header->data);
      header = g_slist_next (header);
    }

    g_slist_free (vorbisenc->headers);
    vorbisenc->headers = NULL;
  }

  return ret;
}
コード例 #2
0
static void
gst_vorbis_enc_get_property (GObject * object, guint prop_id, GValue * value,
    GParamSpec * pspec)
{
  GstVorbisEnc *vorbisenc;

  g_return_if_fail (GST_IS_VORBISENC (object));

  vorbisenc = GST_VORBISENC (object);

  switch (prop_id) {
    case ARG_MAX_BITRATE:
      g_value_set_int (value, vorbisenc->max_bitrate);
      break;
    case ARG_BITRATE:
      g_value_set_int (value, vorbisenc->bitrate);
      break;
    case ARG_MIN_BITRATE:
      g_value_set_int (value, vorbisenc->min_bitrate);
      break;
    case ARG_QUALITY:
      g_value_set_float (value, vorbisenc->quality);
      break;
    case ARG_MANAGED:
      g_value_set_boolean (value, vorbisenc->managed);
      break;
    case ARG_LAST_MESSAGE:
      g_value_set_string (value, vorbisenc->last_message);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
コード例 #3
0
static gboolean
gst_vorbis_enc_sink_event (GstPad * pad, GstEvent * event)
{
  gboolean res = TRUE;
  GstVorbisEnc *vorbisenc;

  vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_EOS:
      /* Tell the library we're at end of stream so that it can handle
       * the last frame and mark end of stream in the output properly */
      GST_DEBUG_OBJECT (vorbisenc, "EOS, clearing state and sending event on");
      gst_vorbis_enc_clear (vorbisenc);

      res = gst_pad_push_event (vorbisenc->srcpad, event);
      break;
    case GST_EVENT_TAG:
      if (vorbisenc->tags) {
        GstTagList *list;

        gst_event_parse_tag (event, &list);
        gst_tag_list_insert (vorbisenc->tags, list,
            gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc)));
      } else {
        g_assert_not_reached ();
      }
      res = gst_pad_push_event (vorbisenc->srcpad, event);
      break;
    default:
      res = gst_pad_push_event (vorbisenc->srcpad, event);
      break;
  }
  return res;
}
コード例 #4
0
static gboolean
gst_vorbis_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
{
  GstVorbisEnc *vorbisenc;

  vorbisenc = GST_VORBISENC (enc);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_TAG:
      if (vorbisenc->tags) {
        GstTagList *list;

        gst_event_parse_tag (event, &list);
        gst_tag_list_insert (vorbisenc->tags, list,
            gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc)));
      } else {
        g_assert_not_reached ();
      }
      break;
      /* fall through */
    default:
      break;
  }

  /* we only peeked, let base class handle it */
  return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (enc, event);
}
コード例 #5
0
static gboolean
gst_vorbis_enc_sink_query (GstPad * pad, GstQuery * query)
{
  gboolean res = TRUE;
  GstVorbisEnc *vorbisenc;

  vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;

      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
      if (!(res =
              gst_vorbis_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
                  &dest_val)))
        goto error;
      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
      break;
    }
    default:
      res = gst_pad_query_default (pad, query);
      break;
  }

error:
  return res;
}
コード例 #6
0
static void
gst_vorbis_enc_flush (GstAudioEncoder * enc)
{
  GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);

  gst_vorbis_enc_clear (vorbisenc);
  vorbisenc->header_sent = FALSE;
}
コード例 #7
0
static GstCaps *
gst_vorbis_enc_sink_getcaps (GstPad * pad)
{
  GstVorbisEnc *vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));

  if (vorbisenc->sinkcaps == NULL)
    vorbisenc->sinkcaps = gst_vorbis_enc_generate_sink_caps ();

  return gst_caps_ref (vorbisenc->sinkcaps);
}
コード例 #8
0
static GstCaps *
gst_vorbis_enc_getcaps (GstAudioEncoder * enc)
{
  GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);

  if (vorbisenc->sinkcaps == NULL)
    vorbisenc->sinkcaps = gst_vorbis_enc_generate_sink_caps ();

  return gst_audio_encoder_proxy_getcaps (enc, vorbisenc->sinkcaps);
}
コード例 #9
0
static gboolean
gst_vorbis_enc_start (GstAudioEncoder * enc)
{
  GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);

  GST_DEBUG_OBJECT (enc, "start");
  vorbisenc->tags = gst_tag_list_new_empty ();
  vorbisenc->header_sent = FALSE;

  return TRUE;
}
コード例 #10
0
static void
gst_vorbis_enc_dispose (GObject * object)
{
  GstVorbisEnc *vorbisenc = GST_VORBISENC (object);

  if (vorbisenc->sinkcaps) {
    gst_caps_unref (vorbisenc->sinkcaps);
    vorbisenc->sinkcaps = NULL;
  }

  G_OBJECT_CLASS (parent_class)->dispose (object);
}
コード例 #11
0
static GstStateChangeReturn
gst_vorbis_enc_change_state (GstElement * element, GstStateChange transition)
{
  GstVorbisEnc *vorbisenc = GST_VORBISENC (element);
  GstStateChangeReturn res;


  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      vorbisenc->tags = gst_tag_list_new ();
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      vorbisenc->setup = FALSE;
      vorbisenc->next_discont = FALSE;
      vorbisenc->header_sent = FALSE;
      break;
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
      break;
    default:
      break;
  }

  res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
      break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      vorbis_block_clear (&vorbisenc->vb);
      vorbis_dsp_clear (&vorbisenc->vd);
      vorbis_info_clear (&vorbisenc->vi);
      g_free (vorbisenc->last_message);
      vorbisenc->last_message = NULL;
      if (vorbisenc->srccaps) {
        gst_caps_unref (vorbisenc->srccaps);
        vorbisenc->srccaps = NULL;
      }
      break;
    case GST_STATE_CHANGE_READY_TO_NULL:
      gst_tag_list_free (vorbisenc->tags);
      vorbisenc->tags = NULL;
    default:
      break;
  }

  return res;
}
コード例 #12
0
static gboolean
gst_vorbis_enc_stop (GstAudioEncoder * enc)
{
  GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);

  GST_DEBUG_OBJECT (enc, "stop");
  vorbis_block_clear (&vorbisenc->vb);
  vorbis_dsp_clear (&vorbisenc->vd);
  vorbis_info_clear (&vorbisenc->vi);
  g_free (vorbisenc->last_message);
  vorbisenc->last_message = NULL;
  gst_tag_list_unref (vorbisenc->tags);
  vorbisenc->tags = NULL;

  gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));

  return TRUE;
}
コード例 #13
0
static gboolean
gst_vorbis_enc_stop (GstAudioEncoder * enc)
{
  GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);

  GST_DEBUG_OBJECT (enc, "stop");
  vorbis_block_clear (&vorbisenc->vb);
  vorbis_dsp_clear (&vorbisenc->vd);
  vorbis_info_clear (&vorbisenc->vi);
  g_free (vorbisenc->last_message);
  vorbisenc->last_message = NULL;
  gst_tag_list_free (vorbisenc->tags);
  vorbisenc->tags = NULL;
  g_slist_foreach (vorbisenc->headers, (GFunc) gst_buffer_unref, NULL);
  vorbisenc->headers = NULL;

  return TRUE;
}
コード例 #14
0
static gboolean
gst_vorbis_enc_convert_src (GstPad * pad, GstFormat src_format,
    gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
{
  gboolean res = TRUE;
  GstVorbisEnc *vorbisenc;
  gint64 avg;

  vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));

  if (vorbisenc->samples_in == 0 ||
      vorbisenc->bytes_out == 0 || vorbisenc->frequency == 0) {
    gst_object_unref (vorbisenc);
    return FALSE;
  }

  avg = (vorbisenc->bytes_out * vorbisenc->frequency) / (vorbisenc->samples_in);

  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
        case GST_FORMAT_TIME:
          *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND, avg);
          break;
        default:
          res = FALSE;
      }
      break;
    case GST_FORMAT_TIME:
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
          *dest_value = gst_util_uint64_scale_int (src_value, avg, GST_SECOND);
          break;
        default:
          res = FALSE;
      }
      break;
    default:
      res = FALSE;
  }
  gst_object_unref (vorbisenc);
  return res;
}
コード例 #15
0
static gboolean
gst_vorbis_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
{
  GstVorbisEnc *vorbisenc;
  GstStructure *structure;

  vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
  vorbisenc->setup = FALSE;

  structure = gst_caps_get_structure (caps, 0);
  gst_structure_get_int (structure, "channels", &vorbisenc->channels);
  gst_structure_get_int (structure, "rate", &vorbisenc->frequency);

  gst_vorbis_enc_setup (vorbisenc);

  if (vorbisenc->setup)
    return TRUE;

  return FALSE;
}
コード例 #16
0
ファイル: gstvorbisenc.c プロジェクト: PeterXu/gst-mobile
static GstCaps *
gst_vorbis_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter)
{
    GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);
    GstCaps *caps;

    if (vorbisenc->sinkcaps == NULL)
        vorbisenc->sinkcaps = gst_vorbis_enc_generate_sink_caps ();

    if (filter) {
        GstCaps *int_caps = gst_caps_intersect_full (filter, vorbisenc->sinkcaps,
                            GST_CAPS_INTERSECT_FIRST);
        caps = gst_audio_encoder_proxy_getcaps (enc, int_caps, filter);
        gst_caps_unref (int_caps);
    } else {
        caps = gst_audio_encoder_proxy_getcaps (enc, vorbisenc->sinkcaps, filter);
    }

    return caps;
}
コード例 #17
0
static gboolean
gst_vorbis_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
{
  GstVorbisEnc *vorbisenc;

  vorbisenc = GST_VORBISENC (enc);

  vorbisenc->channels = GST_AUDIO_INFO_CHANNELS (info);
  vorbisenc->frequency = GST_AUDIO_INFO_RATE (info);

  /* if re-configured, we were drained and cleared already */
  if (!gst_vorbis_enc_setup (vorbisenc))
    return FALSE;

  /* feedback to base class */
  gst_audio_encoder_set_latency (enc,
      gst_vorbis_enc_get_latency (vorbisenc),
      gst_vorbis_enc_get_latency (vorbisenc));

  return TRUE;
}
コード例 #18
0
static void
gst_vorbis_enc_metadata_set1 (const GstTagList * list, const gchar * tag,
    gpointer vorbisenc)
{
  GstVorbisEnc *enc = GST_VORBISENC (vorbisenc);
  GList *vc_list, *l;

  vc_list = gst_tag_to_vorbis_comments (list, tag);

  for (l = vc_list; l != NULL; l = l->next) {
    const gchar *vc_string = (const gchar *) l->data;
    gchar *key = NULL, *val = NULL;

    GST_LOG_OBJECT (vorbisenc, "vorbis comment: %s", vc_string);
    if (gst_tag_parse_extended_comment (vc_string, &key, NULL, &val, TRUE)) {
      vorbis_comment_add_tag (&enc->vc, key, val);
      g_free (key);
      g_free (val);
    }
  }

  g_list_foreach (vc_list, (GFunc) g_free, NULL);
  g_list_free (vc_list);
}
コード例 #19
0
static GstFlowReturn
gst_vorbis_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
{
  GstVorbisEnc *vorbisenc;
  GstFlowReturn ret = GST_FLOW_OK;
  GstMapInfo map;
  gfloat *ptr;
  gulong size;
  gulong i, j;
  float **vorbis_buffer;
  GstBuffer *buf1, *buf2, *buf3;

  vorbisenc = GST_VORBISENC (enc);

  if (G_UNLIKELY (!vorbisenc->setup)) {
    if (buffer) {
      GST_DEBUG_OBJECT (vorbisenc, "forcing setup");
      /* should not fail, as setup before same way */
      if (!gst_vorbis_enc_setup (vorbisenc))
        return GST_FLOW_ERROR;
    } else {
      /* end draining */
      GST_LOG_OBJECT (vorbisenc, "already drained");
      return GST_FLOW_OK;
    }
  }

  if (!vorbisenc->header_sent) {
    /* Vorbis streams begin with three headers; the initial header (with
       most of the codec setup parameters) which is mandated by the Ogg
       bitstream spec.  The second header holds any comment fields.  The
       third header holds the bitstream codebook.  We merely need to
       make the headers, then pass them to libvorbis one at a time;
       libvorbis handles the additional Ogg bitstream constraints */
    ogg_packet header;
    ogg_packet header_comm;
    ogg_packet header_code;
    GstCaps *caps;
    GList *headers;

    GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets");
    gst_vorbis_enc_set_metadata (vorbisenc);
    vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header,
        &header_comm, &header_code);
    vorbis_comment_clear (&vorbisenc->vc);

    /* create header buffers */
    buf1 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header);
    buf2 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_comm);
    buf3 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_code);

    /* mark and put on caps */
    caps = gst_caps_new_simple ("audio/x-vorbis",
        "rate", G_TYPE_INT, vorbisenc->frequency,
        "channels", G_TYPE_INT, vorbisenc->channels, NULL);
    caps = _gst_caps_set_buffer_array (caps, "streamheader",
        buf1, buf2, buf3, NULL);

    /* negotiate with these caps */
    GST_DEBUG_OBJECT (vorbisenc, "here are the caps: %" GST_PTR_FORMAT, caps);
    gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (vorbisenc), caps);
    gst_caps_unref (caps);

    /* store buffers for later pre_push sending */
    headers = NULL;
    GST_DEBUG_OBJECT (vorbisenc, "storing header buffers");
    headers = g_list_prepend (headers, buf3);
    headers = g_list_prepend (headers, buf2);
    headers = g_list_prepend (headers, buf1);
    gst_audio_encoder_set_headers (enc, headers);

    vorbisenc->header_sent = TRUE;
  }

  if (!buffer)
    return gst_vorbis_enc_clear (vorbisenc);

  gst_buffer_map (buffer, &map, GST_MAP_WRITE);

  /* data to encode */
  size = map.size / (vorbisenc->channels * sizeof (float));
  ptr = (gfloat *) map.data;

  /* expose the buffer to submit data */
  vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);

  /* deinterleave samples, write the buffer data */
  if (vorbisenc->channels < 2 || vorbisenc->channels > 8) {
    for (i = 0; i < size; i++) {
      for (j = 0; j < vorbisenc->channels; j++) {
        vorbis_buffer[j][i] = *ptr++;
      }
    }
  } else {
    gint i, j;

    /* Reorder */
    for (i = 0; i < size; i++) {
      for (j = 0; j < vorbisenc->channels; j++) {
        vorbis_buffer[gst_vorbis_reorder_map[vorbisenc->channels - 1][j]][i] =
            ptr[j];
      }
      ptr += vorbisenc->channels;
    }
  }

  /* tell the library how much we actually submitted */
  vorbis_analysis_wrote (&vorbisenc->vd, size);
  gst_buffer_unmap (buffer, &map);

  GST_LOG_OBJECT (vorbisenc, "wrote %lu samples to vorbis", size);

  ret = gst_vorbis_enc_output_buffers (vorbisenc);

  return ret;
}
コード例 #20
0
static gboolean
gst_vorbis_enc_convert_sink (GstPad * pad, GstFormat src_format,
    gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
{
  gboolean res = TRUE;
  guint scale = 1;
  gint bytes_per_sample;
  GstVorbisEnc *vorbisenc;

  vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));

  bytes_per_sample = vorbisenc->channels * 2;

  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
          if (bytes_per_sample == 0)
            return FALSE;
          *dest_value = src_value / bytes_per_sample;
          break;
        case GST_FORMAT_TIME:
        {
          gint byterate = bytes_per_sample * vorbisenc->frequency;

          if (byterate == 0)
            return FALSE;
          *dest_value =
              gst_util_uint64_scale_int (src_value, GST_SECOND, byterate);
          break;
        }
        default:
          res = FALSE;
      }
      break;
    case GST_FORMAT_DEFAULT:
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
          *dest_value = src_value * bytes_per_sample;
          break;
        case GST_FORMAT_TIME:
          if (vorbisenc->frequency == 0)
            return FALSE;
          *dest_value =
              gst_util_uint64_scale_int (src_value, GST_SECOND,
              vorbisenc->frequency);
          break;
        default:
          res = FALSE;
      }
      break;
    case GST_FORMAT_TIME:
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
          scale = bytes_per_sample;
          /* fallthrough */
        case GST_FORMAT_DEFAULT:
          *dest_value =
              gst_util_uint64_scale_int (src_value,
              scale * vorbisenc->frequency, GST_SECOND);
          break;
        default:
          res = FALSE;
      }
      break;
    default:
      res = FALSE;
  }
  gst_object_unref (vorbisenc);
  return res;
}
コード例 #21
0
static gboolean
gst_vorbis_enc_src_query (GstPad * pad, GstQuery * query)
{
  gboolean res = TRUE;
  GstVorbisEnc *vorbisenc;
  GstPad *peerpad;

  vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
  peerpad = gst_pad_get_peer (GST_PAD (vorbisenc->sinkpad));

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_POSITION:
    {
      GstFormat fmt, req_fmt;
      gint64 pos, val;

      gst_query_parse_position (query, &req_fmt, NULL);
      if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) {
        gst_query_set_position (query, req_fmt, val);
        break;
      }

      fmt = GST_FORMAT_TIME;
      if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
        break;

      if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val))) {
        gst_query_set_position (query, req_fmt, val);
      }
      break;
    }
    case GST_QUERY_DURATION:
    {
      GstFormat fmt, req_fmt;
      gint64 dur, val;

      gst_query_parse_duration (query, &req_fmt, NULL);
      if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) {
        gst_query_set_duration (query, req_fmt, val);
        break;
      }

      fmt = GST_FORMAT_TIME;
      if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
        break;

      if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
        gst_query_set_duration (query, req_fmt, val);
      }
      break;
    }
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;

      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
      if (!(res =
              gst_vorbis_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
                  &dest_val)))
        goto error;
      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
      break;
    }
    default:
      res = gst_pad_query_default (pad, query);
      break;
  }

error:
  gst_object_unref (peerpad);
  gst_object_unref (vorbisenc);
  return res;
}
コード例 #22
0
static GstFlowReturn
gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer)
{
  GstVorbisEnc *vorbisenc;
  GstFlowReturn ret = GST_FLOW_OK;
  gfloat *data;
  gulong size;
  gulong i, j;
  float **vorbis_buffer;
  GstBuffer *buf1, *buf2, *buf3;
  gboolean first = FALSE;

  vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));

  if (!vorbisenc->setup)
    goto not_setup;

  if (!vorbisenc->header_sent) {
    /* Vorbis streams begin with three headers; the initial header (with
       most of the codec setup parameters) which is mandated by the Ogg
       bitstream spec.  The second header holds any comment fields.  The
       third header holds the bitstream codebook.  We merely need to
       make the headers, then pass them to libvorbis one at a time;
       libvorbis handles the additional Ogg bitstream constraints */
    ogg_packet header;
    ogg_packet header_comm;
    ogg_packet header_code;
    GstCaps *caps;

    /* first, make sure header buffers get timestamp == 0 */
    vorbisenc->next_ts = 0;
    vorbisenc->granulepos_offset = 0;
    vorbisenc->subgranule_offset = 0;

    GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets");
    gst_vorbis_enc_set_metadata (vorbisenc);
    vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header,
        &header_comm, &header_code);
    vorbis_comment_clear (&vorbisenc->vc);

    /* create header buffers */
    buf1 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header);
    buf2 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_comm);
    buf3 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_code);

    /* mark and put on caps */
    vorbisenc->srccaps = gst_caps_new_simple ("audio/x-vorbis", NULL);
    caps = vorbisenc->srccaps;
    caps = gst_vorbis_enc_set_header_on_caps (caps, buf1, buf2, buf3);

    /* negotiate with these caps */
    GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
    gst_pad_set_caps (vorbisenc->srcpad, caps);

    gst_buffer_set_caps (buf1, caps);
    gst_buffer_set_caps (buf2, caps);
    gst_buffer_set_caps (buf3, caps);

    /* push out buffers */
    /* push_buffer takes the reference even for failure */
    if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf1)) != GST_FLOW_OK)
      goto failed_header_push;
    if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf2)) != GST_FLOW_OK) {
      buf2 = NULL;
      goto failed_header_push;
    }
    if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf3)) != GST_FLOW_OK) {
      buf3 = NULL;
      goto failed_header_push;
    }

    /* now adjust starting granulepos accordingly if the buffer's timestamp is
       nonzero */
    vorbisenc->next_ts = GST_BUFFER_TIMESTAMP (buffer);
    vorbisenc->expected_ts = GST_BUFFER_TIMESTAMP (buffer);
    vorbisenc->granulepos_offset = gst_util_uint64_scale
        (GST_BUFFER_TIMESTAMP (buffer), vorbisenc->frequency, GST_SECOND);
    vorbisenc->subgranule_offset = 0;
    vorbisenc->subgranule_offset =
        vorbisenc->next_ts - granulepos_to_timestamp_offset (vorbisenc, 0);

    vorbisenc->header_sent = TRUE;
    first = TRUE;
  }

  if (vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
      GST_BUFFER_TIMESTAMP (buffer) < vorbisenc->expected_ts) {
    GST_WARNING_OBJECT (vorbisenc, "Buffer is older than previous "
        "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
        "), cannot handle. Dropping buffer.",
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
        GST_TIME_ARGS (vorbisenc->expected_ts));
    gst_buffer_unref (buffer);
    return GST_FLOW_OK;
  }

  if (gst_vorbis_enc_buffer_check_discontinuous (vorbisenc, buffer) && !first) {
    GST_WARNING_OBJECT (vorbisenc, "Buffer is discontinuous, flushing encoder "
        "and restarting (Discont from %" GST_TIME_FORMAT
        " to %" GST_TIME_FORMAT ")", GST_TIME_ARGS (vorbisenc->next_ts),
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
    /* Re-initialise encoder (there's unfortunately no API to flush it) */
    if ((ret = gst_vorbis_enc_clear (vorbisenc)) != GST_FLOW_OK)
      return ret;
    if (!gst_vorbis_enc_setup (vorbisenc))
      return GST_FLOW_ERROR;    /* Should be impossible, we can only get here if
                                   we successfully initialised earlier */

    /* Now, set our granulepos offset appropriately. */
    vorbisenc->next_ts = GST_BUFFER_TIMESTAMP (buffer);
    /* We need to round to the nearest whole number of samples, not just do
     * a truncating division here */
    vorbisenc->granulepos_offset = gst_util_uint64_scale
        (GST_BUFFER_TIMESTAMP (buffer) + GST_SECOND / vorbisenc->frequency / 2
        - vorbisenc->subgranule_offset, vorbisenc->frequency, GST_SECOND);

    vorbisenc->header_sent = TRUE;

    /* And our next output buffer must have DISCONT set on it */
    vorbisenc->next_discont = TRUE;
  }

  /* Sending zero samples to libvorbis marks EOS, so we mustn't do that */
  if (GST_BUFFER_SIZE (buffer) == 0) {
    gst_buffer_unref (buffer);
    return GST_FLOW_OK;
  }

  /* data to encode */
  data = (gfloat *) GST_BUFFER_DATA (buffer);
  size = GST_BUFFER_SIZE (buffer) / (vorbisenc->channels * sizeof (float));

  /* expose the buffer to submit data */
  vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);

  /* deinterleave samples, write the buffer data */
  for (i = 0; i < size; i++) {
    for (j = 0; j < vorbisenc->channels; j++) {
      vorbis_buffer[j][i] = *data++;
    }
  }

  /* tell the library how much we actually submitted */
  vorbis_analysis_wrote (&vorbisenc->vd, size);

  vorbisenc->samples_in += size;

  gst_buffer_unref (buffer);

  ret = gst_vorbis_enc_output_buffers (vorbisenc);

  return ret;

  /* error cases */
not_setup:
  {
    gst_buffer_unref (buffer);
    GST_ELEMENT_ERROR (vorbisenc, CORE, NEGOTIATION, (NULL),
        ("encoder not initialized (input is not audio?)"));
    return GST_FLOW_UNEXPECTED;
  }
failed_header_push:
  {
    GST_WARNING_OBJECT (vorbisenc, "Failed to push headers");
    /* buf1 is always already unreffed */
    if (buf2)
      gst_buffer_unref (buf2);
    if (buf3)
      gst_buffer_unref (buf3);
    gst_buffer_unref (buffer);
    return ret;
  }
}
コード例 #23
0
static void
gst_vorbis_enc_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstVorbisEnc *vorbisenc;

  g_return_if_fail (GST_IS_VORBISENC (object));

  vorbisenc = GST_VORBISENC (object);

  switch (prop_id) {
    case ARG_MAX_BITRATE:
    {
      gboolean old_value = vorbisenc->managed;

      vorbisenc->max_bitrate = g_value_get_int (value);
      if (vorbisenc->max_bitrate >= 0
          && vorbisenc->max_bitrate < LOWEST_BITRATE) {
        g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
        vorbisenc->max_bitrate = LOWEST_BITRATE;
      }
      if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
        vorbisenc->managed = TRUE;
      else
        vorbisenc->managed = FALSE;

      if (old_value != vorbisenc->managed)
        g_object_notify (object, "managed");
      break;
    }
    case ARG_BITRATE:
      vorbisenc->bitrate = g_value_get_int (value);
      if (vorbisenc->bitrate >= 0 && vorbisenc->bitrate < LOWEST_BITRATE) {
        g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
        vorbisenc->bitrate = LOWEST_BITRATE;
      }
      break;
    case ARG_MIN_BITRATE:
    {
      gboolean old_value = vorbisenc->managed;

      vorbisenc->min_bitrate = g_value_get_int (value);
      if (vorbisenc->min_bitrate >= 0
          && vorbisenc->min_bitrate < LOWEST_BITRATE) {
        g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
        vorbisenc->min_bitrate = LOWEST_BITRATE;
      }
      if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
        vorbisenc->managed = TRUE;
      else
        vorbisenc->managed = FALSE;

      if (old_value != vorbisenc->managed)
        g_object_notify (object, "managed");
      break;
    }
    case ARG_QUALITY:
      vorbisenc->quality = g_value_get_float (value);
      if (vorbisenc->quality >= 0.0)
        vorbisenc->quality_set = TRUE;
      else
        vorbisenc->quality_set = FALSE;
      break;
    case ARG_MANAGED:
      vorbisenc->managed = g_value_get_boolean (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
コード例 #24
0
static GstFlowReturn
gst_vorbis_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
{
  GstVorbisEnc *vorbisenc;
  GstFlowReturn ret = GST_FLOW_OK;
  gfloat *data;
  gulong size;
  gulong i, j;
  float **vorbis_buffer;
  GstBuffer *buf1, *buf2, *buf3;

  vorbisenc = GST_VORBISENC (enc);

  if (G_UNLIKELY (!vorbisenc->setup)) {
    if (buffer) {
      GST_DEBUG_OBJECT (vorbisenc, "forcing setup");
      /* should not fail, as setup before same way */
      if (!gst_vorbis_enc_setup (vorbisenc))
        return GST_FLOW_ERROR;
    } else {
      /* end draining */
      GST_LOG_OBJECT (vorbisenc, "already drained");
      return GST_FLOW_OK;
    }
  }

  if (!vorbisenc->header_sent) {
    /* Vorbis streams begin with three headers; the initial header (with
       most of the codec setup parameters) which is mandated by the Ogg
       bitstream spec.  The second header holds any comment fields.  The
       third header holds the bitstream codebook.  We merely need to
       make the headers, then pass them to libvorbis one at a time;
       libvorbis handles the additional Ogg bitstream constraints */
    ogg_packet header;
    ogg_packet header_comm;
    ogg_packet header_code;
    GstCaps *caps;

    GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets");
    gst_vorbis_enc_set_metadata (vorbisenc);
    vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header,
        &header_comm, &header_code);
    vorbis_comment_clear (&vorbisenc->vc);

    /* create header buffers */
    buf1 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header);
    buf2 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_comm);
    buf3 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_code);

    /* mark and put on caps */
    caps = gst_caps_new_simple ("audio/x-vorbis", NULL);
    caps = _gst_caps_set_buffer_array (caps, "streamheader",
        buf1, buf2, buf3, NULL);

    /* negotiate with these caps */
    GST_DEBUG_OBJECT (vorbisenc, "here are the caps: %" GST_PTR_FORMAT, caps);

    gst_buffer_set_caps (buf1, caps);
    gst_buffer_set_caps (buf2, caps);
    gst_buffer_set_caps (buf3, caps);
    gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (vorbisenc), caps);
    gst_caps_unref (caps);

    /* store buffers for later pre_push sending */
    g_slist_foreach (vorbisenc->headers, (GFunc) gst_buffer_unref, NULL);
    vorbisenc->headers = NULL;
    GST_DEBUG_OBJECT (vorbisenc, "storing header buffers");
    vorbisenc->headers = g_slist_prepend (vorbisenc->headers, buf3);
    vorbisenc->headers = g_slist_prepend (vorbisenc->headers, buf2);
    vorbisenc->headers = g_slist_prepend (vorbisenc->headers, buf1);

    vorbisenc->header_sent = TRUE;
  }

  if (!buffer)
    return gst_vorbis_enc_clear (vorbisenc);

  /* data to encode */
  data = (gfloat *) GST_BUFFER_DATA (buffer);
  size = GST_BUFFER_SIZE (buffer) / (vorbisenc->channels * sizeof (float));

  /* expose the buffer to submit data */
  vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);

  /* deinterleave samples, write the buffer data */
  for (i = 0; i < size; i++) {
    for (j = 0; j < vorbisenc->channels; j++) {
      vorbis_buffer[j][i] = *data++;
    }
  }

  /* tell the library how much we actually submitted */
  vorbis_analysis_wrote (&vorbisenc->vd, size);

  GST_LOG_OBJECT (vorbisenc, "wrote %lu samples to vorbis", size);

  vorbisenc->samples_in += size;

  ret = gst_vorbis_enc_output_buffers (vorbisenc);

  return ret;
}