static GstFlowReturn
gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc)
{
  GstFlowReturn ret;

  /* vorbis does some data preanalysis, then divides up blocks for
     more involved (potentially parallel) processing.  Get a single
     block for encoding now */
  while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) {
    ogg_packet op;

    GST_LOG_OBJECT (vorbisenc, "analysed to a block");

    /* analysis */
    vorbis_analysis (&vorbisenc->vb, NULL);
    vorbis_bitrate_addblock (&vorbisenc->vb);

    while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) {
      GstBuffer *buf;

      if (op.e_o_s) {
        GstAudioEncoder *enc = GST_AUDIO_ENCODER (vorbisenc);
        GstClockTime duration;

        GST_DEBUG_OBJECT (vorbisenc, "Got EOS packet from libvorbis");
        GST_AUDIO_ENCODER_STREAM_LOCK (enc);
        if (!GST_CLOCK_TIME_IS_VALID (enc->output_segment.stop)) {
          GST_DEBUG_OBJECT (vorbisenc,
              "Output segment has no end time, setting");
          duration =
              gst_util_uint64_scale (op.granulepos, GST_SECOND,
              vorbisenc->frequency);
          enc->output_segment.stop = enc->output_segment.start + duration;
          GST_DEBUG_OBJECT (enc, "new output segment %" GST_SEGMENT_FORMAT,
              &enc->output_segment);
          gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (enc),
              gst_event_new_segment (&enc->output_segment));
        }
        GST_AUDIO_ENCODER_STREAM_UNLOCK (enc);
      }

      GST_LOG_OBJECT (vorbisenc, "pushing out a data packet");
      buf =
          gst_audio_encoder_allocate_output_buffer (GST_AUDIO_ENCODER
          (vorbisenc), op.bytes);
      gst_buffer_fill (buf, 0, op.packet, op.bytes);
      /* tracking granulepos should tell us samples accounted for */
      ret =
          gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER
          (vorbisenc), buf, op.granulepos - vorbisenc->samples_out);
      vorbisenc->samples_out = op.granulepos;

      if (ret != GST_FLOW_OK)
        return ret;
    }
  }

  return GST_FLOW_OK;
}
static GstFlowReturn
gst_two_lame_flush_full (GstTwoLame * lame, gboolean push)
{
  GstBuffer *buf;
  GstMapInfo map;
  gint size;
  GstFlowReturn result = GST_FLOW_OK;

  if (!lame->glopts)
    return GST_FLOW_OK;

  buf = gst_buffer_new_and_alloc (16384);
  gst_buffer_map (buf, &map, GST_MAP_WRITE);
  size = twolame_encode_flush (lame->glopts, map.data, 16384);
  gst_buffer_unmap (buf, &map);

  if (size > 0 && push) {
    gst_buffer_set_size (buf, size);
    GST_DEBUG_OBJECT (lame, "pushing final packet of %u bytes", size);
    result = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (lame), buf, -1);
  } else {
    GST_DEBUG_OBJECT (lame, "no final packet (size=%d, push=%d)", size, push);
    gst_buffer_unref (buf);
    result = GST_FLOW_OK;
  }
  return result;
}
示例#3
0
static void
gst_opus_enc_init (GstOpusEnc * enc, GstOpusEncClass * klass)
{
  GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);

  GST_DEBUG_OBJECT (enc, "init");

  enc->property_lock = g_mutex_new ();

  enc->n_channels = -1;
  enc->sample_rate = -1;
  enc->frame_samples = 0;

  enc->bitrate = DEFAULT_BITRATE;
  enc->bandwidth = DEFAULT_BANDWIDTH;
  enc->frame_size = DEFAULT_FRAMESIZE;
  enc->cbr = DEFAULT_CBR;
  enc->constrained_vbr = DEFAULT_CONSTRAINED_VBR;
  enc->complexity = DEFAULT_COMPLEXITY;
  enc->inband_fec = DEFAULT_INBAND_FEC;
  enc->dtx = DEFAULT_DTX;
  enc->packet_loss_percentage = DEFAULT_PACKET_LOSS_PERCENT;
  enc->max_payload_size = DEFAULT_MAX_PAYLOAD_SIZE;

  /* arrange granulepos marking (and required perfect ts) */
  gst_audio_encoder_set_mark_granule (benc, TRUE);
  gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
}
示例#4
0
static GstFlowReturn
gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
{
  GstSpeexEnc *enc;
  GstFlowReturn ret = GST_FLOW_OK;

  enc = GST_SPEEX_ENC (benc);

  if (!enc->header_sent) {
    /* Speex streams begin with two 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.
       We merely need to make the headers, then pass them to libspeex 
       one at a time; libspeex handles the additional Ogg bitstream 
       constraints */
    GstBuffer *buf1, *buf2;
    GstCaps *caps;
    guchar *data;
    gint data_len;
    GList *headers;

    /* create header buffer */
    data = (guint8 *) speex_header_to_packet (&enc->header, &data_len);
    buf1 = gst_buffer_new_wrapped (data, data_len);
    GST_BUFFER_OFFSET_END (buf1) = 0;
    GST_BUFFER_OFFSET (buf1) = 0;

    /* create comment buffer */
    buf2 = gst_speex_enc_create_metadata_buffer (enc);

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

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

    gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
    gst_caps_unref (caps);

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

    enc->header_sent = TRUE;
  }

  GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
      buf ? gst_buffer_get_size (buf) : 0);

  ret = gst_speex_enc_encode (enc, buf);

  return ret;
}
示例#5
0
static void
gst_fdkaacenc_init (GstFdkAacEnc * self)
{
  self->bitrate = DEFAULT_BITRATE;
  self->enc = NULL;

  gst_audio_encoder_set_drainable (GST_AUDIO_ENCODER (self), TRUE);
}
示例#6
0
static void
gst_speex_enc_init (GstSpeexEnc * enc)
{
  GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc);

  /* arrange granulepos marking (and required perfect ts) */
  gst_audio_encoder_set_mark_granule (benc, TRUE);
  gst_audio_encoder_set_perfect_timestamp (benc, TRUE);
}
示例#7
0
static void
gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc)
{
  GstFFMpegAudEncClass *klass =
      (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);

  /* ffmpeg objects */
  ffmpegaudenc->context = avcodec_alloc_context3 (klass->in_plugin);
  ffmpegaudenc->opened = FALSE;

  gst_audio_encoder_set_drainable (GST_AUDIO_ENCODER (ffmpegaudenc), TRUE);
}
示例#8
0
static GstFlowReturn
gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc)
{
    GstFlowReturn ret;

    /* vorbis does some data preanalysis, then divides up blocks for
       more involved (potentially parallel) processing.  Get a single
       block for encoding now */
    while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) {
        ogg_packet op;

        GST_LOG_OBJECT (vorbisenc, "analysed to a block");

        /* analysis */
        vorbis_analysis (&vorbisenc->vb, NULL);
        vorbis_bitrate_addblock (&vorbisenc->vb);

        while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) {
            GstBuffer *buf;

            GST_LOG_OBJECT (vorbisenc, "pushing out a data packet");
            buf =
                gst_audio_encoder_allocate_output_buffer (GST_AUDIO_ENCODER
                        (vorbisenc), op.bytes);
            gst_buffer_fill (buf, 0, op.packet, op.bytes);
            /* tracking granulepos should tell us samples accounted for */
            ret =
                gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER
                                                (vorbisenc), buf, op.granulepos - vorbisenc->samples_out);
            vorbisenc->samples_out = op.granulepos;

            if (ret != GST_FLOW_OK)
                return ret;
        }
    }

    return GST_FLOW_OK;
}
示例#9
0
static GstFlowReturn
gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc,
    GstBuffer * buffer, gint * have_data)
{
  GstAudioEncoder *enc;
  AVCodecContext *ctx;
  gint res;
  GstFlowReturn ret;
  GstAudioInfo *info;
  AVPacket *pkt;
  AVFrame *frame = ffmpegaudenc->frame;
  gboolean planar;
  gint nsamples = -1;

  enc = GST_AUDIO_ENCODER (ffmpegaudenc);

  ctx = ffmpegaudenc->context;

  pkt = g_slice_new0 (AVPacket);

  if (buffer != NULL) {
    BufferInfo *buffer_info = g_slice_new0 (BufferInfo);
    guint8 *audio_in;
    guint in_size;

    buffer_info->buffer = buffer;
    gst_buffer_map (buffer, &buffer_info->map, GST_MAP_READ);
    audio_in = buffer_info->map.data;
    in_size = buffer_info->map.size;

    GST_LOG_OBJECT (ffmpegaudenc, "encoding buffer %p size:%u", audio_in,
        in_size);

    info = gst_audio_encoder_get_audio_info (enc);
    planar = av_sample_fmt_is_planar (ffmpegaudenc->context->sample_fmt);

    if (planar && info->channels > 1) {
      gint channels;
      gint i, j;

      nsamples = frame->nb_samples = in_size / info->bpf;
      channels = info->channels;

      frame->buf[0] =
          av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);

      if (info->channels > AV_NUM_DATA_POINTERS) {
        buffer_info->ext_data_array = frame->extended_data =
            g_new (uint8_t *, info->channels);
      } else {
示例#10
0
static gboolean
gst_gsmenc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
{
  GstCaps *srccaps;

  srccaps = gst_static_pad_template_get_caps (&gsmenc_src_template);
  gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (benc), srccaps);

  /* report needs to base class */
  gst_audio_encoder_set_frame_samples_min (benc, 160);
  gst_audio_encoder_set_frame_samples_max (benc, 160);
  gst_audio_encoder_set_frame_max (benc, 1);

  return TRUE;
}
示例#11
0
static void
gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc)
{
    GstFFMpegAudEncClass *klass =
        (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);

    GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (ffmpegaudenc));

    /* ffmpeg objects */
    ffmpegaudenc->context = avcodec_alloc_context3 (klass->in_plugin);
    ffmpegaudenc->opened = FALSE;
    ffmpegaudenc->frame = av_frame_alloc ();

    ffmpegaudenc->compliance = FFMPEG_DEFAULT_COMPLIANCE;

    gst_audio_encoder_set_drainable (GST_AUDIO_ENCODER (ffmpegaudenc), TRUE);
}
示例#12
0
static GstBuffer *
gst_vorbis_enc_buffer_from_header_packet (GstVorbisEnc * vorbisenc,
        ogg_packet * packet)
{
    GstBuffer *outbuf;

    outbuf =
        gst_audio_encoder_allocate_output_buffer (GST_AUDIO_ENCODER (vorbisenc),
                packet->bytes);
    gst_buffer_fill (outbuf, 0, packet->packet, packet->bytes);
    GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out;
    GST_BUFFER_OFFSET_END (outbuf) = 0;
    GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
    GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;

    GST_DEBUG ("created header packet buffer, %" G_GSIZE_FORMAT " bytes",
               gst_buffer_get_size (outbuf));
    return outbuf;
}
示例#13
0
static void
gst_vorbis_enc_init (GstVorbisEnc * vorbisenc, GstVorbisEncClass * klass)
{
  GstAudioEncoder *enc = GST_AUDIO_ENCODER (vorbisenc);

  vorbisenc->channels = -1;
  vorbisenc->frequency = -1;

  vorbisenc->managed = FALSE;
  vorbisenc->max_bitrate = MAX_BITRATE_DEFAULT;
  vorbisenc->bitrate = BITRATE_DEFAULT;
  vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT;
  vorbisenc->quality = QUALITY_DEFAULT;
  vorbisenc->quality_set = FALSE;
  vorbisenc->last_message = NULL;

  /* arrange granulepos marking (and required perfect ts) */
  gst_audio_encoder_set_mark_granule (enc, TRUE);
  gst_audio_encoder_set_perfect_timestamp (enc, TRUE);
}
static void
gst_mulawenc_set_tags (GstMuLawEnc * mulawenc)
{
  GstTagList *taglist;
  guint bitrate;

  /* bitrate of mulaw is 8 bits/sample * sample rate * number of channels */
  bitrate = 8 * mulawenc->rate * mulawenc->channels;

  taglist = gst_tag_list_new_empty ();
  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
      GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
      GST_TAG_MINIMUM_BITRATE, bitrate, NULL);
  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
      GST_TAG_BITRATE, bitrate, NULL);

  gst_audio_encoder_merge_tags (GST_AUDIO_ENCODER (mulawenc),
      taglist, GST_TAG_MERGE_REPLACE);

  gst_tag_list_unref (taglist);
}
示例#15
0
static GstFlowReturn
gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc,
    guint8 * audio_in, guint in_size, gint * have_data)
{
  GstAudioEncoder *enc;
  AVCodecContext *ctx;
  gint res;
  GstFlowReturn ret;
  GstAudioInfo *info;
  AVPacket pkt;
  AVFrame frame;
  gboolean planar;

  enc = GST_AUDIO_ENCODER (ffmpegaudenc);

  ctx = ffmpegaudenc->context;

  GST_LOG_OBJECT (ffmpegaudenc, "encoding buffer ");

  memset (&pkt, 0, sizeof (pkt));
  memset (&frame, 0, sizeof (frame));
  avcodec_get_frame_defaults (&frame);

  info = gst_audio_encoder_get_audio_info (enc);
  planar = av_sample_fmt_is_planar (ffmpegaudenc->context->sample_fmt);

  if (planar && info->channels > 1) {
    gint channels, nsamples;
    gint i, j;

    nsamples = frame.nb_samples = in_size / info->bpf;
    channels = info->channels;

    if (info->channels > AV_NUM_DATA_POINTERS) {
      frame.extended_data = g_new (uint8_t *, info->channels);
    } else {
示例#16
0
static gboolean
gst_amrnbenc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
{
  GstAmrnbEnc *amrnbenc;
  GstCaps *copy;

  amrnbenc = GST_AMRNBENC (enc);

  /* parameters already parsed for us */
  amrnbenc->rate = GST_AUDIO_INFO_RATE (info);
  amrnbenc->channels = GST_AUDIO_INFO_CHANNELS (info);

  /* we do not really accept other input, but anyway ... */
  /* this is not wrong but will sound bad */
  if (amrnbenc->channels != 1) {
    g_warning ("amrnbdec is only optimized for mono channels");
  }
  if (amrnbenc->rate != 8000) {
    g_warning ("amrnbdec is only optimized for 8000 Hz samplerate");
  }

  /* create reverse caps */
  copy = gst_caps_new_simple ("audio/AMR",
      "channels", G_TYPE_INT, amrnbenc->channels,
      "rate", G_TYPE_INT, amrnbenc->rate, NULL);

  gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (amrnbenc), copy);
  gst_caps_unref (copy);

  /* report needs to base class: hand one frame at a time */
  gst_audio_encoder_set_frame_samples_min (enc, 160);
  gst_audio_encoder_set_frame_samples_max (enc, 160);
  gst_audio_encoder_set_frame_max (enc, 1);

  return TRUE;
}
示例#17
0
static GstFlowReturn
gst_celt_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
{
  GstCeltEnc *enc;
  GstFlowReturn ret = GST_FLOW_OK;

  enc = GST_CELT_ENC (benc);

  if (!enc->header_sent) {
    /* Celt streams begin with two 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.
       We merely need to make the headers, then pass them to libcelt 
       one at a time; libcelt handles the additional Ogg bitstream 
       constraints */
    GstBuffer *buf1, *buf2;
    GstCaps *caps;
    /* libcelt has a bug which underestimates header size by 4... */
    unsigned int header_size = enc->header.header_size + 4;
    unsigned char *data = g_malloc (header_size);
    GList *headers;

    /* create header buffer */
    int error = celt_header_to_packet (&enc->header, data, header_size);
    if (error < 0) {
      g_free (data);
      goto no_header;
    }
    buf1 = gst_buffer_new_wrapped (data, header_size);
    GST_BUFFER_OFFSET_END (buf1) = 0;
    GST_BUFFER_OFFSET (buf1) = 0;

    /* create comment buffer */
    buf2 = gst_celt_enc_create_metadata_buffer (enc);

    /* mark and put on caps */
    caps = gst_caps_new_simple ("audio/x-celt",
        "rate", G_TYPE_INT, enc->rate,
        "channels", G_TYPE_INT, enc->channels,
        "frame-size", G_TYPE_INT, enc->frame_size, NULL);
    caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);

    /* negotiate with these caps */
    GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
    GST_LOG_OBJECT (enc, "rate=%d channels=%d frame-size=%d",
        enc->rate, enc->channels, enc->frame_size);
    gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
    gst_caps_unref (caps);

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

    enc->header_sent = TRUE;
  }

  GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes",
      buf, buf ? gst_buffer_get_size (buf) : 0);

  ret = gst_celt_enc_encode (enc, buf);

done:
  return ret;

  /* ERRORS */
no_header:
  {
    GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
        ("Failed to encode header"));
    ret = GST_FLOW_ERROR;
    goto done;
  }
}
示例#18
0
static gboolean
gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
{
  GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
  GstCaps *other_caps;
  GstCaps *allowed_caps;
  GstCaps *icaps;
  gsize frame_size;
  GstFFMpegAudEncClass *oclass =
      (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);

  /* close old session */
  if (ffmpegaudenc->opened) {
    gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
    ffmpegaudenc->opened = FALSE;
  }

  /* if we set it in _getcaps we should set it also in _link */
  ffmpegaudenc->context->strict_std_compliance = -1;

  /* user defined properties */
  if (ffmpegaudenc->bitrate > 0) {
    GST_INFO_OBJECT (ffmpegaudenc, "Setting avcontext to bitrate %d",
        ffmpegaudenc->bitrate);
    ffmpegaudenc->context->bit_rate = ffmpegaudenc->bitrate;
    ffmpegaudenc->context->bit_rate_tolerance = ffmpegaudenc->bitrate;
  } else {
    GST_INFO_OBJECT (ffmpegaudenc, "Using avcontext default bitrate %d",
        ffmpegaudenc->context->bit_rate);
  }

  /* RTP payload used for GOB production (for Asterisk) */
  if (ffmpegaudenc->rtp_payload_size) {
    ffmpegaudenc->context->rtp_payload_size = ffmpegaudenc->rtp_payload_size;
  }

  /* some other defaults */
  ffmpegaudenc->context->rc_strategy = 2;
  ffmpegaudenc->context->b_frame_strategy = 0;
  ffmpegaudenc->context->coder_type = 0;
  ffmpegaudenc->context->context_model = 0;
  ffmpegaudenc->context->scenechange_threshold = 0;
  ffmpegaudenc->context->inter_threshold = 0;

  /* fetch pix_fmt and so on */
  gst_ffmpeg_audioinfo_to_context (info, ffmpegaudenc->context);
  if (!ffmpegaudenc->context->time_base.den) {
    ffmpegaudenc->context->time_base.den = GST_AUDIO_INFO_RATE (info);
    ffmpegaudenc->context->time_base.num = 1;
    ffmpegaudenc->context->ticks_per_frame = 1;
  }

  if (ffmpegaudenc->context->channel_layout) {
    gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout,
        ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout);
    ffmpegaudenc->needs_reorder =
        (memcmp (ffmpegaudenc->ffmpeg_layout, info->position,
            sizeof (GstAudioChannelPosition) *
            ffmpegaudenc->context->channels) != 0);
  }

  /* open codec */
  if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) {
    if (ffmpegaudenc->context->priv_data)
      gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
    GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec",
        oclass->in_plugin->name);
    return FALSE;
  }

  /* some codecs support more than one format, first auto-choose one */
  GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ...");
  allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
  if (!allowed_caps) {
    GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps");
    /* we need to copy because get_allowed_caps returns a ref, and
     * get_pad_template_caps doesn't */
    allowed_caps =
        gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
  }
  GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
  gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
      oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context);

  /* try to set this caps on the other side */
  other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
      ffmpegaudenc->context, TRUE);

  if (!other_caps) {
    gst_caps_unref (allowed_caps);
    gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
    GST_DEBUG ("Unsupported codec - no caps found");
    return FALSE;
  }

  icaps = gst_caps_intersect (allowed_caps, other_caps);
  gst_caps_unref (allowed_caps);
  gst_caps_unref (other_caps);
  if (gst_caps_is_empty (icaps)) {
    gst_caps_unref (icaps);
    return FALSE;
  }
  icaps = gst_caps_truncate (icaps);

  if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc),
          icaps)) {
    gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
    gst_caps_unref (icaps);
    return FALSE;
  }
  gst_caps_unref (icaps);

  frame_size = ffmpegaudenc->context->frame_size;
  if (frame_size > 1) {
    gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
        frame_size);
    gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
        frame_size);
    gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 1);
  } else {
    gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
        0);
    gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
        0);
    gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0);
  }

  /* success! */
  ffmpegaudenc->opened = TRUE;

  return TRUE;
}
示例#19
0
static gboolean
gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
{
    GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
    GstCaps *other_caps;
    GstCaps *allowed_caps;
    GstCaps *icaps;
    gsize frame_size;
    GstFFMpegAudEncClass *oclass =
        (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);

    /* close old session */
    if (ffmpegaudenc->opened) {
        gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
        ffmpegaudenc->opened = FALSE;
        if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
                                           oclass->in_plugin) < 0) {
            GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
            return FALSE;
        }
    }

    /* if we set it in _getcaps we should set it also in _link */
    ffmpegaudenc->context->strict_std_compliance = ffmpegaudenc->compliance;

    /* user defined properties */
    if (ffmpegaudenc->bitrate > 0) {
        GST_INFO_OBJECT (ffmpegaudenc, "Setting avcontext to bitrate %d",
                         ffmpegaudenc->bitrate);
        ffmpegaudenc->context->bit_rate = ffmpegaudenc->bitrate;
        ffmpegaudenc->context->bit_rate_tolerance = ffmpegaudenc->bitrate;
    } else {
        GST_INFO_OBJECT (ffmpegaudenc,
                         "Using avcontext default bitrate %" G_GINT64_FORMAT,
                         (gint64) ffmpegaudenc->context->bit_rate);
    }

    /* RTP payload used for GOB production (for Asterisk) */
    if (ffmpegaudenc->rtp_payload_size) {
        ffmpegaudenc->context->rtp_payload_size = ffmpegaudenc->rtp_payload_size;
    }

    /* some other defaults */
    ffmpegaudenc->context->rc_strategy = 2;
    ffmpegaudenc->context->b_frame_strategy = 0;
    ffmpegaudenc->context->coder_type = 0;
    ffmpegaudenc->context->context_model = 0;
    ffmpegaudenc->context->scenechange_threshold = 0;

    /* fetch pix_fmt and so on */
    gst_ffmpeg_audioinfo_to_context (info, ffmpegaudenc->context);
    if (!ffmpegaudenc->context->time_base.den) {
        ffmpegaudenc->context->time_base.den = GST_AUDIO_INFO_RATE (info);
        ffmpegaudenc->context->time_base.num = 1;
        ffmpegaudenc->context->ticks_per_frame = 1;
    }

    if (ffmpegaudenc->context->channel_layout) {
        gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout,
                                          ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout);
        ffmpegaudenc->needs_reorder =
            (memcmp (ffmpegaudenc->ffmpeg_layout, info->position,
                     sizeof (GstAudioChannelPosition) *
                     ffmpegaudenc->context->channels) != 0);
    }

    /* some codecs support more than one format, first auto-choose one */
    GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ...");
    allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
    if (!allowed_caps) {
        GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps");
        /* we need to copy because get_allowed_caps returns a ref, and
         * get_pad_template_caps doesn't */
        allowed_caps =
            gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
    }
    GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
    gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
                                  oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context);

    /* open codec */
    if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) {
        gst_caps_unref (allowed_caps);
        gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
        GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec",
                          oclass->in_plugin->name);
        if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
                                           oclass->in_plugin) < 0)
            GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");

        if ((oclass->in_plugin->capabilities & CODEC_CAP_EXPERIMENTAL) &&
                ffmpegaudenc->compliance != GST_FFMPEG_EXPERIMENTAL) {
            GST_ELEMENT_ERROR (ffmpegaudenc, LIBRARY, SETTINGS,
                               ("Codec is experimental, but settings don't allow encoders to "
                                "produce output of experimental quality"),
                               ("This codec may not create output that is conformant to the specs "
                                "or of good quality. If you must use it anyway, set the "
                                "compliance property to experimental"));
        }
        return FALSE;
    }

    /* try to set this caps on the other side */
    other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
                 ffmpegaudenc->context, TRUE);

    if (!other_caps) {
        gst_caps_unref (allowed_caps);
        gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
        GST_DEBUG ("Unsupported codec - no caps found");
        if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
                                           oclass->in_plugin) < 0)
            GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
        return FALSE;
    }

    icaps = gst_caps_intersect (allowed_caps, other_caps);
    gst_caps_unref (allowed_caps);
    gst_caps_unref (other_caps);
    if (gst_caps_is_empty (icaps)) {
        gst_caps_unref (icaps);
        return FALSE;
    }
    icaps = gst_caps_fixate (icaps);

    if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc),
            icaps)) {
        gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
        gst_caps_unref (icaps);
        if (avcodec_get_context_defaults3 (ffmpegaudenc->context,
                                           oclass->in_plugin) < 0)
            GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
        return FALSE;
    }
    gst_caps_unref (icaps);

    frame_size = ffmpegaudenc->context->frame_size;
    if (frame_size > 1) {
        gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
                frame_size);
        gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
                frame_size);
        gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 1);
    } else {
        gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
                0);
        gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
                0);
        gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0);
    }

    /* Store some tags */
    {
        GstTagList *tags = gst_tag_list_new_empty ();
        const gchar *codec;

        gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
                          (guint) ffmpegaudenc->context->bit_rate, NULL);

        if ((codec =
                    gst_ffmpeg_get_codecid_longname (ffmpegaudenc->context->codec_id)))
            gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec,
                              NULL);

        gst_audio_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE);
        gst_tag_list_unref (tags);
    }

    /* success! */
    ffmpegaudenc->opened = TRUE;

    return TRUE;
}
示例#20
0
static GstFlowReturn
gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
{
  guint8 *bdata, *data, *mdata = NULL;
  gsize bsize, size;
  gsize bytes;
  gint ret = GST_FLOW_OK;
  gint outsize;
  GstBuffer *outbuf;

  g_mutex_lock (enc->property_lock);

  bytes = enc->frame_samples * enc->n_channels * 2;
  if (G_LIKELY (buf)) {
    bdata = GST_BUFFER_DATA (buf);
    bsize = GST_BUFFER_SIZE (buf);
    if (G_UNLIKELY (bsize % bytes)) {
      GST_DEBUG_OBJECT (enc, "draining; adding silence samples");

      size = ((bsize / bytes) + 1) * bytes;
      mdata = g_malloc0 (size);
      memcpy (mdata, bdata, bsize);
      bdata = NULL;
      data = mdata;
    } else {
      data = bdata;
      size = bsize;
    }
  } else {
    GST_DEBUG_OBJECT (enc, "nothing to drain");
    goto done;
  }

  g_assert (size == bytes);

  ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
      GST_BUFFER_OFFSET_NONE, enc->max_payload_size * enc->n_channels,
      GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);

  if (GST_FLOW_OK != ret)
    goto done;

  GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)",
      enc->frame_samples, (int) bytes);

  outsize =
      opus_multistream_encode (enc->state, (const gint16 *) data,
      enc->frame_samples, GST_BUFFER_DATA (outbuf),
      enc->max_payload_size * enc->n_channels);

  if (outsize < 0) {
    GST_ERROR_OBJECT (enc, "Encoding failed: %d", outsize);
    ret = GST_FLOW_ERROR;
    goto done;
  } else if (outsize > enc->max_payload_size) {
    GST_WARNING_OBJECT (enc,
        "Encoded size %d is higher than max payload size (%d bytes)",
        outsize, enc->max_payload_size);
    ret = GST_FLOW_ERROR;
    goto done;
  }

  GST_DEBUG_OBJECT (enc, "Output packet is %u bytes", outsize);
  GST_BUFFER_SIZE (outbuf) = outsize;

  ret =
      gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc), outbuf,
      enc->frame_samples);

done:

  g_mutex_unlock (enc->property_lock);

  if (mdata)
    g_free (mdata);

  return ret;
}
示例#21
0
static void
gst_opus_enc_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstOpusEnc *enc;

  enc = GST_OPUS_ENC (object);

#define GST_OPUS_UPDATE_PROPERTY(prop,type,ctl) do { \
  g_mutex_lock (enc->property_lock); \
  enc->prop = g_value_get_##type (value); \
  if (enc->state) { \
    opus_multistream_encoder_ctl (enc->state, OPUS_SET_##ctl (enc->prop)); \
  } \
  g_mutex_unlock (enc->property_lock); \
} while(0)

  switch (prop_id) {
    case PROP_AUDIO:
      enc->audio_or_voip = g_value_get_boolean (value);
      break;
    case PROP_BITRATE:
      GST_OPUS_UPDATE_PROPERTY (bitrate, int, BITRATE);
      break;
    case PROP_BANDWIDTH:
      GST_OPUS_UPDATE_PROPERTY (bandwidth, enum, BANDWIDTH);
      break;
    case PROP_FRAME_SIZE:
      g_mutex_lock (enc->property_lock);
      enc->frame_size = g_value_get_enum (value);
      enc->frame_samples = gst_opus_enc_get_frame_samples (enc);
      gst_opus_enc_setup_base_class (enc, GST_AUDIO_ENCODER (enc));
      g_mutex_unlock (enc->property_lock);
      break;
    case PROP_CBR:
      /* this one has an opposite meaning to the opus ctl... */
      g_mutex_lock (enc->property_lock);
      enc->cbr = g_value_get_boolean (value);
      opus_multistream_encoder_ctl (enc->state, OPUS_SET_VBR (!enc->cbr));
      g_mutex_unlock (enc->property_lock);
      break;
    case PROP_CONSTRAINED_VBR:
      GST_OPUS_UPDATE_PROPERTY (constrained_vbr, boolean, VBR_CONSTRAINT);
      break;
    case PROP_COMPLEXITY:
      GST_OPUS_UPDATE_PROPERTY (complexity, int, COMPLEXITY);
      break;
    case PROP_INBAND_FEC:
      GST_OPUS_UPDATE_PROPERTY (inband_fec, boolean, INBAND_FEC);
      break;
    case PROP_DTX:
      GST_OPUS_UPDATE_PROPERTY (dtx, boolean, DTX);
      break;
    case PROP_PACKET_LOSS_PERCENT:
      GST_OPUS_UPDATE_PROPERTY (packet_loss_percentage, int, PACKET_LOSS_PERC);
      break;
    case PROP_MAX_PAYLOAD_SIZE:
      g_mutex_lock (enc->property_lock);
      enc->max_payload_size = g_value_get_uint (value);
      g_mutex_unlock (enc->property_lock);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }

#undef GST_OPUS_UPDATE_PROPERTY

}
示例#22
0
static gboolean
gst_omx_audio_enc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
{
  GstOMXAudioEnc *self;
  GstOMXAudioEncClass *klass;
  gboolean needs_disable = FALSE;
  OMX_PARAM_PORTDEFINITIONTYPE port_def;
  OMX_AUDIO_PARAM_PCMMODETYPE pcm_param;
  gint i;
  OMX_ERRORTYPE err;

  self = GST_OMX_AUDIO_ENC (encoder);
  klass = GST_OMX_AUDIO_ENC_GET_CLASS (encoder);

  GST_DEBUG_OBJECT (self, "Setting new caps");

  /* Set audio encoder base class properties */
  gst_audio_encoder_set_frame_samples_min (encoder,
      gst_util_uint64_scale_ceil (OMX_MIN_PCMPAYLOAD_MSEC,
          GST_MSECOND * info->rate, GST_SECOND));
  gst_audio_encoder_set_frame_samples_max (encoder, 0);

  gst_omx_port_get_port_definition (self->enc_in_port, &port_def);

  needs_disable =
      gst_omx_component_get_state (self->enc,
      GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
  /* If the component is not in Loaded state and a real format change happens
   * we have to disable the port and re-allocate all buffers. If no real
   * format change happened we can just exit here.
   */
  if (needs_disable) {
    GST_DEBUG_OBJECT (self, "Need to disable and drain encoder");
    gst_omx_audio_enc_drain (self);
    gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, TRUE);

    /* Wait until the srcpad loop is finished,
     * unlock GST_AUDIO_ENCODER_STREAM_LOCK to prevent deadlocks
     * caused by using this lock from inside the loop function */
    GST_AUDIO_ENCODER_STREAM_UNLOCK (self);
    gst_pad_stop_task (GST_AUDIO_ENCODER_SRC_PAD (encoder));
    GST_AUDIO_ENCODER_STREAM_LOCK (self);

    if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
      GST_AUDIO_ENCODER_STREAM_UNLOCK (self);
      gst_omx_audio_enc_stop (GST_AUDIO_ENCODER (self));
      gst_omx_audio_enc_close (GST_AUDIO_ENCODER (self));
      GST_AUDIO_ENCODER_STREAM_LOCK (self);

      if (!gst_omx_audio_enc_open (GST_AUDIO_ENCODER (self)))
        return FALSE;
      needs_disable = FALSE;
    } else {
      if (gst_omx_port_set_enabled (self->enc_in_port, FALSE) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_wait_buffers_released (self->enc_in_port,
              5 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_wait_buffers_released (self->enc_out_port,
              1 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_deallocate_buffers (self->enc_in_port) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_deallocate_buffers (self->enc_out_port) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_wait_enabled (self->enc_in_port,
              1 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_wait_enabled (self->enc_out_port,
              1 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;
    }

    GST_DEBUG_OBJECT (self, "Encoder drained and disabled");
  }

  port_def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
  GST_DEBUG_OBJECT (self, "Setting inport port definition");
  if (gst_omx_port_update_port_definition (self->enc_in_port,
          &port_def) != OMX_ErrorNone)
    return FALSE;

  GST_OMX_INIT_STRUCT (&pcm_param);
  pcm_param.nPortIndex = self->enc_in_port->index;
  pcm_param.nChannels = info->channels;
  pcm_param.eNumData =
      ((info->finfo->flags & GST_AUDIO_FORMAT_FLAG_SIGNED) ?
      OMX_NumericalDataSigned : OMX_NumericalDataUnsigned);
  pcm_param.eEndian =
      ((info->finfo->endianness == G_LITTLE_ENDIAN) ?
      OMX_EndianLittle : OMX_EndianBig);
  pcm_param.bInterleaved = OMX_TRUE;
  pcm_param.nBitPerSample = info->finfo->width;
  pcm_param.nSamplingRate = info->rate;
  pcm_param.ePCMMode = OMX_AUDIO_PCMModeLinear;

  for (i = 0; i < pcm_param.nChannels; i++) {
    OMX_AUDIO_CHANNELTYPE pos;

    switch (info->position[i]) {
      case GST_AUDIO_CHANNEL_POSITION_MONO:
      case GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER:
        pos = OMX_AUDIO_ChannelCF;
        break;
      case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT:
        pos = OMX_AUDIO_ChannelLF;
        break;
      case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT:
        pos = OMX_AUDIO_ChannelRF;
        break;
      case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT:
        pos = OMX_AUDIO_ChannelLS;
        break;
      case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT:
        pos = OMX_AUDIO_ChannelRS;
        break;
      case GST_AUDIO_CHANNEL_POSITION_LFE1:
        pos = OMX_AUDIO_ChannelLFE;
        break;
      case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER:
        pos = OMX_AUDIO_ChannelCS;
        break;
      case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT:
        pos = OMX_AUDIO_ChannelLR;
        break;
      case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT:
        pos = OMX_AUDIO_ChannelRR;
        break;
      default:
        pos = OMX_AUDIO_ChannelNone;
        break;
    }
    pcm_param.eChannelMapping[i] = pos;
  }

  GST_DEBUG_OBJECT (self, "Setting PCM parameters");
  err =
      gst_omx_component_set_parameter (self->enc, OMX_IndexParamAudioPcm,
      &pcm_param);
  if (err != OMX_ErrorNone) {
    GST_ERROR_OBJECT (self, "Failed to set PCM parameters: %s (0x%08x)",
        gst_omx_error_to_string (err), err);
    return FALSE;
  }

  if (klass->set_format) {
    if (!klass->set_format (self, self->enc_in_port, info)) {
      GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
      return FALSE;
    }
  }

  GST_DEBUG_OBJECT (self, "Updating outport port definition");
  if (gst_omx_port_update_port_definition (self->enc_out_port,
          NULL) != OMX_ErrorNone)
    return FALSE;

  GST_DEBUG_OBJECT (self, "Enabling component");
  if (needs_disable) {
    if (gst_omx_port_set_enabled (self->enc_in_port, TRUE) != OMX_ErrorNone)
      return FALSE;
    if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
      return FALSE;

    if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
      if (gst_omx_port_set_enabled (self->enc_out_port, TRUE) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
        return FALSE;

      if (gst_omx_port_wait_enabled (self->enc_out_port,
              5 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;
    }

    if (gst_omx_port_wait_enabled (self->enc_in_port,
            5 * GST_SECOND) != OMX_ErrorNone)
      return FALSE;
    if (gst_omx_port_mark_reconfigured (self->enc_in_port) != OMX_ErrorNone)
      return FALSE;
  } else {
    if (!(klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
      /* Disable output port */
      if (gst_omx_port_set_enabled (self->enc_out_port, FALSE) != OMX_ErrorNone)
        return FALSE;

      if (gst_omx_port_wait_enabled (self->enc_out_port,
              1 * GST_SECOND) != OMX_ErrorNone)
        return FALSE;

      if (gst_omx_component_set_state (self->enc,
              OMX_StateIdle) != OMX_ErrorNone)
        return FALSE;

      /* Need to allocate buffers to reach Idle state */
      if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
        return FALSE;
    } else {
      if (gst_omx_component_set_state (self->enc,
              OMX_StateIdle) != OMX_ErrorNone)
        return FALSE;

      /* Need to allocate buffers to reach Idle state */
      if (gst_omx_port_allocate_buffers (self->enc_in_port) != OMX_ErrorNone)
        return FALSE;
      if (gst_omx_port_allocate_buffers (self->enc_out_port) != OMX_ErrorNone)
        return FALSE;
    }

    if (gst_omx_component_get_state (self->enc,
            GST_CLOCK_TIME_NONE) != OMX_StateIdle)
      return FALSE;

    if (gst_omx_component_set_state (self->enc,
            OMX_StateExecuting) != OMX_ErrorNone)
      return FALSE;

    if (gst_omx_component_get_state (self->enc,
            GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
      return FALSE;
  }

  /* Unset flushing to allow ports to accept data again */
  gst_omx_port_set_flushing (self->enc_in_port, 5 * GST_SECOND, FALSE);
  gst_omx_port_set_flushing (self->enc_out_port, 5 * GST_SECOND, FALSE);

  if (gst_omx_component_get_last_error (self->enc) != OMX_ErrorNone) {
    GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
        gst_omx_component_get_last_error_string (self->enc),
        gst_omx_component_get_last_error (self->enc));
    return FALSE;
  }

  /* Start the srcpad loop again */
  GST_DEBUG_OBJECT (self, "Starting task again");
  self->downstream_flow_ret = GST_FLOW_OK;
  gst_pad_start_task (GST_AUDIO_ENCODER_SRC_PAD (self),
      (GstTaskFunction) gst_omx_audio_enc_loop, encoder, NULL);

  return TRUE;
}
示例#23
0
static GstFlowReturn
gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc,
                               GstBuffer * buffer, gint * have_data)
{
    GstAudioEncoder *enc;
    AVCodecContext *ctx;
    gint res;
    GstFlowReturn ret;
    GstAudioInfo *info;
    AVPacket *pkt;
    AVFrame *frame = ffmpegaudenc->frame;
    gboolean planar;
    gint nsamples = -1;

    enc = GST_AUDIO_ENCODER (ffmpegaudenc);

    ctx = ffmpegaudenc->context;

    pkt = g_slice_new0 (AVPacket);

    if (buffer != NULL) {
        BufferInfo *buffer_info = g_slice_new0 (BufferInfo);
        guint8 *audio_in;
        guint in_size;

        buffer_info->buffer = buffer;
        gst_buffer_map (buffer, &buffer_info->map, GST_MAP_READ);
        audio_in = buffer_info->map.data;
        in_size = buffer_info->map.size;

        GST_LOG_OBJECT (ffmpegaudenc, "encoding buffer %p size:%u", audio_in,
                        in_size);

        info = gst_audio_encoder_get_audio_info (enc);
        planar = av_sample_fmt_is_planar (ffmpegaudenc->context->sample_fmt);
        frame->format = ffmpegaudenc->context->sample_fmt;
        frame->sample_rate = ffmpegaudenc->context->sample_rate;
        frame->channels = ffmpegaudenc->context->channels;
        frame->channel_layout = ffmpegaudenc->context->channel_layout;

        if (planar && info->channels > 1) {
            gint channels;
            gint i, j;

            nsamples = frame->nb_samples = in_size / info->bpf;
            channels = info->channels;

            frame->buf[0] =
                av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);

            if (info->channels > AV_NUM_DATA_POINTERS) {
                buffer_info->ext_data_array = frame->extended_data =
                                                  av_malloc_array (info->channels, sizeof (uint8_t *));
            } else {
                frame->extended_data = frame->data;
            }

            buffer_info->ext_data = frame->extended_data[0] = av_malloc (in_size);
            frame->linesize[0] = in_size / channels;
            for (i = 1; i < channels; i++)
                frame->extended_data[i] =
                    frame->extended_data[i - 1] + frame->linesize[0];

            switch (info->finfo->width) {
            case 8: {
                const guint8 *idata = (const guint8 *) audio_in;

                for (i = 0; i < nsamples; i++) {
                    for (j = 0; j < channels; j++) {
                        ((guint8 *) frame->extended_data[j])[i] = idata[j];
                    }
                    idata += channels;
                }
                break;
            }
            case 16: {
                const guint16 *idata = (const guint16 *) audio_in;

                for (i = 0; i < nsamples; i++) {
                    for (j = 0; j < channels; j++) {
                        ((guint16 *) frame->extended_data[j])[i] = idata[j];
                    }
                    idata += channels;
                }
                break;
            }
            case 32: {
                const guint32 *idata = (const guint32 *) audio_in;

                for (i = 0; i < nsamples; i++) {
                    for (j = 0; j < channels; j++) {
                        ((guint32 *) frame->extended_data[j])[i] = idata[j];
                    }
                    idata += channels;
                }

                break;
            }
            case 64: {
                const guint64 *idata = (const guint64 *) audio_in;

                for (i = 0; i < nsamples; i++) {
                    for (j = 0; j < channels; j++) {
                        ((guint64 *) frame->extended_data[j])[i] = idata[j];
                    }
                    idata += channels;
                }

                break;
            }
            default:
                g_assert_not_reached ();
                break;
            }

            gst_buffer_unmap (buffer, &buffer_info->map);
            gst_buffer_unref (buffer);
            buffer_info->buffer = NULL;
        } else {
            frame->data[0] = audio_in;
            frame->extended_data = frame->data;
            frame->linesize[0] = in_size;
            frame->nb_samples = nsamples = in_size / info->bpf;
            frame->buf[0] =
                av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);
        }

        /* we have a frame to feed the encoder */
        res = avcodec_encode_audio2 (ctx, pkt, frame, have_data);

        av_frame_unref (frame);
    } else {
        GST_LOG_OBJECT (ffmpegaudenc, "draining");
        /* flushing the encoder */
        res = avcodec_encode_audio2 (ctx, pkt, NULL, have_data);
    }

    if (res < 0) {
        char error_str[128] = { 0, };

        g_slice_free (AVPacket, pkt);
        av_strerror (res, error_str, sizeof (error_str));
        GST_ERROR_OBJECT (enc, "Failed to encode buffer: %d - %s", res, error_str);
        return GST_FLOW_OK;
    }
    GST_LOG_OBJECT (ffmpegaudenc, "got output size %d", res);

    if (*have_data) {
        GstBuffer *outbuf;
        const AVCodec *codec;

        GST_LOG_OBJECT (ffmpegaudenc, "pushing size %d", pkt->size);

        outbuf =
            gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data,
                                         pkt->size, 0, pkt->size, pkt, gst_ffmpegaudenc_free_avpacket);

        codec = ffmpegaudenc->context->codec;
        if ((codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) || !buffer) {
            /* FIXME: Not really correct, as -1 means "all the samples we got
               given so far", which may not be true depending on the codec,
               but we have no way to know AFAICT */
            ret = gst_audio_encoder_finish_frame (enc, outbuf, -1);
        } else {
            ret = gst_audio_encoder_finish_frame (enc, outbuf, nsamples);
        }
    } else {
        GST_LOG_OBJECT (ffmpegaudenc, "no output produced");
        g_slice_free (AVPacket, pkt);
        ret = GST_FLOW_OK;
    }

    return ret;
}
示例#24
0
static GstFlowReturn
gst_celt_enc_encode (GstCeltEnc * enc, GstBuffer * buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  gint frame_size = enc->frame_size;
  gint bytes = frame_size * 2 * enc->channels;
  gint bytes_per_packet;
  gint16 *data, *data0 = NULL;
  gint outsize, size;
  GstBuffer *outbuf;

  if (G_LIKELY (buf)) {
    data = (gint16 *) GST_BUFFER_DATA (buf);
    size = GST_BUFFER_SIZE (buf);

    if (G_UNLIKELY (size % bytes)) {
      GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
      size = ((size / bytes) + 1) * bytes;
      data0 = data = g_malloc0 (size);
      memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
    }
  } else {
    GST_DEBUG_OBJECT (enc, "nothing to drain");
    goto done;
  }

  frame_size = size / (2 * enc->channels);
  if (enc->cbr) {
    bytes_per_packet = (enc->bitrate * frame_size / enc->rate + 4) / 8;
  } else {
    bytes_per_packet = (enc->max_bitrate * frame_size / enc->rate + 4) / 8;
  }

  ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
      GST_BUFFER_OFFSET_NONE, bytes_per_packet,
      GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);

  if (GST_FLOW_OK != ret)
    goto done;

  GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);

#ifdef HAVE_CELT_0_8
  outsize =
      celt_encode (enc->state, data, frame_size,
      GST_BUFFER_DATA (outbuf), bytes_per_packet);
#else
  outsize =
      celt_encode (enc->state, data, NULL,
      GST_BUFFER_DATA (outbuf), bytes_per_packet);
#endif

  if (outsize < 0) {
    GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
        ("encoding failed: %d", outsize));
    ret = GST_FLOW_ERROR;
    goto done;
  }

  GST_DEBUG_OBJECT (enc, "encoding %d bytes", bytes);

  ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
      outbuf, frame_size);

done:
  g_free (data0);
  return ret;
}
示例#25
0
static GstFlowReturn
gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
{
  guint8 *bdata = NULL, *data, *mdata = NULL;
  gsize bsize, size;
  gsize bytes = enc->frame_samples * enc->n_channels * 2;
  gint ret = GST_FLOW_OK;
  GstMapInfo map;
  GstMapInfo omap;
  gint outsize;
  GstBuffer *outbuf;

  g_mutex_lock (enc->property_lock);

  if (G_LIKELY (buf)) {
    gst_buffer_map (buf, &map, GST_MAP_READ);
    bdata = map.data;
    bsize = map.size;

    if (G_UNLIKELY (bsize % bytes)) {
      GST_DEBUG_OBJECT (enc, "draining; adding silence samples");

      size = ((bsize / bytes) + 1) * bytes;
      mdata = g_malloc0 (size);
      memcpy (mdata, bdata, bsize);
      data = mdata;
    } else {
      data = bdata;
      size = bsize;
    }
  } else {
    GST_DEBUG_OBJECT (enc, "nothing to drain");
    goto done;
  }

  g_assert (size == bytes);

  outbuf = gst_buffer_new_and_alloc (enc->max_payload_size * enc->n_channels);
  if (!outbuf)
    goto done;

  GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)",
      enc->frame_samples, (int) bytes);

  gst_buffer_map (outbuf, &omap, GST_MAP_WRITE);

  GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)",
      enc->frame_samples, (int) bytes);

  outsize =
      opus_multistream_encode (enc->state, (const gint16 *) data,
      enc->frame_samples, omap.data, enc->max_payload_size * enc->n_channels);

  gst_buffer_unmap (outbuf, &omap);

  if (outsize < 0) {
    GST_ERROR_OBJECT (enc, "Encoding failed: %d", outsize);
    ret = GST_FLOW_ERROR;
    goto done;
  } else if (outsize > enc->max_payload_size) {
    GST_WARNING_OBJECT (enc,
        "Encoded size %d is higher than max payload size (%d bytes)",
        outsize, enc->max_payload_size);
    ret = GST_FLOW_ERROR;
    goto done;
  }

  GST_DEBUG_OBJECT (enc, "Output packet is %u bytes", outsize);
  gst_buffer_set_size (outbuf, outsize);

  ret =
      gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc), outbuf,
      enc->frame_samples);

done:

  if (bdata)
    gst_buffer_unmap (buf, &map);
  g_mutex_unlock (enc->property_lock);

  if (mdata)
    g_free (mdata);

  return ret;
}
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;
}
示例#27
0
static void
gst_omx_audio_enc_loop (GstOMXAudioEnc * self)
{
  GstOMXAudioEncClass *klass;
  GstOMXPort *port = self->enc_out_port;
  GstOMXBuffer *buf = NULL;
  GstFlowReturn flow_ret = GST_FLOW_OK;
  GstOMXAcquireBufferReturn acq_return;
  OMX_ERRORTYPE err;

  klass = GST_OMX_AUDIO_ENC_GET_CLASS (self);

  acq_return = gst_omx_port_acquire_buffer (port, &buf);
  if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
    goto component_error;
  } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
    goto flushing;
  } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
    goto eos;
  }

  if (!gst_pad_has_current_caps (GST_AUDIO_ENCODER_SRC_PAD (self))
      || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
    GstAudioInfo *info =
        gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (self));
    GstCaps *caps;

    GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");

    /* Reallocate all buffers */
    if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
      err = gst_omx_port_set_enabled (port, FALSE);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_deallocate_buffers (port);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

    }

    GST_AUDIO_ENCODER_STREAM_LOCK (self);

    caps = klass->get_caps (self, self->enc_out_port, info);
    if (!caps) {
      if (buf)
        gst_omx_port_release_buffer (self->enc_out_port, buf);
      GST_AUDIO_ENCODER_STREAM_UNLOCK (self);
      goto caps_failed;
    }

    GST_DEBUG_OBJECT (self, "Setting output caps: %" GST_PTR_FORMAT, caps);

    if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (self), caps)) {
      gst_caps_unref (caps);
      if (buf)
        gst_omx_port_release_buffer (self->enc_out_port, buf);
      GST_AUDIO_ENCODER_STREAM_UNLOCK (self);
      goto caps_failed;
    }
    gst_caps_unref (caps);

    GST_AUDIO_ENCODER_STREAM_UNLOCK (self);

    if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
      err = gst_omx_port_set_enabled (port, TRUE);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_allocate_buffers (port);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_populate (port);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;

      err = gst_omx_port_mark_reconfigured (port);
      if (err != OMX_ErrorNone)
        goto reconfigure_error;
    }

    /* Now get a buffer */
    if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
      return;
    }
  }

  g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
  if (!buf) {
    g_assert ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER));
    GST_AUDIO_ENCODER_STREAM_LOCK (self);
    goto eos;
  }

  GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %" G_GUINT64_FORMAT,
      (guint) buf->omx_buf->nFlags, (guint64) buf->omx_buf->nTimeStamp);

  /* This prevents a deadlock between the srcpad stream
   * lock and the videocodec stream lock, if ::reset()
   * is called at the wrong time
   */
  if (gst_omx_port_is_flushing (self->enc_out_port)) {
    GST_DEBUG_OBJECT (self, "Flushing");
    gst_omx_port_release_buffer (self->enc_out_port, buf);
    goto flushing;
  }

  GST_AUDIO_ENCODER_STREAM_LOCK (self);

  if ((buf->omx_buf->nFlags & OMX_BUFFERFLAG_CODECCONFIG)
      && buf->omx_buf->nFilledLen > 0) {
    GstCaps *caps;
    GstBuffer *codec_data;
    GstMapInfo map = GST_MAP_INFO_INIT;

    GST_DEBUG_OBJECT (self, "Handling codec data");
    caps =
        gst_caps_copy (gst_pad_get_current_caps (GST_AUDIO_ENCODER_SRC_PAD
            (self)));
    codec_data = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);

    gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
    memcpy (map.data,
        buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
        buf->omx_buf->nFilledLen);
    gst_buffer_unmap (codec_data, &map);

    gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
    if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (self), caps)) {
      gst_caps_unref (caps);
      if (buf)
        gst_omx_port_release_buffer (self->enc_out_port, buf);
      GST_AUDIO_ENCODER_STREAM_UNLOCK (self);
      goto caps_failed;
    }
    gst_caps_unref (caps);
    flow_ret = GST_FLOW_OK;
  } else if (buf->omx_buf->nFilledLen > 0) {
    GstBuffer *outbuf;
    guint n_samples;

    GST_DEBUG_OBJECT (self, "Handling output data");

    n_samples =
        klass->get_num_samples (self, self->enc_out_port,
        gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (self)), buf);

    if (buf->omx_buf->nFilledLen > 0) {
      GstMapInfo map = GST_MAP_INFO_INIT;
      outbuf = gst_buffer_new_and_alloc (buf->omx_buf->nFilledLen);

      gst_buffer_map (outbuf, &map, GST_MAP_WRITE);

      memcpy (map.data,
          buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
          buf->omx_buf->nFilledLen);
      gst_buffer_unmap (outbuf, &map);

    } else {
      outbuf = gst_buffer_new ();
    }

    GST_BUFFER_TIMESTAMP (outbuf) =
        gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
        OMX_TICKS_PER_SECOND);
    if (buf->omx_buf->nTickCount != 0)
      GST_BUFFER_DURATION (outbuf) =
          gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND,
          OMX_TICKS_PER_SECOND);

    flow_ret =
        gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (self),
        outbuf, n_samples);
  }

  GST_DEBUG_OBJECT (self, "Handled output data");

  GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));

  err = gst_omx_port_release_buffer (port, buf);
  if (err != OMX_ErrorNone)
    goto release_error;

  self->downstream_flow_ret = flow_ret;

  if (flow_ret != GST_FLOW_OK)
    goto flow_error;

  GST_AUDIO_ENCODER_STREAM_UNLOCK (self);

  return;

component_error:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
        ("OpenMAX component in error state %s (0x%08x)",
            gst_omx_component_get_last_error_string (self->enc),
            gst_omx_component_get_last_error (self->enc)));
    gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    self->started = FALSE;
    return;
  }
flushing:
  {
    GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
    gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_FLUSHING;
    self->started = FALSE;
    return;
  }
eos:
  {
    g_mutex_lock (&self->drain_lock);
    if (self->draining) {
      GST_DEBUG_OBJECT (self, "Drained");
      self->draining = FALSE;
      g_cond_broadcast (&self->drain_cond);
      flow_ret = GST_FLOW_OK;
      gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self));
    } else {
      GST_DEBUG_OBJECT (self, "Component signalled EOS");
      flow_ret = GST_FLOW_EOS;
    }
    g_mutex_unlock (&self->drain_lock);

    GST_AUDIO_ENCODER_STREAM_LOCK (self);
    self->downstream_flow_ret = flow_ret;

    /* Here we fallback and pause the task for the EOS case */
    if (flow_ret != GST_FLOW_OK)
      goto flow_error;

    GST_AUDIO_ENCODER_STREAM_UNLOCK (self);

    return;
  }
flow_error:
  {
    if (flow_ret == GST_FLOW_EOS) {
      GST_DEBUG_OBJECT (self, "EOS");

      gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (self),
          gst_event_new_eos ());
      gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self));
    } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) {
      GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."),
          ("stream stopped, reason %s", gst_flow_get_name (flow_ret)));

      gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (self),
          gst_event_new_eos ());
      gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self));
    }
    self->started = FALSE;
    GST_AUDIO_ENCODER_STREAM_UNLOCK (self);
    return;
  }
reconfigure_error:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
        ("Unable to reconfigure output port"));
    gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
    self->started = FALSE;
    return;
  }
caps_failed:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
    gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
    self->started = FALSE;
    return;
  }
release_error:
  {
    GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
        ("Failed to relase output buffer to component: %s (0x%08x)",
            gst_omx_error_to_string (err), err));
    gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (self), gst_event_new_eos ());
    gst_pad_pause_task (GST_AUDIO_ENCODER_SRC_PAD (self));
    self->downstream_flow_ret = GST_FLOW_ERROR;
    self->started = FALSE;
    GST_AUDIO_ENCODER_STREAM_UNLOCK (self);
    return;
  }
}
static gboolean
gst_two_lame_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
{
  GstTwoLame *twolame;
  gint out_samplerate;
  gint version;
  GstCaps *othercaps;

  twolame = GST_TWO_LAME (enc);

  /* parameters already parsed for us */
  twolame->samplerate = GST_AUDIO_INFO_RATE (info);
  twolame->num_channels = GST_AUDIO_INFO_CHANNELS (info);
  twolame->float_input = !GST_AUDIO_INFO_IS_INTEGER (info);

  /* but we might be asked to reconfigure, so reset */
  gst_two_lame_release_memory (twolame);

  GST_DEBUG_OBJECT (twolame, "setting up twolame");
  if (!gst_two_lame_setup (twolame))
    goto setup_failed;

  out_samplerate = twolame_get_out_samplerate (twolame->glopts);
  if (out_samplerate == 0)
    goto zero_output_rate;

  if (out_samplerate != twolame->samplerate) {
    GST_WARNING_OBJECT (twolame,
        "output samplerate %d is different from incoming samplerate %d",
        out_samplerate, twolame->samplerate);
  }

  version = twolame_get_version (twolame->glopts);
  if (version == TWOLAME_MPEG2)
    version = 2;
  else
    version = 1;

  othercaps =
      gst_caps_new_simple ("audio/mpeg",
      "mpegversion", G_TYPE_INT, 1,
      "mpegaudioversion", G_TYPE_INT, version,
      "layer", G_TYPE_INT, 2,
      "channels", G_TYPE_INT,
      twolame->mode == TWOLAME_MONO ? 1 : twolame->num_channels, "rate",
      G_TYPE_INT, out_samplerate, NULL);

  /* and use these caps */
  gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (twolame), othercaps);
  gst_caps_unref (othercaps);

  /* report needs to base class:
   * hand one frame at a time, if we are pretty sure what a frame is */
  if (out_samplerate == twolame->samplerate) {
    gst_audio_encoder_set_frame_samples_min (enc, 1152);
    gst_audio_encoder_set_frame_samples_max (enc, 1152);
    gst_audio_encoder_set_frame_max (enc, 1);
  }

  return TRUE;

zero_output_rate:
  {
    GST_ELEMENT_ERROR (twolame, LIBRARY, SETTINGS, (NULL),
        ("TwoLAME decided on a zero sample rate"));
    return FALSE;
  }
setup_failed:
  {
    GST_ELEMENT_ERROR (twolame, LIBRARY, SETTINGS,
        (_("Failed to configure TwoLAME encoder. Check your encoding parameters.")), (NULL));
    return FALSE;
  }
}
示例#29
0
static GstFlowReturn
gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
{
  gint frame_size = enc->frame_size;
  gint bytes = frame_size * 2 * enc->channels, samples;
  gint outsize, written, dtx_ret = 0;
  GstMapInfo map;
  guint8 *data, *data0 = NULL, *bdata;
  gsize bsize, size;
  GstBuffer *outbuf;
  GstFlowReturn ret = GST_FLOW_OK;

  if (G_LIKELY (buf)) {
    gst_buffer_map (buf, &map, GST_MAP_READ);
    bdata = map.data;
    bsize = map.size;

    if (G_UNLIKELY (bsize % bytes)) {
      GST_DEBUG_OBJECT (enc, "draining; adding silence samples");

      size = ((bsize / bytes) + 1) * bytes;
      data0 = data = g_malloc0 (size);
      memcpy (data, bdata, bsize);
      gst_buffer_unmap (buf, &map);
      bdata = NULL;
    } else {
      data = bdata;
      size = bsize;
    }
  } else {
    GST_DEBUG_OBJECT (enc, "nothing to drain");
    goto done;
  }

  samples = size / (2 * enc->channels);
  speex_bits_reset (&enc->bits);

  /* FIXME what about dropped samples if DTS enabled ?? */

  while (size) {
    GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);

    if (enc->channels == 2) {
      speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
    }
    dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);

    data += bytes;
    size -= bytes;
  }

  speex_bits_insert_terminator (&enc->bits);
  outsize = speex_bits_nbytes (&enc->bits);

  if (bdata)
    gst_buffer_unmap (buf, &map);

#if 0
  ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
      GST_BUFFER_OFFSET_NONE, outsize,
      GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);

  if ((GST_FLOW_OK != ret))
    goto done;
#endif
  outbuf = gst_buffer_new_allocate (NULL, outsize, NULL);
  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);

  written = speex_bits_write (&enc->bits, (gchar *) map.data, outsize);

  if (G_UNLIKELY (written < outsize)) {
    GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
  } else if (G_UNLIKELY (written > outsize)) {
    GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
    written = outsize;
  }
  gst_buffer_unmap (outbuf, &map);
  gst_buffer_resize (outbuf, 0, written);

  if (!dtx_ret)
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);

  ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
      outbuf, samples);

done:
  g_free (data0);
  return ret;
}
示例#30
0
static GstFlowReturn
gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
{
  gint frame_size = enc->frame_size;
  gint bytes = frame_size * 2 * enc->channels, samples, size;
  gint outsize, written, dtx_ret = 0;
  guint8 *data;
  GstBuffer *outbuf;
  GstFlowReturn ret = GST_FLOW_OK;

  if (G_LIKELY (buf)) {
    data = GST_BUFFER_DATA (buf);
    size = GST_BUFFER_SIZE (buf);

    if (G_UNLIKELY (size % bytes)) {
      GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
      size = ((size / bytes) + 1) * bytes;
      data = g_malloc0 (size);
      memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
    }
  } else {
    GST_DEBUG_OBJECT (enc, "nothing to drain");
    goto done;
  }

  samples = size / (2 * enc->channels);
  speex_bits_reset (&enc->bits);

  /* FIXME what about dropped samples if DTS enabled ?? */

  while (size) {
    GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", frame_size, bytes);

    if (enc->channels == 2) {
      speex_encode_stereo_int ((gint16 *) data, frame_size, &enc->bits);
    }
    dtx_ret += speex_encode_int (enc->state, (gint16 *) data, &enc->bits);

    data += bytes;
    size -= bytes;
  }

  speex_bits_insert_terminator (&enc->bits);
  outsize = speex_bits_nbytes (&enc->bits);

  ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
      GST_BUFFER_OFFSET_NONE, outsize,
      GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);

  if ((GST_FLOW_OK != ret))
    goto done;

  written = speex_bits_write (&enc->bits,
      (gchar *) GST_BUFFER_DATA (outbuf), outsize);

  if (G_UNLIKELY (written < outsize)) {
    GST_ERROR_OBJECT (enc, "short write: %d < %d bytes", written, outsize);
    GST_BUFFER_SIZE (outbuf) = written;
  } else if (G_UNLIKELY (written > outsize)) {
    GST_ERROR_OBJECT (enc, "overrun: %d > %d bytes", written, outsize);
  }

  if (!dtx_ret)
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);

  ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc),
      outbuf, samples);

done:
  return ret;
}