Esempio n. 1
0
static GstFlowReturn
gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer * inbuf)
{
  GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad));
  GstBuffer *outbuf;
  gint ret_size = 0, frame_size;
  gboolean force_keyframe;

  GST_DEBUG_OBJECT (ffmpegenc,
      "Received buffer of time %" GST_TIME_FORMAT,
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)));

  GST_OBJECT_LOCK (ffmpegenc);
  force_keyframe = ffmpegenc->force_keyframe;
  ffmpegenc->force_keyframe = FALSE;
  GST_OBJECT_UNLOCK (ffmpegenc);

  if (force_keyframe)
    ffmpegenc->picture->pict_type = FF_I_TYPE;

  frame_size = gst_ffmpeg_avpicture_fill ((AVPicture *) ffmpegenc->picture,
      GST_BUFFER_DATA (inbuf),
      ffmpegenc->context->pix_fmt,
      ffmpegenc->context->width, ffmpegenc->context->height);
  g_return_val_if_fail (frame_size == GST_BUFFER_SIZE (inbuf), GST_FLOW_ERROR);

  ffmpegenc->picture->pts =
      gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (inbuf) /
      ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base);

  ffmpegenc_setup_working_buf (ffmpegenc);

  ret_size = avcodec_encode_video (ffmpegenc->context,
      ffmpegenc->working_buf, ffmpegenc->working_buf_size, ffmpegenc->picture);

  if (ret_size < 0) {
#ifndef GST_DISABLE_GST_DEBUG
    GstFFMpegEncClass *oclass =
        (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
    GST_ERROR_OBJECT (ffmpegenc,
        "ffenc_%s: failed to encode buffer", oclass->in_plugin->name);
#endif /* GST_DISABLE_GST_DEBUG */
    gst_buffer_unref (inbuf);
    return GST_FLOW_OK;
  }

  /* handle b-frame delay when no output, so we don't output empty frames;
   * timestamps and so can permute a bit between coding and display order
   * but keyframes should still end up with the proper metadata */
  g_queue_push_tail (ffmpegenc->delay, inbuf);
  if (ret_size)
    inbuf = g_queue_pop_head (ffmpegenc->delay);
  else
    return GST_FLOW_OK;

  /* save stats info if there is some as well as a stats file */
  if (ffmpegenc->file && ffmpegenc->context->stats_out)
    if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0)
      GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE,
          (("Could not write to file \"%s\"."), ffmpegenc->filename),
          GST_ERROR_SYSTEM);

  outbuf = gst_buffer_new_and_alloc (ret_size);
  memcpy (GST_BUFFER_DATA (outbuf), ffmpegenc->working_buf, ret_size);
  GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
  GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
  /* buggy codec may not set coded_frame */
  if (ffmpegenc->context->coded_frame) {
    if (!ffmpegenc->context->coded_frame->key_frame)
      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
  } else
    GST_WARNING_OBJECT (ffmpegenc, "codec did not provide keyframe info");
  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad));

  gst_buffer_unref (inbuf);

  /* Reset frame type */
  if (ffmpegenc->picture->pict_type)
    ffmpegenc->picture->pict_type = 0;

  if (force_keyframe) {
    gst_pad_push_event (ffmpegenc->srcpad,
        gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
            gst_structure_new ("GstForceKeyUnit",
                "timestamp", G_TYPE_UINT64, GST_BUFFER_TIMESTAMP (outbuf),
                NULL)));
  }

  return gst_pad_push (ffmpegenc->srcpad, outbuf);
}
void GStreamerReader::ReadAndPushData(guint aLength)
{
  MediaResource* resource = mDecoder->GetResource();
  NS_ASSERTION(resource, "Decoder has no media resource");
  int64_t offset1 = resource->Tell();
  unused << offset1;
  nsresult rv = NS_OK;

  GstBuffer* buffer = gst_buffer_new_and_alloc(aLength);
#if GST_VERSION_MAJOR >= 1
  GstMapInfo info;
  gst_buffer_map(buffer, &info, GST_MAP_WRITE);
  guint8 *data = info.data;
#else
  guint8* data = GST_BUFFER_DATA(buffer);
#endif
  uint32_t size = 0, bytesRead = 0;
  while(bytesRead < aLength) {
    rv = resource->Read(reinterpret_cast<char*>(data + bytesRead),
        aLength - bytesRead, &size);
    if (NS_FAILED(rv) || size == 0)
      break;

    bytesRead += size;
  }

  int64_t offset2 = resource->Tell();
  unused << offset2;

#if GST_VERSION_MAJOR >= 1
  gst_buffer_unmap(buffer, &info);
  gst_buffer_set_size(buffer, bytesRead);
#else
  GST_BUFFER_SIZE(buffer) = bytesRead;
#endif

  GstFlowReturn ret = gst_app_src_push_buffer(mSource, gst_buffer_ref(buffer));
  if (ret != GST_FLOW_OK) {
    LOG(PR_LOG_ERROR, "ReadAndPushData push ret %s(%d)", gst_flow_get_name(ret), ret);
  }

  if (NS_FAILED(rv)) {
    /* Terminate the stream if there is an error in reading */
    LOG(PR_LOG_ERROR, "ReadAndPushData read error, rv=%x", rv);
    gst_app_src_end_of_stream(mSource);
  } else if (bytesRead < aLength) {
    /* If we read less than what we wanted, we reached the end */
    LOG(PR_LOG_WARNING, "ReadAndPushData read underflow, "
        "bytesRead=%u, aLength=%u, offset(%lld,%lld)",
        bytesRead, aLength, offset1, offset2);
    gst_app_src_end_of_stream(mSource);
  }

  gst_buffer_unref(buffer);

  /* Ensure offset change is consistent in this function.
   * If there are other stream operations on another thread at the same time,
   * it will disturb the GStreamer state machine.
   */
  MOZ_ASSERT(offset1 + bytesRead == offset2);
}
Esempio n. 3
0
static int
gst_dv1394src_iso_receive (raw1394handle_t handle, int channel, size_t len,
    quadlet_t * data)
{
  GstDV1394Src *dv1394src = gst_dv1394src_from_raw1394handle (handle);

  if (len > 16) {
    /*
       the following code taken from kino-0.51 (Dan Dennedy/Charles Yates)
       Kindly relicensed under the LGPL. See the commit log for version 1.6 of
       this file in CVS.
     */
    unsigned char *p = (unsigned char *) &data[3];

    int section_type = p[0] >> 5;       /* section type is in bits 5 - 7 */
    int dif_sequence = p[1] >> 4;       /* dif sequence number is in bits 4 - 7 */
    int dif_block = p[2];

    /* if we are at the beginning of a frame, 
       we set buf=frame, and alloc a new buffer for frame
     */
    if (section_type == 0 && dif_sequence == 0) {       // dif header
      if (!GST_PAD_CAPS (GST_BASE_SRC_PAD (dv1394src))) {
        GstCaps *caps;

        // figure format (NTSC/PAL)
        if (p[3] & 0x80) {
          // PAL
          dv1394src->frame_size = PAL_FRAMESIZE;
          dv1394src->frame_rate = PAL_FRAMERATE;
          GST_DEBUG ("PAL data");
          caps = gst_caps_new_simple ("video/x-dv",
              "format", G_TYPE_STRING, "PAL",
              "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
        } else {
          // NTSC (untested)
          dv1394src->frame_size = NTSC_FRAMESIZE;
          dv1394src->frame_rate = NTSC_FRAMERATE;
          GST_DEBUG
              ("NTSC data [untested] - please report success/failure to <*****@*****.**>");
          caps = gst_caps_new_simple ("video/x-dv",
              "format", G_TYPE_STRING, "NTSC",
              "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
        }
        gst_pad_set_caps (GST_BASE_SRC_PAD (dv1394src), caps);
        gst_caps_unref (caps);
      }
      // drop last frame when not complete
      if (!dv1394src->drop_incomplete
          || dv1394src->bytes_in_frame == dv1394src->frame_size) {
        dv1394src->buf = dv1394src->frame;
      } else {
        GST_INFO_OBJECT (GST_ELEMENT (dv1394src), "incomplete frame dropped");
        g_signal_emit (G_OBJECT (dv1394src),
            gst_dv1394src_signals[SIGNAL_FRAME_DROPPED], 0);
        if (dv1394src->frame) {
          gst_buffer_unref (dv1394src->frame);
        }
      }
      if ((dv1394src->frame_sequence + 1) % (dv1394src->skip +
              dv1394src->consecutive) < dv1394src->consecutive) {
        GstBuffer *buf;
        gint64 i64;

        buf = gst_buffer_new_and_alloc (dv1394src->frame_size);

        /* fill in offset, duration, timestamp */
        GST_BUFFER_OFFSET (buf) = dv1394src->frame_sequence;
        dv1394src->frame = buf;
      }
      dv1394src->frame_sequence++;
      dv1394src->bytes_in_frame = 0;
    }

    if (dv1394src->frame != NULL) {
      guint8 *data = GST_BUFFER_DATA (dv1394src->frame);

      switch (section_type) {
        case 0:                /* 1 Header block */
          /* p[3] |= 0x80; // hack to force PAL data */
          memcpy (data + dif_sequence * 150 * 80, p, 480);
          break;

        case 1:                /* 2 Subcode blocks */
          memcpy (data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p,
              480);
          break;

        case 2:                /* 3 VAUX blocks */
          memcpy (data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p,
              480);
          break;

        case 3:                /* 9 Audio blocks interleaved with video */
          memcpy (data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p,
              480);
          break;

        case 4:                /* 135 Video blocks interleaved with audio */
          memcpy (data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) +
                  dif_block) * 80, p, 480);
          break;

        default:               /* we can't handle any other data */
          break;
      }
      dv1394src->bytes_in_frame += 480;
    }
  }
Esempio n. 4
0
/* This test outputs 2 buffers of same dimensions (320x240), then 1 buffer of 
 * differing dimensions (240x120), and then another buffer of previous 
 * dimensions (320x240) and checks that the 3 buffers output as a result have 
 * correct caps (first 2 with 320x240 and 3rd with 240x120).
 */
void test_changing_size()
{
  GstElement *videorate;
  GstBuffer *first;
  GstBuffer *second;
  GstBuffer *third;
  GstBuffer *fourth;
  GstBuffer *fifth;
  GstBuffer *outbuf;
  GstEvent *newsegment;
  GstCaps *caps, *caps_newsize;

  videorate = setup_videorate ();
  fail_unless (gst_element_set_state (videorate,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
      "could not set to playing");

  newsegment = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1,
      0);
  fail_unless (gst_pad_push_event (mysrcpad, newsegment) == TRUE);

  first = gst_buffer_new_and_alloc (4);
  memset (GST_BUFFER_DATA (first), 0, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  GST_BUFFER_TIMESTAMP (first) = 0;
  gst_buffer_set_caps (first, caps);

  GST_DEBUG ("pushing first buffer");
  fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK);

  /* second buffer */
  second = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (second) = GST_SECOND / 25;
  memset (GST_BUFFER_DATA (second), 0, 4);
  gst_buffer_set_caps (second, caps);

  fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
  fail_unless_equals_int (g_list_length (buffers), 1);
  outbuf = buffers->data;
  /* first buffer should be output here */
  fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (outbuf), caps));
  fail_unless (GST_BUFFER_TIMESTAMP (outbuf) == 0);

  /* third buffer with new size */
  third = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND / 25;
  memset (GST_BUFFER_DATA (third), 0, 4);
  caps_newsize = gst_caps_from_string (VIDEO_CAPS_NEWSIZE_STRING);
  gst_buffer_set_caps (third, caps_newsize);

  fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK);
  /* new caps flushed the internal state, no new output yet */
  fail_unless_equals_int (g_list_length (buffers), 1);
  outbuf = g_list_last (buffers)->data;
  /* first buffer should be output here */
  fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (outbuf), caps));
  fail_unless (GST_BUFFER_TIMESTAMP (outbuf) == 0);

  /* fourth buffer with original size */
  fourth = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (fourth) = 3 * GST_SECOND / 25;
  memset (GST_BUFFER_DATA (fourth), 0, 4);
  gst_buffer_set_caps (fourth, caps);

  fail_unless (gst_pad_push (mysrcpad, fourth) == GST_FLOW_OK);
  fail_unless_equals_int (g_list_length (buffers), 1);

  /* fifth buffer with original size */
  fifth = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (fifth) = 4 * GST_SECOND / 25;
  memset (GST_BUFFER_DATA (fifth), 0, 4);
  gst_buffer_set_caps (fifth, caps);

  fail_unless (gst_pad_push (mysrcpad, fifth) == GST_FLOW_OK);
  /* all four missing buffers here, dups of fourth buffer */
  fail_unless_equals_int (g_list_length (buffers), 4);
  outbuf = g_list_last (buffers)->data;
  /* third buffer should be output here */
  fail_unless (GST_BUFFER_TIMESTAMP (outbuf) == 3 * GST_SECOND / 25);
  fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (outbuf), caps));

  gst_caps_unref (caps);
  gst_caps_unref (caps_newsize);
  cleanup_videorate (videorate);
  std_log(LOG_FILENAME_LINE, "Test Successful");
  create_xml(0);
}
Esempio n. 5
0
static GstFlowReturn
gst_pnmenc_chain (GstPad * pad, GstBuffer * buf)
{
  GstPnmenc *s = GST_PNMENC (gst_pad_get_parent (pad));
  GstFlowReturn r;
  gchar *header;
  GstBuffer *out;

  /* Assumption: One buffer, one image. That is, always first write header. */
  header = g_strdup_printf ("P%i\n%i %i\n%i\n",
      s->info.type + 3 * (1 - s->info.encoding), s->info.width, s->info.height,
      s->info.max);
  out = gst_buffer_new ();
  gst_buffer_set_data (out, (guchar *) header, strlen (header));
  gst_buffer_set_caps (out, GST_PAD_CAPS (s->src));
  if ((r = gst_pad_push (s->src, out)) != GST_FLOW_OK)
    goto out;

  /* Need to convert from GStreamer rowstride to PNM rowstride */
  if (s->info.width % 4 != 0) {
    guint i_rowstride;
    guint o_rowstride;
    GstBuffer *obuf;
    guint i;

    if (s->info.type == GST_PNM_TYPE_PIXMAP) {
      o_rowstride = 3 * s->info.width;
      i_rowstride = GST_ROUND_UP_4 (o_rowstride);
    } else {
      o_rowstride = s->info.width;
      i_rowstride = GST_ROUND_UP_4 (o_rowstride);
    }

    obuf = gst_buffer_new_and_alloc (o_rowstride * s->info.height);
    for (i = 0; i < s->info.height; i++)
      memcpy (GST_BUFFER_DATA (obuf) + o_rowstride * i,
          GST_BUFFER_DATA (buf) + i_rowstride * i, o_rowstride);
    gst_buffer_unref (buf);
    buf = obuf;
  } else {
    /* Pass through the data. */
    buf = gst_buffer_make_metadata_writable (buf);
  }

  /* We might need to convert to ASCII... */
  if (s->info.encoding == GST_PNM_ENCODING_ASCII) {
    GstBuffer *obuf;
    guint i, o;

    obuf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) * (4 + 1 / 20.));
    for (i = o = 0; i < GST_BUFFER_SIZE (buf); i++) {
      g_snprintf ((char *) GST_BUFFER_DATA (obuf) + o, 4, "%3i",
          GST_BUFFER_DATA (buf)[i]);
      o += 3;
      GST_BUFFER_DATA (obuf)[o++] = ' ';
      if (!((i + 1) % 20))
        GST_BUFFER_DATA (obuf)[o++] = '\n';
    }
    gst_buffer_unref (buf);
    buf = obuf;
  }

  gst_buffer_set_caps (buf, GST_PAD_CAPS (s->src));
  r = gst_pad_push (s->src, buf);

out:
  gst_object_unref (s);

  return r;
}
Esempio n. 6
0
AudioDecoderGst::AudioDecoderGst(const AudioInfo& info)
{
    // init GStreamer. TODO: what about doing this in MediaHandlerGst ctor?
    gst_init (NULL, NULL);

    GstCaps* srccaps=0;

    if (info.type == CODEC_TYPE_FLASH && info.codec == AUDIO_CODEC_MP3)
    {
        srccaps = gst_caps_new_simple ("audio/mpeg",
		"mpegversion", G_TYPE_INT, 1,
		"layer", G_TYPE_INT, 3,
		"rate", G_TYPE_INT, info.sampleRate,
		"channels", G_TYPE_INT, info.stereo ? 2 : 1, NULL);
        setup(srccaps);
        return;
    }
    
    if (info.type == CODEC_TYPE_FLASH && info.codec == AUDIO_CODEC_NELLYMOSER)
    {
        srccaps = gst_caps_new_simple ("audio/x-nellymoser",
		"rate", G_TYPE_INT, info.sampleRate,
		"channels", G_TYPE_INT, info.stereo ? 2 : 1, NULL);
        setup(srccaps);
        return;
    }

    if (info.type == CODEC_TYPE_FLASH && info.codec == AUDIO_CODEC_ADPCM)
    {
        srccaps = gst_caps_new_simple ("audio/x-adpcm",
                "rate", G_TYPE_INT, info.sampleRate,
                "channels", G_TYPE_INT, info.stereo ? 2 : 1, 
                "layout", G_TYPE_STRING, "swf", NULL);
        setup(srccaps);
        return;
    }

    if (info.type == CODEC_TYPE_FLASH && info.codec == AUDIO_CODEC_AAC)
    {
        srccaps = gst_caps_new_simple ("audio/mpeg",
            "mpegversion", G_TYPE_INT, 4,
            "rate", G_TYPE_INT, 44100,
            "channels", G_TYPE_INT, 2, 
            NULL);

        ExtraAudioInfoFlv* extra = dynamic_cast<ExtraAudioInfoFlv*>(info.extra.get());
        if (extra) {
            GstBuffer* buf = gst_buffer_new_and_alloc(extra->size);
            memcpy(GST_BUFFER_DATA(buf), extra->data.get(), extra->size);
            gst_caps_set_simple (srccaps, "codec_data", GST_TYPE_BUFFER, buf, NULL);

        } else {
            log_error(_("Creating AAC decoder without extra data. This will probably fail!"));
        }

        setup(srccaps);
        return;
    }


    if (info.type == CODEC_TYPE_FLASH) {
		boost::format err = boost::format(
                _("AudioDecoderGst: cannot handle codec %d (%s)")) %
                info.codec %
                (audioCodecType)info.codec;
        throw MediaException(err.str());
    }

    ExtraInfoGst* extraaudioinfo = dynamic_cast<ExtraInfoGst*>(info.extra.get());

    if (!extraaudioinfo) {
		boost::format err = boost::format(
                _("AudioDecoderGst: cannot handle codec %d "
                  "(no ExtraInfoGst attached)")) %
                info.codec;
        throw MediaException(err.str());
    }

    gst_caps_ref(extraaudioinfo->caps);
    setup(extraaudioinfo->caps);
}
Esempio n. 7
0
/* frames at 1, 0, 2 -> second one should be ignored */
void test_wrong_order_from_zero()
{
  GstElement *videorate;
  GstBuffer *first, *second, *third, *outbuffer;
  GstCaps *caps;

  videorate = setup_videorate ();
  fail_unless (gst_element_set_state (videorate,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
      "could not set to playing");
  assert_videorate_stats (videorate, "start", 0, 0, 0, 0);

  /* first buffer */
  first = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (first) = GST_SECOND;
  memset (GST_BUFFER_DATA (first), 0, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  gst_buffer_set_caps (first, caps);
  gst_caps_unref (caps);
  ASSERT_BUFFER_REFCOUNT (first, "first", 1);
  gst_buffer_ref (first);

  GST_DEBUG ("pushing first buffer");
  /* pushing gives away my reference ... */
  fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK);
  /* ... and it is now stuck inside videorate */
  ASSERT_BUFFER_REFCOUNT (first, "first", 2);
  fail_unless_equals_int (g_list_length (buffers), 0);
  assert_videorate_stats (videorate, "first", 1, 0, 0, 0);

  /* second buffer */
  second = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (second) = 0;
  memset (GST_BUFFER_DATA (second), 0, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  gst_buffer_set_caps (second, caps);
  gst_caps_unref (caps);
  ASSERT_BUFFER_REFCOUNT (second, "second", 1);
  gst_buffer_ref (second);

  /* pushing gives away my reference ... */
  fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
  /* ... and it is now dropped because it is too old */
  ASSERT_BUFFER_REFCOUNT (second, "second", 1);
  fail_unless_equals_int (g_list_length (buffers), 0);

  /* ... and the first one is still there */
  assert_videorate_stats (videorate, "second", 2, 0, 1, 0);
  ASSERT_BUFFER_REFCOUNT (first, "first", 2);

  /* third buffer */
  third = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND;
  memset (GST_BUFFER_DATA (third), 0, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  gst_buffer_set_caps (third, caps);
  gst_caps_unref (caps);
  ASSERT_BUFFER_REFCOUNT (third, "third", 1);
  gst_buffer_ref (third);

  /* pushing gives away my reference ... */
  fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK);
  /* ... and it is now stuck inside videorate */
  ASSERT_BUFFER_REFCOUNT (third, "third", 2);

  /* and now the first one should be pushed once and dupped 24 + 13 times, to
   * reach the half point between 1 s (first) and 2 s (third) */
  fail_unless_equals_int (g_list_length (buffers), 38);
  ASSERT_BUFFER_REFCOUNT (first, "first", 39);
  ASSERT_BUFFER_REFCOUNT (second, "second", 1);
  ASSERT_BUFFER_REFCOUNT (third, "third", 2);
  assert_videorate_stats (videorate, "third", 3, 38, 1, 37);

  /* verify last buffer */
  outbuffer = g_list_last (buffers)->data;
  fail_unless (GST_IS_BUFFER (outbuffer));
  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer),
      GST_SECOND * 37 / 25);

  /* cleanup */
  gst_buffer_unref (first);
  gst_buffer_unref (second);
  gst_buffer_unref (third);
  cleanup_videorate (videorate);
  std_log(LOG_FILENAME_LINE, "Test Successful");
  create_xml(0);
}
Esempio n. 8
0
/**
 * Main working loop for stuff coming in from the CCNx network
 *
 * The only kind of content we work with are data messages. They are in response to the
 * interest messages we send out. The work involves 2 pieces: packing the data from ccn message
 * sizes into buffer sizes we use internally, and detecting when the stream of data is done.
 * 
 * The first is fairly simple. Each internal buffer we 'fill' is placed onto the fifo queue
 * so the main thread can take it off and reply to the pipeline request for more data.
 *
 * Determining the end of stream at the moment is a bit of a hack and could use some work.
 * \todo volunteers?  8-)
 *
 * \param	selfp		-> a context structure we created when registering this call-back
 * \param	kind		specifies the type of call-back being processed, see the \b switch statement
 * \param	info		context information about the call-back itself; interests, data, etc.
 * \return a response as to how successful we were in processing the call-back
 * \retval CCN_UPCALL_RESULT_OK		things went well
 * \retval CCN_UPCALL_RESULT_VERIFY	need to verify the contents of what we received
 * \retval CCN_UPCALL_RESULT_REEXPRESS an interest timedout waiting for data, so we try again
 * \retval CCN_UPCALL_RESULT_ERR	some error was encountered
 */
static enum ccn_upcall_res
incoming_content (struct ccn_closure *selfp,
    enum ccn_upcall_kind kind, struct ccn_upcall_info *info)
{
  Gstccnxsrc *me = GST_CCNXSRC (selfp->data);

  const unsigned char *ccnb = NULL;
  size_t ccnb_size = 0;
  const unsigned char *ib = NULL;       /* info->interest_ccnb */
  struct ccn_indexbuf *ic = NULL;
  unsigned int i;
  uintmax_t segment;
  CcnxInterestState *istate = NULL;
  gint res;
  const unsigned char *cp;
  size_t sz;
  const unsigned char *data = NULL;
  size_t data_size = 0;
  gboolean b_last = FALSE;

  GST_INFO ("content has arrived!");

  /* Do some basic sanity and type checks to see if we want to process this data */

  if (CCN_UPCALL_FINAL == kind) {
    GST_LOG_OBJECT (me, "CCN upcall final %p", selfp);
    if (me->i_bufoffset > 0) {
      GST_BUFFER_SIZE (me->buf) = me->i_bufoffset;
      fifo_put (me, me->buf);
      me->buf = gst_buffer_new_and_alloc (CCN_FIFO_BLOCK_SIZE);
      me->i_bufoffset = 0;
    }
/*
 * Should emit an eos here instead of the empty buffer
 */
    GST_BUFFER_SIZE (me->buf) = 0;
    fifo_put (me, me->buf);
    me->i_bufoffset = 0;
    return (CCN_UPCALL_RESULT_OK);
  }

  if (!info)
    return CCN_UPCALL_RESULT_ERR;       // Now why would this happen?

  // show_comps( info->content_ccnb, info->content_comps);

  if (CCN_UPCALL_INTEREST_TIMED_OUT == kind) {
    if (selfp != me->ccn_closure) {
      GST_LOG_OBJECT (me, "CCN Interest timed out on dead closure %p", selfp);
      return (CCN_UPCALL_RESULT_OK);
    }
    segment =
        ccn_ccnb_fetch_segment (info->interest_ccnb, info->interest_comps);
    GST_INFO ("...looks to be for segment: %d", segment);
    GST_LOG_OBJECT (me, "CCN upcall reexpress -- timed out");
    istate = fetchSegmentInterest (me, segment);
    if (istate) {
      if (istate->timeouts > 5) {
        GST_LOG_OBJECT (me, "CCN upcall reexpress -- too many reexpressions");
        if (segment == me->post_seg)    // We have been waiting for this one...process as an empty block to trigger other activity
          process_or_queue (me, me->post_seg, NULL, 0, FALSE);
        else
          freeInterestState (me, istate);
        post_next_interest (me);        // make sure to ask for new stuff if needed, or else we stall waiting for nothing
        return (CCN_UPCALL_RESULT_OK);
      } else {
        istate->timeouts++;
        return (CCN_UPCALL_RESULT_REEXPRESS);
      }
    } else {
      GST_LOG_OBJECT (me, "segment not found in cache: %d", segment);
      return (CCN_UPCALL_RESULT_OK);
    }

  } else if (CCN_UPCALL_CONTENT_UNVERIFIED == kind) {
    if (selfp != me->ccn_closure) {
      GST_LOG_OBJECT (me, "CCN unverified content on dead closure %p", selfp);
      return (CCN_UPCALL_RESULT_OK);
    }
    return (CCN_UPCALL_RESULT_VERIFY);

  } else if (CCN_UPCALL_CONTENT != kind) {
    GST_LOG_OBJECT (me, "CCN upcall result error");
    return (CCN_UPCALL_RESULT_ERR);
  }

  segment = ccn_ccnb_fetch_segment (info->content_ccnb, info->content_comps);
  GST_INFO ("...looks to be for segment: %d", segment);
  if (selfp != me->ccn_closure) {
    GST_LOG_OBJECT (me, "CCN content on dead closure %p", selfp);
    return (CCN_UPCALL_RESULT_OK);
  }


  /* At this point it seems we have a data message we want to process */

  ccnb = info->content_ccnb;
  ccnb_size = info->pco->offset[CCN_PCO_E];

  /* spit out some debug information */
  for (i = 0; i < 5; ++i) {
    GST_DEBUG ("%3d: ", i);
    if (0 > ccn_name_comp_get (info->content_ccnb, info->content_comps, i, &cp,
            &sz)) {
      // fprintf(stderr, "could not get comp\n");
    } else {
      // hDump( DUMP_ADDR( cp ), DUMP_SIZE( sz ) );
    }
  }

  /* go get the data and process it...note that the data pointer here is only temporary, a copy is needed to keep the data */
  ib = info->interest_ccnb;
  ic = info->interest_comps;
  res = ccn_content_get_value (ccnb, ccnb_size, info->pco, &data, &data_size);
  if (res < 0) {
    GST_LOG_OBJECT (me, "CCN error on get value of size");
    process_or_queue (me, segment, NULL, 0, FALSE);     // process null block to adjust interest array queue
    post_next_interest (me);    // Keep the data flowing
    return (CCN_UPCALL_RESULT_ERR);
  }

  /* was this the last block? [code taken from a ccnx tool */
  /* \todo  the test below should get refactored into the library */
  if (info->pco->offset[CCN_PCO_B_FinalBlockID] !=
      info->pco->offset[CCN_PCO_E_FinalBlockID]) {
    const unsigned char *finalid = NULL;
    size_t finalid_size = 0;
    const unsigned char *nameid = NULL;
    size_t nameid_size = 0;
    struct ccn_indexbuf *cc = info->content_comps;
    ccn_ref_tagged_BLOB (CCN_DTAG_FinalBlockID, ccnb,
        info->pco->offset[CCN_PCO_B_FinalBlockID],
        info->pco->offset[CCN_PCO_E_FinalBlockID], &finalid, &finalid_size);
    if (cc->n < 2)
      abort ();                 // \todo we need to behave better than this
    ccn_ref_tagged_BLOB (CCN_DTAG_Component, ccnb,
        cc->buf[cc->n - 2], cc->buf[cc->n - 1], &nameid, &nameid_size);
    if (finalid_size == nameid_size
        && 0 == memcmp (finalid, nameid, nameid_size)) {
      b_last = TRUE;
    }
  }

  /* a short block can also indicate the end, if the client isn't using FinalBlockID */
  if (data_size < CCN_CHUNK_SIZE)
    b_last = TRUE;

  /* something to process */
  process_or_queue (me, segment, data, data_size, b_last);
  post_next_interest (me);

  if (!b_last)
    return post_next_interest (me);

  return (CCN_UPCALL_RESULT_OK);

}
Esempio n. 9
0
static void
spc_play (GstPad * pad)
{
  GstSpcDec *spc = GST_SPC_DEC (gst_pad_get_parent (pad));
  GstFlowReturn flow_return;
  GstBuffer *out;
  gboolean seeking = spc->seeking;
  gint64 duration, fade, end, position;

  if (!seeking) {
    out = gst_buffer_new_and_alloc (1600 * 4);
    gst_buffer_set_caps (out, GST_PAD_CAPS (pad));
    GST_BUFFER_TIMESTAMP (out) =
        (gint64) gst_util_uint64_scale ((guint64) spc->byte_pos, GST_SECOND,
        32000 * 2 * 2);
    spc->byte_pos += OSPC_Run (-1, (short *) GST_BUFFER_DATA (out), 1600 * 4);
  } else {
    if (spc->seekpoint < spc->byte_pos) {
      OSPC_Init (GST_BUFFER_DATA (spc->buf), GST_BUFFER_SIZE (spc->buf));
      spc->byte_pos = 0;
    }
    spc->byte_pos += OSPC_Run (-1, NULL, 1600 * 4);
    if (spc->byte_pos >= spc->seekpoint) {
      spc->seeking = FALSE;
    }
    out = gst_buffer_new ();
    gst_buffer_set_caps (out, GST_PAD_CAPS (pad));
  }

  duration = gst_spc_duration (spc);
  fade = gst_spc_fadeout (spc);
  end = duration + fade;
  position =
      (gint64) gst_util_uint64_scale ((guint64) spc->byte_pos, GST_SECOND,
      32000 * 2 * 2);

  if (position >= duration) {
    gint16 *data = (gint16 *) GST_BUFFER_DATA (out);
    guint32 size = GST_BUFFER_SIZE (out) / sizeof (gint16);
    unsigned int i;

    gint64 num = (fade - (position - duration));

    for (i = 0; i < size; i++) {
      /* Apply a parabolic volume envelope */
      data[i] = (gint16) (data[i] * num / fade * num / fade);
    }
  }

  if ((flow_return = gst_pad_push (spc->srcpad, out)) != GST_FLOW_OK) {
    GST_DEBUG_OBJECT (spc, "pausing task, reason %s",
        gst_flow_get_name (flow_return));

    gst_pad_pause_task (pad);

    if (flow_return <= GST_FLOW_UNEXPECTED
        || flow_return == GST_FLOW_NOT_LINKED) {
      gst_pad_push_event (pad, gst_event_new_eos ());
    }
  }

  if (position >= end) {
    gst_pad_pause_task (pad);
    gst_pad_push_event (pad, gst_event_new_eos ());
  }

  gst_object_unref (spc);

  return;
}
Esempio n. 10
0
static gboolean
brasero_transcode_buffer_handler (GstPad *pad,
				  GstBuffer *buffer,
				  BraseroTranscode *self)
{
	BraseroTranscodePrivate *priv;
	GstPad *peer;
	gint64 size;

	priv = BRASERO_TRANSCODE_PRIVATE (self);

	size = GST_BUFFER_SIZE (buffer);

	if (priv->segment_start <= 0 && priv->segment_end <= 0)
		return TRUE;

	/* what we do here is more or less what gstreamer does when seeking:
	 * it reads and process from 0 to the seek position (I tried).
	 * It even forwards the data before the seek position to the sink (which
	 * is a problem in our case as it would be written) */
	if (priv->size > priv->segment_end) {
		priv->size += size;
		return FALSE;
	}

	if (priv->size + size > priv->segment_end) {
		GstBuffer *new_buffer;
		int data_size;

		/* the entire the buffer is not interesting for us */
		/* create a new buffer and push it on the pad:
		 * NOTE: we're going to receive it ... */
		data_size = priv->segment_end - priv->size;
		new_buffer = gst_buffer_new_and_alloc (data_size);
		memcpy (GST_BUFFER_DATA (new_buffer), GST_BUFFER_DATA (buffer), data_size);

		/* Recursive: the following calls ourselves BEFORE we finish */
		peer = gst_pad_get_peer (pad);
		gst_pad_push (peer, new_buffer);

		priv->size += size - data_size;

		/* post an EOS event to stop pipeline */
		gst_pad_push_event (peer, gst_event_new_eos ());
		gst_object_unref (peer);
		return FALSE;
	}

	/* see if the buffer is in the segment */
	if (priv->size < priv->segment_start) {
		GstBuffer *new_buffer;
		gint data_size;

		/* see if all the buffer is interesting for us */
		if (priv->size + size < priv->segment_start) {
			priv->size += size;
			return FALSE;
		}

		/* create a new buffer and push it on the pad:
		 * NOTE: we're going to receive it ... */
		data_size = priv->size + size - priv->segment_start;
		new_buffer = gst_buffer_new_and_alloc (data_size);
		memcpy (GST_BUFFER_DATA (new_buffer),
			GST_BUFFER_DATA (buffer) +
			GST_BUFFER_SIZE (buffer) -
			data_size,
			data_size);
		GST_BUFFER_TIMESTAMP (new_buffer) = GST_BUFFER_TIMESTAMP (buffer) + data_size;

		/* move forward by the size of bytes we dropped */
		priv->size += size - data_size;

		/* this is recursive the following calls ourselves 
		 * BEFORE we finish */
		peer = gst_pad_get_peer (pad);
		gst_pad_push (peer, new_buffer);
		gst_object_unref (peer);

		return FALSE;
	}

	priv->size += size;
	priv->pos += size;

	return TRUE;
}
Esempio n. 11
0
/* notes:
 * - avc1 brand is not used, since the specific extensions indicated by it
 *   are not used (e.g. sample groupings, etc)
 * - TODO: maybe even more 3GPP brand fine-tuning ??
 *   (but that might need ftyp rewriting at the end) */
void
gst_qt_mux_map_format_to_header (GstQTMuxFormat format, GstBuffer ** _prefix,
    guint32 * _major, guint32 * _version, GList ** _compatible, AtomMOOV * moov,
    GstClockTime longest_chunk, gboolean faststart)
{
  static const guint32 qt_brands[] = { 0 };
  static const guint32 mp4_brands[] =
      { FOURCC_mp41, FOURCC_isom, FOURCC_iso2, 0 };
  static const guint32 isml_brands[] = { FOURCC_iso2, 0 };
  static const guint32 gpp_brands[] = { FOURCC_isom, FOURCC_iso2, 0 };
  static const guint32 mjp2_brands[] = { FOURCC_isom, FOURCC_iso2, 0 };
  static const guint8 mjp2_prefix[] =
      { 0, 0, 0, 12, 'j', 'P', ' ', ' ', 0x0D, 0x0A, 0x87, 0x0A };
  const guint32 *comp = NULL;
  guint32 major = 0, version = 0;
  GstBuffer *prefix = NULL;
  GList *result = NULL;

  g_return_if_fail (_prefix != NULL);
  g_return_if_fail (_major != NULL);
  g_return_if_fail (_version != NULL);
  g_return_if_fail (_compatible != NULL);

  switch (format) {
    case GST_QT_MUX_FORMAT_QT:
      major = FOURCC_qt__;
      comp = qt_brands;
      version = 0x20050300;
      break;
    case GST_QT_MUX_FORMAT_MP4:
      major = FOURCC_mp42;
      comp = mp4_brands;
      break;
    case GST_QT_MUX_FORMAT_ISML:
      major = FOURCC_isml;
      comp = isml_brands;
      break;
    case GST_QT_MUX_FORMAT_3GP:
    {
      gint video, audio;
      gboolean has_h264;

      gst_qt_mux_map_check_tracks (moov, &video, &audio, &has_h264);
      /* only track restriction really matters for Basic Profile */
      if (video <= 1 && audio <= 1) {
        /* it seems only newer spec knows about H264 */
        major = has_h264 ? FOURCC_3gp6 : FOURCC_3gp4;
        version = has_h264 ? 0x100 : 0x200;
      } else {
        major = FOURCC_3gg6;
        version = 0x100;
      }
      comp = gpp_brands;

      /*
       * We assume that we have chunks in dts order
       */
      if (faststart && longest_chunk <= GST_SECOND) {
        /* add progressive download profile */
        result = g_list_append (result, GUINT_TO_POINTER (FOURCC_3gr6));
      }
      break;
    }
    case GST_QT_MUX_FORMAT_MJ2:
    {
      major = FOURCC_mjp2;
      comp = mjp2_brands;
      version = 0;
      prefix = gst_buffer_new_and_alloc (sizeof (mjp2_prefix));
      gst_buffer_fill (prefix, 0, mjp2_prefix, sizeof (mjp2_prefix));
      break;
    }
    default:
      g_assert_not_reached ();
      break;
  }

  /* convert list to list, hm */
  while (comp && *comp != 0) {
    /* order matters over efficiency */
    result = g_list_append (result, GUINT_TO_POINTER (*comp));
    comp++;
  }

  *_major = major;
  *_version = version;
  *_prefix = prefix;
  *_compatible = result;

  /* TODO 3GPP may include mp42 as compatible if applicable */
  /* TODO 3GPP major brand 3gp7 if at most 1 video and audio track */
}
Esempio n. 12
0
static void
gst_vp8_enc_set_stream_info (GstVPXEnc * enc, GstCaps * caps,
    GstVideoInfo * info)
{
  GstStructure *s;
  GstVideoEncoder *video_encoder;
  GstBuffer *stream_hdr, *vorbiscomment;
  const GstTagList *iface_tags;
  GValue array = { 0, };
  GValue value = { 0, };
  guint8 *data = NULL;
  GstMapInfo map;

  video_encoder = GST_VIDEO_ENCODER (enc);
  s = gst_caps_get_structure (caps, 0);

  /* put buffers in a fixed list */
  g_value_init (&array, GST_TYPE_ARRAY);
  g_value_init (&value, GST_TYPE_BUFFER);

  /* Create Ogg stream-info */
  stream_hdr = gst_buffer_new_and_alloc (26);
  gst_buffer_map (stream_hdr, &map, GST_MAP_WRITE);
  data = map.data;

  GST_WRITE_UINT8 (data, 0x4F);
  GST_WRITE_UINT32_BE (data + 1, 0x56503830);   /* "VP80" */
  GST_WRITE_UINT8 (data + 5, 0x01);     /* stream info header */
  GST_WRITE_UINT8 (data + 6, 1);        /* Major version 1 */
  GST_WRITE_UINT8 (data + 7, 0);        /* Minor version 0 */
  GST_WRITE_UINT16_BE (data + 8, GST_VIDEO_INFO_WIDTH (info));
  GST_WRITE_UINT16_BE (data + 10, GST_VIDEO_INFO_HEIGHT (info));
  GST_WRITE_UINT24_BE (data + 12, GST_VIDEO_INFO_PAR_N (info));
  GST_WRITE_UINT24_BE (data + 15, GST_VIDEO_INFO_PAR_D (info));
  GST_WRITE_UINT32_BE (data + 18, GST_VIDEO_INFO_FPS_N (info));
  GST_WRITE_UINT32_BE (data + 22, GST_VIDEO_INFO_FPS_D (info));

  gst_buffer_unmap (stream_hdr, &map);

  GST_BUFFER_FLAG_SET (stream_hdr, GST_BUFFER_FLAG_HEADER);
  gst_value_set_buffer (&value, stream_hdr);
  gst_value_array_append_value (&array, &value);
  g_value_unset (&value);
  gst_buffer_unref (stream_hdr);

  iface_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (video_encoder));
  if (iface_tags) {
    vorbiscomment =
        gst_tag_list_to_vorbiscomment_buffer (iface_tags,
        (const guint8 *) "OVP80\2 ", 7,
        "Encoded with GStreamer vp8enc " PACKAGE_VERSION);

    GST_BUFFER_FLAG_SET (vorbiscomment, GST_BUFFER_FLAG_HEADER);

    g_value_init (&value, GST_TYPE_BUFFER);
    gst_value_set_buffer (&value, vorbiscomment);
    gst_value_array_append_value (&array, &value);
    g_value_unset (&value);
    gst_buffer_unref (vorbiscomment);
  }

  gst_structure_set_value (s, "streamheader", &array);
  g_value_unset (&array);

}
Esempio n. 13
0
static GstBuffer *
gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
{
  GstRtpJPEGDepay *rtpjpegdepay;
  GstBuffer *outbuf;
  gint payload_len, header_len;
  guint8 *payload;
  guint frag_offset;
  gint Q;
  guint type, width, height;
  guint16 dri, precision, length;
  guint8 *qtable;

  rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);

  if (GST_BUFFER_IS_DISCONT (buf)) {
    gst_adapter_clear (rtpjpegdepay->adapter);
  }

  payload_len = gst_rtp_buffer_get_payload_len (buf);

  if (payload_len < 8)
    goto empty_packet;

  payload = gst_rtp_buffer_get_payload (buf);
  header_len = 0;

  /*  0                   1                   2                   3
   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * | Type-specific |              Fragment Offset                  |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |      Type     |       Q       |     Width     |     Height    |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   */
  frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
  type = payload[4];
  Q = payload[5];
  width = payload[6] * 8;
  height = payload[7] * 8;

  if (width == 0 || height == 0)
    goto invalid_dimension;

  GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
      frag_offset, type, Q, width, height);

  header_len += 8;
  payload += 8;
  payload_len -= 8;

  dri = 0;
  if (type > 63) {
    if (payload_len < 4)
      goto empty_packet;

    /*  0                   1                   2                   3
     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |       Restart Interval        |F|L|       Restart Count       |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     */
    dri = (payload[0] << 8) | payload[1];

    GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);

    payload += 4;
    header_len += 4;
    payload_len -= 4;
  }

  if (Q >= 128 && frag_offset == 0) {
    if (payload_len < 4)
      goto empty_packet;

    /*  0                   1                   2                   3
     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |      MBZ      |   Precision   |             Length            |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |                    Quantization Table Data                    |
     * |                              ...                              |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     */
    precision = payload[1];
    length = (payload[2] << 8) | payload[3];

    GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
        precision, length);

    if (Q == 255 && length == 0)
      goto empty_packet;

    payload += 4;
    header_len += 4;
    payload_len -= 4;

    if (length > payload_len)
      goto empty_packet;

    if (length > 0)
      qtable = payload;
    else
      qtable = rtpjpegdepay->qtables[Q];

    payload += length;
    header_len += length;
    payload_len -= length;
  } else {
    length = 0;
    qtable = NULL;
    precision = 0;
  }

  if (frag_offset == 0) {
    guint size;

    if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
      GstCaps *outcaps;

      outcaps =
          gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION, 0,
          1, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
      gst_pad_set_caps (depayload->srcpad, outcaps);
      gst_caps_unref (outcaps);

      rtpjpegdepay->width = width;
      rtpjpegdepay->height = height;
    }

    GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
        length);

    /* first packet */
    if (length == 0) {
      if (Q < 128) {
        /* no quant table, see if we have one cached */
        qtable = rtpjpegdepay->qtables[Q];
        if (!qtable) {
          GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
          /* make and cache the table */
          qtable = g_new (guint8, 128);
          MakeTables (rtpjpegdepay, Q, qtable);
          rtpjpegdepay->qtables[Q] = qtable;
        } else {
          GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
        }
        /* all 8 bit quantizers */
        precision = 0;
      } else {
        if (!qtable)
          goto no_qtable;
      }
    }
    /* max header length, should be big enough */
    outbuf = gst_buffer_new_and_alloc (1000);
    size = MakeHeaders (GST_BUFFER_DATA (outbuf), type,
        width, height, qtable, precision, dri);

    GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);

    GST_BUFFER_SIZE (outbuf) = size;

    gst_adapter_push (rtpjpegdepay->adapter, outbuf);
  }

  /* take JPEG data, push in the adapter */
  GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
  outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1);
  gst_adapter_push (rtpjpegdepay->adapter, outbuf);
  outbuf = NULL;

  if (gst_rtp_buffer_get_marker (buf)) {
    guint avail;
    guint8 end[2];
    guint8 *data;

    /* last buffer take all data out of the adapter */
    avail = gst_adapter_available (rtpjpegdepay->adapter);
    GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");

    /* take the last bytes of the jpeg data to see if there is an EOI
     * marker */
    gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);

    if (end[0] != 0xff && end[1] != 0xd9) {
      GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");

      /* no EOI marker, add one */
      outbuf = gst_buffer_new_and_alloc (2);
      data = GST_BUFFER_DATA (outbuf);
      data[0] = 0xff;
      data[1] = 0xd9;

      gst_adapter_push (rtpjpegdepay->adapter, outbuf);
      avail += 2;
    }
    outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);

    GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
  }

  return outbuf;

  /* ERRORS */
empty_packet:
  {
    GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
        ("Empty Payload."), (NULL));
    return NULL;
  }
invalid_dimension:
  {
    GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
        ("Invalid Dimension %dx%d.", width, height), (NULL));
    return NULL;
  }
no_qtable:
  {
    GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
    return NULL;
  }
}
Esempio n. 14
0
static void
gst_ffmpegenc_flush_buffers (GstFFMpegEnc * ffmpegenc, gboolean send)
{
  GstBuffer *outbuf, *inbuf;
  gint ret_size;

  GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send);

  /* no need to empty codec if there is none */
  if (!ffmpegenc->opened)
    goto flush;

  while (!g_queue_is_empty (ffmpegenc->delay)) {

    ffmpegenc_setup_working_buf (ffmpegenc);

    ret_size = avcodec_encode_video (ffmpegenc->context,
        ffmpegenc->working_buf, ffmpegenc->working_buf_size, NULL);

    if (ret_size < 0) {         /* there should be something, notify and give up */
#ifndef GST_DISABLE_GST_DEBUG
      GstFFMpegEncClass *oclass =
          (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
      GST_WARNING_OBJECT (ffmpegenc,
          "ffenc_%s: failed to flush buffer", oclass->in_plugin->name);
#endif /* GST_DISABLE_GST_DEBUG */
      break;
    }

    /* save stats info if there is some as well as a stats file */
    if (ffmpegenc->file && ffmpegenc->context->stats_out)
      if (fprintf (ffmpegenc->file, "%s", ffmpegenc->context->stats_out) < 0)
        GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, WRITE,
            (("Could not write to file \"%s\"."), ffmpegenc->filename),
            GST_ERROR_SYSTEM);

    /* handle b-frame delay when no output, so we don't output empty frames */
    inbuf = g_queue_pop_head (ffmpegenc->delay);

    outbuf = gst_buffer_new_and_alloc (ret_size);
    memcpy (GST_BUFFER_DATA (outbuf), ffmpegenc->working_buf, ret_size);
    GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
    GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);

    if (!ffmpegenc->context->coded_frame->key_frame)
      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad));

    gst_buffer_unref (inbuf);

    if (send)
      gst_pad_push (ffmpegenc->srcpad, outbuf);
    else
      gst_buffer_unref (outbuf);
  }

flush:
  {
    /* make sure that we empty the queue, is still needed if we had to break */
    while (!g_queue_is_empty (ffmpegenc->delay))
      gst_buffer_unref (g_queue_pop_head (ffmpegenc->delay));
  }
}
Esempio n. 15
0
static GstFlowReturn
gst_rdt_depay_handle_data (GstRDTDepay * rdtdepay, GstClockTime outtime,
    GstRDTPacket * packet)
{
  GstFlowReturn ret;
  GstBuffer *outbuf;
  guint8 *data, *outdata;
  guint size;
  guint16 stream_id;
  guint32 timestamp;
  gint gap;
  guint16 seqnum;
  guint8 flags;
  guint16 outflags;

  /* get pointers to the packet data */
  gst_rdt_packet_data_peek_data (packet, &data, &size);

  outbuf = gst_buffer_new_and_alloc (12 + size);
  outdata = GST_BUFFER_DATA (outbuf);
  GST_BUFFER_TIMESTAMP (outbuf) = outtime;

  GST_DEBUG_OBJECT (rdtdepay, "have size %u", size);

  /* copy over some things */
  stream_id = gst_rdt_packet_data_get_stream_id (packet);
  timestamp = gst_rdt_packet_data_get_timestamp (packet);
  flags = gst_rdt_packet_data_get_flags (packet);

  seqnum = gst_rdt_packet_data_get_seq (packet);

  GST_DEBUG_OBJECT (rdtdepay, "stream_id %u, timestamp %u, seqnum %d, flags %d",
      stream_id, timestamp, seqnum, flags);

  if (rdtdepay->next_seqnum != -1) {
    gap = gst_rdt_buffer_compare_seqnum (seqnum, rdtdepay->next_seqnum);

    /* if we have no gap, all is fine */
    if (G_UNLIKELY (gap != 0)) {
      GST_LOG_OBJECT (rdtdepay, "got packet %u, expected %u, gap %d", seqnum,
          rdtdepay->next_seqnum, gap);
      if (gap < 0) {
        /* seqnum > next_seqnum, we are missing some packets, this is always a
         * DISCONT. */
        GST_LOG_OBJECT (rdtdepay, "%d missing packets", gap);
        rdtdepay->discont = TRUE;
      } else {
        /* seqnum < next_seqnum, we have seen this packet before or the sender
         * could be restarted. If the packet is not too old, we throw it away as
         * a duplicate, otherwise we mark discont and continue. 100 misordered
         * packets is a good threshold. See also RFC 4737. */
        if (gap < 100)
          goto dropping;

        GST_LOG_OBJECT (rdtdepay,
            "%d > 100, packet too old, sender likely restarted", gap);
        rdtdepay->discont = TRUE;
      }
    }
  }
  rdtdepay->next_seqnum = (seqnum + 1);
  if (rdtdepay->next_seqnum == 0xff00)
    rdtdepay->next_seqnum = 0;

  if ((flags & 1) == 0)
    outflags = 2;
  else
    outflags = 0;

  GST_WRITE_UINT16_BE (outdata + 0, 0); /* version   */
  GST_WRITE_UINT16_BE (outdata + 2, size + 12); /* length    */
  GST_WRITE_UINT16_BE (outdata + 4, stream_id); /* stream    */
  GST_WRITE_UINT32_BE (outdata + 6, timestamp); /* timestamp */
  GST_WRITE_UINT16_BE (outdata + 10, outflags); /* flags     */
  memcpy (outdata + 12, data, size);

  GST_DEBUG_OBJECT (rdtdepay, "Pushing packet, outtime %" GST_TIME_FORMAT,
      GST_TIME_ARGS (outtime));

  ret = gst_rdt_depay_push (rdtdepay, outbuf);

  return ret;

  /* ERRORS */
dropping:
  {
    GST_WARNING_OBJECT (rdtdepay, "%d <= 100, dropping old packet", gap);
    return GST_FLOW_OK;
  }
}
Esempio n. 16
0
static GstFlowReturn
gst_tta_dec_chain (GstPad * pad, GstBuffer * in)
{
  GstTtaDec *ttadec;
  GstBuffer *outbuf, *buf = GST_BUFFER (in);
  guchar *data, *p;
  decoder *dec;
  unsigned long outsize;
  unsigned long size;
  guint32 frame_samples;
  long res;
  long *prev;

  ttadec = GST_TTA_DEC (GST_OBJECT_PARENT (pad));

  data = GST_BUFFER_DATA (buf);
  size = GST_BUFFER_SIZE (buf);

  ttadec->tta_buf.bit_count = 0;
  ttadec->tta_buf.bit_cache = 0;
  ttadec->tta_buf.bitpos = ttadec->tta_buf.buffer_end;
  ttadec->tta_buf.offset = 0;
  decoder_init (ttadec->tta, ttadec->channels, ttadec->bytes);

  if (GST_BUFFER_DURATION_IS_VALID (buf)) {
    frame_samples =
        ceil ((gdouble) (GST_BUFFER_DURATION (buf) * ttadec->samplerate) /
        (gdouble) GST_SECOND);
  } else {
    frame_samples = ttadec->samplerate * FRAME_TIME;
  }
  outsize = ttadec->channels * frame_samples * ttadec->bytes;

  dec = ttadec->tta;
  p = ttadec->decdata;
  prev = ttadec->cache;
  for (res = 0;
      p < ttadec->decdata + frame_samples * ttadec->channels * ttadec->bytes;) {
    unsigned long unary, binary, depth, k;
    long value, temp_value;
    fltst *fst = &dec->fst;
    adapt *rice = &dec->rice;
    long *last = &dec->last;

    // decode Rice unsigned
    get_unary (&ttadec->tta_buf, data, size, &unary);

    switch (unary) {
      case 0:
        depth = 0;
        k = rice->k0;
        break;
      default:
        depth = 1;
        k = rice->k1;
        unary--;
    }

    if (k) {
      get_binary (&ttadec->tta_buf, data, size, &binary, k);
      value = (unary << k) + binary;
    } else
      value = unary;

    switch (depth) {
      case 1:
        rice->sum1 += value - (rice->sum1 >> 4);
        if (rice->k1 > 0 && rice->sum1 < shift_16[rice->k1])
          rice->k1--;
        else if (rice->sum1 > shift_16[rice->k1 + 1])
          rice->k1++;
        value += bit_shift[rice->k0];
      default:
        rice->sum0 += value - (rice->sum0 >> 4);
        if (rice->k0 > 0 && rice->sum0 < shift_16[rice->k0])
          rice->k0--;
        else if (rice->sum0 > shift_16[rice->k0 + 1])
          rice->k0++;
    }

    /* this only uses a temporary variable to silence a gcc warning */
    temp_value = DEC (value);
    value = temp_value;

    // decompress stage 1: adaptive hybrid filter
    hybrid_filter (fst, &value);

    // decompress stage 2: fixed order 1 prediction
    switch (ttadec->bytes) {
      case 1:
        value += PREDICTOR1 (*last, 4);
        break;                  // bps 8
      case 2:
        value += PREDICTOR1 (*last, 5);
        break;                  // bps 16
      case 3:
        value += PREDICTOR1 (*last, 5);
        break;                  // bps 24
      case 4:
        value += *last;
        break;                  // bps 32
    }
    *last = value;

    if (dec < ttadec->tta + ttadec->channels - 1) {
      *prev++ = value;
      dec++;
    } else {
      *prev = value;
      if (ttadec->channels > 1) {
        long *r = prev - 1;

        for (*prev += *r / 2; r >= ttadec->cache; r--)
          *r = *(r + 1) - *r;
        for (r = ttadec->cache; r < prev; r++)
          WRITE_BUFFER (r, ttadec->bytes, p);
      }
      WRITE_BUFFER (prev, ttadec->bytes, p);
      prev = ttadec->cache;
      res++;
      dec = ttadec->tta;
    }
  }

  outbuf = gst_buffer_new_and_alloc (outsize);
  memcpy (GST_BUFFER_DATA (outbuf), ttadec->decdata, outsize);
  GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
  GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ttadec->srcpad));
  return gst_pad_push (ttadec->srcpad, outbuf);
}
Esempio n. 17
0
static GstBuffer *
gst_cd_paranoia_src_read_sector (GstCddaBaseSrc * cddabasesrc, gint sector)
{
  GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (cddabasesrc);
  GstBuffer *buf;
  gboolean do_serialize;
  gint16 *cdda_buf;

#if 0
  /* Do we really need to output this? (tpm) */
  /* Due to possible autocorrections of start sectors of audio tracks on 
   * multisession cds, we can maybe not compute the correct discid.
   * So issue a warning.
   * See cdparanoia/interface/common-interface.c:FixupTOC */
  if (src->d && src->d->cd_extra) {
    g_message
        ("DiscID on multisession discs might be broken. Use at own risk.");
  }
#endif

  if (src->next_sector == -1 || src->next_sector != sector) {
    if (paranoia_seek (src->p, sector, SEEK_SET) == -1)
      goto seek_failed;

    GST_DEBUG_OBJECT (src, "successfully seeked to sector %d", sector);
    src->next_sector = sector;
  }

  do_serialize =
      gst_cd_paranoia_src_signal_is_being_watched (src, TRANSPORT_ERROR) ||
      gst_cd_paranoia_src_signal_is_being_watched (src, UNCORRECTED_ERROR);

  if (do_serialize) {
    GST_LOG_OBJECT (src, "Signal handlers connected, serialising access");
    g_static_mutex_lock (&cur_cb_mutex);
    GST_LOG_OBJECT (src, "Got lock");
    cur_cb_source = src;

    cdda_buf = paranoia_read (src->p, gst_cd_paranoia_paranoia_callback);

    cur_cb_source = NULL;
    GST_LOG_OBJECT (src, "Releasing lock");
    g_static_mutex_unlock (&cur_cb_mutex);
  } else {
    cdda_buf = paranoia_read (src->p, gst_cd_paranoia_dummy_callback);
  }

  if (cdda_buf == NULL)
    goto read_failed;

  buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW);
  memcpy (GST_BUFFER_DATA (buf), cdda_buf, CD_FRAMESIZE_RAW);

  /* cdda base class will take care of timestamping etc. */
  ++src->next_sector;

  return buf;

  /* ERRORS */
seek_failed:
  {
    GST_WARNING_OBJECT (src, "seek to sector %d failed!", sector);
    GST_ELEMENT_ERROR (src, RESOURCE, SEEK,
        (_("Could not seek CD.")),
        ("paranoia_seek to %d failed: %s", sector, g_strerror (errno)));
    return NULL;
  }
read_failed:
  {
    GST_WARNING_OBJECT (src, "read at sector %d failed!", sector);
    GST_ELEMENT_ERROR (src, RESOURCE, READ,
        (_("Could not read CD.")),
        ("paranoia_read at %d failed: %s", sector, g_strerror (errno)));
    return NULL;
  }
}
Esempio n. 18
0
static GstFlowReturn
gst_wavenc_write_toc (GstWavEnc * wavenc)
{
  GList *list;
  GstToc *toc;
  GstTocEntry *entry, *subentry;
  GstBuffer *buf;
  GstMapInfo map;
  guint8 *data;
  guint32 ncues, size, cues_size, labls_size, notes_size;

  if (!wavenc->toc) {
    GST_DEBUG_OBJECT (wavenc, "have no toc, checking toc_setter");
    wavenc->toc = gst_toc_setter_get_toc (GST_TOC_SETTER (wavenc));
  }
  if (!wavenc->toc) {
    GST_WARNING_OBJECT (wavenc, "have no toc");
    return GST_FLOW_OK;
  }

  toc = gst_toc_ref (wavenc->toc);
  size = 0;
  cues_size = 0;
  labls_size = 0;
  notes_size = 0;

  /* check if the TOC entries is valid */
  list = gst_toc_get_entries (toc);
  entry = list->data;
  if (gst_toc_entry_is_alternative (entry)) {
    list = gst_toc_entry_get_sub_entries (entry);
    while (list) {
      subentry = list->data;
      if (!gst_toc_entry_is_sequence (subentry))
        return FALSE;
      list = g_list_next (list);
    }
    list = gst_toc_entry_get_sub_entries (entry);
  }
  if (gst_toc_entry_is_sequence (entry)) {
    while (list) {
      entry = list->data;
      if (!gst_toc_entry_is_sequence (entry))
        return FALSE;
      list = g_list_next (list);
    }
    list = gst_toc_get_entries (toc);
  }

  ncues = g_list_length (list);
  GST_DEBUG_OBJECT (wavenc, "number of cue entries: %d", ncues);

  while (list) {
    guint32 id = 0;
    gint64 id64;
    const gchar *uid;

    entry = list->data;
    uid = gst_toc_entry_get_uid (entry);
    id64 = g_ascii_strtoll (uid, NULL, 0);
    /* check if id unique compatible with guint32 else generate random */
    if (id64 >= 0 && gst_wavenc_is_cue_id_unique (id64, wavenc->cues)) {
      id = (guint32) id64;
    } else {
      do {
        id = g_random_int ();
      } while (!gst_wavenc_is_cue_id_unique (id, wavenc->cues));
    }
    gst_wavenc_parse_cue (wavenc, id, entry);
    gst_wavenc_parse_labl (wavenc, id, entry);
    gst_wavenc_parse_note (wavenc, id, entry);
    list = g_list_next (list);
  }

  /* count cues size */
  if (wavenc->cues) {
    cues_size = 24 * g_list_length (wavenc->cues);
    size += 12 + cues_size;
  } else {
    GST_WARNING_OBJECT (wavenc, "cue's not found");
    return FALSE;
  }
  /* count labls size */
  if (wavenc->labls) {
    list = wavenc->labls;
    while (list) {
      GstWavEncLabl *labl;
      labl = list->data;
      labls_size += 8 + GST_ROUND_UP_2 (labl->chunk_data_size);
      list = g_list_next (list);
    }
    size += labls_size;
  }
  /* count notes size */
  if (wavenc->notes) {
    list = wavenc->notes;
    while (list) {
      GstWavEncNote *note;
      note = list->data;
      notes_size += 8 + GST_ROUND_UP_2 (note->chunk_data_size);
      list = g_list_next (list);
    }
    size += notes_size;
  }
  if (wavenc->labls || wavenc->notes) {
    size += 12;
  }

  buf = gst_buffer_new_and_alloc (size);
  gst_buffer_map (buf, &map, GST_MAP_WRITE);
  data = map.data;
  memset (data, 0, size);

  /* write Cue Chunk */
  if (wavenc->cues) {
    memcpy (data, (gchar *) "cue ", 4);
    GST_WRITE_UINT32_LE (data + 4, 4 + cues_size);
    GST_WRITE_UINT32_LE (data + 8, ncues);
    data += 12;
    gst_wavenc_write_cues (&data, wavenc->cues);

    /* write Associated Data List Chunk */
    if (wavenc->labls || wavenc->notes) {
      memcpy (data, (gchar *) "LIST", 4);
      GST_WRITE_UINT32_LE (data + 4, 4 + labls_size + notes_size);
      memcpy (data + 8, (gchar *) "adtl", 4);
      data += 12;
      if (wavenc->labls)
        gst_wavenc_write_labls (&data, wavenc->labls);
      if (wavenc->notes)
        gst_wavenc_write_notes (&data, wavenc->notes);
    }
  }

  /* free resources */
  if (toc)
    gst_toc_unref (toc);
  if (wavenc->cues)
    g_list_free_full (wavenc->cues, g_free);
  if (wavenc->labls)
    g_list_free_full (wavenc->labls, g_free);
  if (wavenc->notes)
    g_list_free_full (wavenc->notes, g_free);

  gst_buffer_unmap (buf, &map);
  wavenc->meta_length += gst_buffer_get_size (buf);

  return gst_pad_push (wavenc->srcpad, buf);
}
Esempio n. 19
0
void test_more()
{
  GstElement *videorate;
  GstBuffer *first, *second, *third, *outbuffer;
  GList *l;
  GstCaps *caps;
  GRand *rand;

  videorate = setup_videorate ();
  fail_unless (gst_element_set_state (videorate,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
      "could not set to playing");
  assert_videorate_stats (videorate, "creation", 0, 0, 0, 0);

  rand = g_rand_new ();

  /* first buffer */
  first = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (first) = 0;
  /* it shouldn't matter what the offsets are, videorate produces perfect
     streams */
  GST_BUFFER_OFFSET (first) = g_rand_int (rand);
  GST_BUFFER_OFFSET_END (first) = g_rand_int (rand);
  memset (GST_BUFFER_DATA (first), 1, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  gst_buffer_set_caps (first, caps);
  gst_caps_unref (caps);
  ASSERT_BUFFER_REFCOUNT (first, "first", 1);
  gst_buffer_ref (first);

  /* pushing gives away my reference ... */
  fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK);
  /* ... and it is now stuck inside videorate */
  ASSERT_BUFFER_REFCOUNT (first, "first", 2);
  fail_unless_equals_int (g_list_length (buffers), 0);
  assert_videorate_stats (videorate, "first buffer", 1, 0, 0, 0);

  /* second buffer; inbetween second and third output frame's timestamp */
  second = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (second) = GST_SECOND * 3 / 50;
  GST_BUFFER_OFFSET (first) = g_rand_int (rand);
  GST_BUFFER_OFFSET_END (first) = g_rand_int (rand);
  memset (GST_BUFFER_DATA (second), 2, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  gst_buffer_set_caps (second, caps);
  gst_caps_unref (caps);
  ASSERT_BUFFER_REFCOUNT (second, "second", 1);
  gst_buffer_ref (second);

  /* pushing gives away one of my references ... */
  fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
  /* ... and it is now stuck inside videorate */
  ASSERT_BUFFER_REFCOUNT (second, "second", 2);

  /* ... and the first one is pushed out, with timestamp 0 */
  fail_unless_equals_int (g_list_length (buffers), 1);
  assert_videorate_stats (videorate, "second buffer", 2, 1, 0, 0);
  ASSERT_BUFFER_REFCOUNT (first, "first", 2);

  outbuffer = buffers->data;
  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer), 0);

  /* third buffer */
  third = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (third) = GST_SECOND * 12 / 50;
  GST_BUFFER_OFFSET (first) = g_rand_int (rand);
  GST_BUFFER_OFFSET_END (first) = g_rand_int (rand);
  memset (GST_BUFFER_DATA (third), 3, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  gst_buffer_set_caps (third, caps);
  gst_caps_unref (caps);
  ASSERT_BUFFER_REFCOUNT (third, "third", 1);
  gst_buffer_ref (third);

  /* pushing gives away my reference ... */
  fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK);
  /* ... and it is now stuck inside videorate */
  ASSERT_BUFFER_REFCOUNT (third, "third", 2);

  /* submitting the third buffer has triggered flushing of three more frames */
  assert_videorate_stats (videorate, "third buffer", 3, 4, 0, 2);

  /* check timestamp and source correctness */
  l = buffers;
  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data), 0);
  fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 1);
  fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 0);
  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 1);

  l = g_list_next (l);
  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data), GST_SECOND / 25);
  fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 2);
  fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 1);
  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 2);

  l = g_list_next (l);
  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data),
      GST_SECOND * 2 / 25);
  fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 2);
  fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 2);
  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 3);

  l = g_list_next (l);
  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data),
      GST_SECOND * 3 / 25);
  fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 2);
  fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 3);
  fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 4);

  fail_unless_equals_int (g_list_length (buffers), 4);
  /* one held by us, three held by each output frame taken from the second */
  ASSERT_BUFFER_REFCOUNT (second, "second", 4);

  /* now send EOS */
  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));

  /* submitting eos should flush out two more frames for tick 8 and 10 */
  /* FIXME: right now it only flushes out one, so out is 5 instead of 6 ! */
  assert_videorate_stats (videorate, "eos", 3, 5, 0, 2);
  fail_unless_equals_int (g_list_length (buffers), 5);

  /* cleanup */
  g_rand_free (rand);
  gst_buffer_unref (first);
  gst_buffer_unref (second);
  gst_buffer_unref (third);
  cleanup_videorate (videorate);
  std_log(LOG_FILENAME_LINE, "Test Successful");
  create_xml(0);
}
Esempio n. 20
0
void
gst_audio_fx_base_fir_filter_push_residue (GstAudioFXBaseFIRFilter * self)
{
  GstBuffer *outbuf;
  GstFlowReturn res;
  gint rate = GST_AUDIO_FILTER_RATE (self);
  gint channels = GST_AUDIO_FILTER_CHANNELS (self);
  gint bps = GST_AUDIO_FILTER_BPS (self);
  gint outsize, outsamples;
  GstMapInfo map;
  guint8 *in, *out;

  if (channels == 0 || rate == 0 || self->nsamples_in == 0) {
    self->buffer_fill = 0;
    g_free (self->buffer);
    self->buffer = NULL;
    return;
  }

  /* Calculate the number of samples and their memory size that
   * should be pushed from the residue */
  outsamples = self->nsamples_in - (self->nsamples_out - self->latency);
  if (outsamples <= 0) {
    self->buffer_fill = 0;
    g_free (self->buffer);
    self->buffer = NULL;
    return;
  }
  outsize = outsamples * channels * bps;

  if (!self->fft || self->low_latency) {
    gint64 diffsize, diffsamples;

    /* Process the difference between latency and residue length samples
     * to start at the actual data instead of starting at the zeros before
     * when we only got one buffer smaller than latency */
    diffsamples =
        ((gint64) self->latency) - ((gint64) self->buffer_fill) / channels;
    if (diffsamples > 0) {
      diffsize = diffsamples * channels * bps;
      in = g_new0 (guint8, diffsize);
      out = g_new0 (guint8, diffsize);
      self->nsamples_out += self->process (self, in, out, diffsamples);
      g_free (in);
      g_free (out);
    }

    outbuf = gst_buffer_new_and_alloc (outsize);

    /* Convolve the residue with zeros to get the actual remaining data */
    in = g_new0 (guint8, outsize);
    gst_buffer_map (outbuf, &map, GST_MAP_READWRITE);
    self->nsamples_out += self->process (self, in, map.data, outsamples);
    gst_buffer_unmap (outbuf, &map);

    g_free (in);
  } else {
    guint gensamples = 0;

    outbuf = gst_buffer_new_and_alloc (outsize);
    gst_buffer_map (outbuf, &map, GST_MAP_READWRITE);

    while (gensamples < outsamples) {
      guint step_insamples = self->block_length - self->buffer_fill;
      guint8 *zeroes = g_new0 (guint8, step_insamples * channels * bps);
      guint8 *out = g_new (guint8, self->block_length * channels * bps);
      guint step_gensamples;

      step_gensamples = self->process (self, zeroes, out, step_insamples);
      g_free (zeroes);

      memcpy (map.data + gensamples * bps, out, MIN (step_gensamples,
              outsamples - gensamples) * bps);
      gensamples += MIN (step_gensamples, outsamples - gensamples);

      g_free (out);
    }
    self->nsamples_out += gensamples;

    gst_buffer_unmap (outbuf, &map);
  }

  /* Set timestamp, offset, etc from the values we
   * saved when processing the regular buffers */
  if (GST_CLOCK_TIME_IS_VALID (self->start_ts))
    GST_BUFFER_TIMESTAMP (outbuf) = self->start_ts;
  else
    GST_BUFFER_TIMESTAMP (outbuf) = 0;
  GST_BUFFER_TIMESTAMP (outbuf) +=
      gst_util_uint64_scale_int (self->nsamples_out - outsamples -
      self->latency, GST_SECOND, rate);

  GST_BUFFER_DURATION (outbuf) =
      gst_util_uint64_scale_int (outsamples, GST_SECOND, rate);

  if (self->start_off != GST_BUFFER_OFFSET_NONE) {
    GST_BUFFER_OFFSET (outbuf) =
        self->start_off + self->nsamples_out - outsamples - self->latency;
    GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + outsamples;
  }

  GST_DEBUG_OBJECT (self,
      "Pushing residue buffer of size %" G_GSIZE_FORMAT " with timestamp: %"
      GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
      G_GUINT64_FORMAT ", offset_end: %" G_GUINT64_FORMAT ", nsamples_out: %d",
      gst_buffer_get_size (outbuf),
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
      GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
      GST_BUFFER_OFFSET_END (outbuf), outsamples);

  res = gst_pad_push (GST_BASE_TRANSFORM_CAST (self)->srcpad, outbuf);

  if (G_UNLIKELY (res != GST_FLOW_OK)) {
    GST_WARNING_OBJECT (self, "failed to push residue");
  }

  self->buffer_fill = 0;
}
Esempio n. 21
0
/* send frames with 0, 1, 2, 0 seconds */
void test_wrong_order()
{
  GstElement *videorate;
  GstBuffer *first, *second, *third, *fourth, *outbuffer;
  GstCaps *caps;

  videorate = setup_videorate ();
  fail_unless (gst_element_set_state (videorate,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
      "could not set to playing");
  assert_videorate_stats (videorate, "start", 0, 0, 0, 0);

  /* first buffer */
  first = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (first) = 0;
  memset (GST_BUFFER_DATA (first), 0, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  gst_buffer_set_caps (first, caps);
  gst_caps_unref (caps);
  ASSERT_BUFFER_REFCOUNT (first, "first", 1);
  gst_buffer_ref (first);

  GST_DEBUG ("pushing first buffer");
  /* pushing gives away my reference ... */
  fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK);
  /* ... and it is now stuck inside videorate */
  ASSERT_BUFFER_REFCOUNT (first, "first", 2);
  fail_unless_equals_int (g_list_length (buffers), 0);
  assert_videorate_stats (videorate, "first", 1, 0, 0, 0);

  /* second buffer */
  second = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (second) = GST_SECOND;
  memset (GST_BUFFER_DATA (second), 0, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  gst_buffer_set_caps (second, caps);
  gst_caps_unref (caps);
  ASSERT_BUFFER_REFCOUNT (second, "second", 1);
  gst_buffer_ref (second);

  /* pushing gives away my reference ... */
  fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
  /* ... and it is now stuck inside videorate */
  ASSERT_BUFFER_REFCOUNT (second, "second", 2);
  /* and it created 13 output buffers as copies of the first frame */
  fail_unless_equals_int (g_list_length (buffers), 13);
  assert_videorate_stats (videorate, "second", 2, 13, 0, 12);
  ASSERT_BUFFER_REFCOUNT (first, "first", 14);

  /* third buffer */
  third = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND;
  memset (GST_BUFFER_DATA (third), 0, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  gst_buffer_set_caps (third, caps);
  gst_caps_unref (caps);
  ASSERT_BUFFER_REFCOUNT (third, "third", 1);
  gst_buffer_ref (third);

  /* pushing gives away my reference ... */
  fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK);
  /* ... and it is now stuck inside videorate */
  ASSERT_BUFFER_REFCOUNT (third, "third", 2);

  /* submitting a frame with 2 seconds triggers output of 25 more frames */
  fail_unless_equals_int (g_list_length (buffers), 38);
  ASSERT_BUFFER_REFCOUNT (first, "first", 14);
  ASSERT_BUFFER_REFCOUNT (second, "second", 26);
  /* three frames submitted; two of them output as is, and 36 duplicated */
  assert_videorate_stats (videorate, "third", 3, 38, 0, 36);

  /* fourth buffer */
  fourth = gst_buffer_new_and_alloc (4);
  GST_BUFFER_TIMESTAMP (fourth) = 0;
  memset (GST_BUFFER_DATA (fourth), 0, 4);
  caps = gst_caps_from_string (VIDEO_CAPS_STRING);
  gst_buffer_set_caps (fourth, caps);
  gst_caps_unref (caps);
  ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1);
  gst_buffer_ref (fourth);

  /* pushing gives away my reference ... */
  fail_unless (gst_pad_push (mysrcpad, fourth) == GST_FLOW_OK);
  /* ... and it is dropped */
  ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1);

  fail_unless_equals_int (g_list_length (buffers), 38);
  ASSERT_BUFFER_REFCOUNT (first, "first", 14);
  ASSERT_BUFFER_REFCOUNT (second, "second", 26);
  assert_videorate_stats (videorate, "fourth", 4, 38, 1, 36);

  /* verify last buffer */
  outbuffer = g_list_last (buffers)->data;
  fail_unless (GST_IS_BUFFER (outbuffer));
  fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer),
      GST_SECOND * 37 / 25);


  /* cleanup */
  gst_buffer_unref (first);
  gst_buffer_unref (second);
  gst_buffer_unref (third);
  gst_buffer_unref (fourth);
  cleanup_videorate (videorate);
  std_log(LOG_FILENAME_LINE, "Test Successful");
  create_xml(0);
}
Esempio n. 22
0
static GstFlowReturn
gst_tcp_server_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
{
  GstTCPServerSrc *src;
  GstFlowReturn ret = GST_FLOW_OK;
  gssize rret, avail;
  gsize read;
  GError *err = NULL;
  GstMapInfo map;

  src = GST_TCP_SERVER_SRC (psrc);

  if (!GST_OBJECT_FLAG_IS_SET (src, GST_TCP_SERVER_SRC_OPEN))
    goto wrong_state;

  if (!src->client_socket) {
    /* wait on server socket for connections */
    src->client_socket =
        g_socket_accept (src->server_socket, src->cancellable, &err);
    if (!src->client_socket)
      goto accept_error;
    /* now read from the socket. */
  }

  /* if we have a client, wait for read */
  GST_LOG_OBJECT (src, "asked for a buffer");

  /* read the buffer header */
  avail = g_socket_get_available_bytes (src->client_socket);
  if (avail < 0) {
    goto get_available_error;
  } else if (avail == 0) {
    GIOCondition condition;

    if (!g_socket_condition_wait (src->client_socket,
            G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, src->cancellable, &err))
      goto select_error;

    condition =
        g_socket_condition_check (src->client_socket,
        G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP);

    if ((condition & G_IO_ERR)) {
      GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
          ("Socket in error state"));
      *outbuf = NULL;
      ret = GST_FLOW_ERROR;
      goto done;
    } else if ((condition & G_IO_HUP)) {
      GST_DEBUG_OBJECT (src, "Connection closed");
      *outbuf = NULL;
      ret = GST_FLOW_EOS;
      goto done;
    }
    avail = g_socket_get_available_bytes (src->client_socket);
    if (avail < 0)
      goto get_available_error;
  }

  if (avail > 0) {
    read = MIN (avail, MAX_READ_SIZE);
    *outbuf = gst_buffer_new_and_alloc (read);
    gst_buffer_map (*outbuf, &map, GST_MAP_READWRITE);
    rret =
        g_socket_receive (src->client_socket, (gchar *) map.data, read,
        src->cancellable, &err);
  } else {
    /* Connection closed */
    rret = 0;
    *outbuf = NULL;
    read = 0;
  }

  if (rret == 0) {
    GST_DEBUG_OBJECT (src, "Connection closed");
    ret = GST_FLOW_EOS;
    if (*outbuf) {
      gst_buffer_unmap (*outbuf, &map);
      gst_buffer_unref (*outbuf);
    }
    *outbuf = NULL;
  } else if (rret < 0) {
    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
      ret = GST_FLOW_FLUSHING;
      GST_DEBUG_OBJECT (src, "Cancelled reading from socket");
    } else {
      ret = GST_FLOW_ERROR;
      GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
          ("Failed to read from socket: %s", err->message));
    }
    gst_buffer_unmap (*outbuf, &map);
    gst_buffer_unref (*outbuf);
    *outbuf = NULL;
  } else {
    ret = GST_FLOW_OK;
    gst_buffer_unmap (*outbuf, &map);
    gst_buffer_resize (*outbuf, 0, rret);

    GST_LOG_OBJECT (src,
        "Returning buffer from _get of size %" G_GSIZE_FORMAT ", ts %"
        GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
        ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
        gst_buffer_get_size (*outbuf),
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (*outbuf)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (*outbuf)),
        GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf));
  }
  g_clear_error (&err);

done:
  return ret;

wrong_state:
  {
    GST_DEBUG_OBJECT (src, "connection to closed, cannot read data");
    return GST_FLOW_FLUSHING;
  }
accept_error:
  {
    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
      GST_DEBUG_OBJECT (src, "Cancelled accepting of client");
    } else {
      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
          ("Failed to accept client: %s", err->message));
    }
    g_clear_error (&err);
    return GST_FLOW_ERROR;
  }
select_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("Select failed: %s", err->message));
    g_clear_error (&err);
    return GST_FLOW_ERROR;
  }
get_available_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("Failed to get available bytes from socket"));
    return GST_FLOW_ERROR;
  }
}
Esempio n. 23
0
static GstFlowReturn
gst_pngenc_chain (GstPad * pad, GstBuffer * buf)
{
  GstPngEnc *pngenc;
  gint row_index;
  gint color_type;
  png_byte *row_pointers[MAX_HEIGHT];
  GstFlowReturn ret = GST_FLOW_OK;
  GstBuffer *encoded_buf = NULL;

  pngenc = GST_PNGENC (gst_pad_get_parent (pad));

  GST_DEBUG_OBJECT (pngenc, "BEGINNING");

  /* initialize png struct stuff */
  pngenc->png_struct_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
      (png_voidp) NULL, user_error_fn, user_warning_fn);
  if (pngenc->png_struct_ptr == NULL) {
    gst_buffer_unref (buf);
    GST_ELEMENT_ERROR (pngenc, LIBRARY, INIT, (NULL),
        ("Failed to initialize png structure"));
    ret = GST_FLOW_ERROR;
    goto done;
  }

  pngenc->png_info_ptr = png_create_info_struct (pngenc->png_struct_ptr);
  if (!pngenc->png_info_ptr) {
    gst_buffer_unref (buf);
    png_destroy_write_struct (&(pngenc->png_struct_ptr), (png_infopp) NULL);
    GST_ELEMENT_ERROR (pngenc, LIBRARY, INIT, (NULL),
        ("Failed to initialize the png info structure"));
    ret = GST_FLOW_ERROR;
    goto done;
  }

  /* non-0 return is from a longjmp inside of libpng */
  if (setjmp (png_jmpbuf (pngenc->png_struct_ptr)) != 0) {
    gst_buffer_unref (buf);
    png_destroy_write_struct (&pngenc->png_struct_ptr, &pngenc->png_info_ptr);
    GST_ELEMENT_ERROR (pngenc, LIBRARY, FAILED, (NULL),
        ("returning from longjmp"));
    ret = GST_FLOW_ERROR;
    goto done;
  }

  png_set_filter (pngenc->png_struct_ptr, 0,
      PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE);
  png_set_compression_level (pngenc->png_struct_ptr, pngenc->compression_level);

  if (pngenc->bpp == 32)
    color_type = PNG_COLOR_TYPE_RGBA;
  else if (pngenc->bpp == 8)
    color_type = PNG_COLOR_TYPE_GRAY;
  else
    color_type = PNG_COLOR_TYPE_RGB;

  png_set_IHDR (pngenc->png_struct_ptr,
      pngenc->png_info_ptr,
      pngenc->width,
      pngenc->height,
      8,
      color_type,
      PNG_INTERLACE_NONE,
      PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

  png_set_write_fn (pngenc->png_struct_ptr, pngenc,
      (png_rw_ptr) user_write_data, user_flush_data);

  for (row_index = 0; row_index < pngenc->height; row_index++) {
    row_pointers[row_index] = GST_BUFFER_DATA (buf) +
        (row_index * pngenc->stride);
  }

  /* allocate the output buffer */
  pngenc->buffer_out =
      gst_buffer_new_and_alloc (pngenc->height * pngenc->stride);
  pngenc->written = 0;

  png_write_info (pngenc->png_struct_ptr, pngenc->png_info_ptr);
  png_write_image (pngenc->png_struct_ptr, row_pointers);
  png_write_end (pngenc->png_struct_ptr, NULL);

  encoded_buf = gst_buffer_create_sub (pngenc->buffer_out, 0, pngenc->written);

  png_destroy_info_struct (pngenc->png_struct_ptr, &pngenc->png_info_ptr);
  png_destroy_write_struct (&pngenc->png_struct_ptr, (png_infopp) NULL);
  gst_buffer_copy_metadata (encoded_buf, buf, GST_BUFFER_COPY_TIMESTAMPS);
  gst_buffer_unref (buf);
  gst_buffer_set_caps (encoded_buf, GST_PAD_CAPS (pngenc->srcpad));

  if ((ret = gst_pad_push (pngenc->srcpad, encoded_buf)) != GST_FLOW_OK)
    goto done;

  if (pngenc->snapshot) {
    GstEvent *event;

    GST_DEBUG_OBJECT (pngenc, "snapshot mode, sending EOS");
    /* send EOS event, since a frame has been pushed out */
    event = gst_event_new_eos ();

    gst_pad_push_event (pngenc->srcpad, event);
    ret = GST_FLOW_UNEXPECTED;
  }

done:
  GST_DEBUG_OBJECT (pngenc, "END, ret:%d", ret);

  if (pngenc->buffer_out != NULL) {
    gst_buffer_unref (pngenc->buffer_out);
    pngenc->buffer_out = NULL;
  }

  gst_object_unref (pngenc);
  return ret;
}
Esempio n. 24
0
static GstFlowReturn
gst_mulawenc_chain (GstPad * pad, GstBuffer * buffer)
{
  GstMuLawEnc *mulawenc;
  gint16 *linear_data;
  guint linear_size;
  guint8 *mulaw_data;
  guint mulaw_size;
  GstBuffer *outbuf;
  GstFlowReturn ret;
  GstClockTime timestamp, duration;

  mulawenc = GST_MULAWENC (gst_pad_get_parent (pad));

  if (!mulawenc->rate || !mulawenc->channels)
    goto not_negotiated;

  linear_data = (gint16 *) GST_BUFFER_DATA (buffer);
  linear_size = GST_BUFFER_SIZE (buffer);

  mulaw_size = linear_size / 2;

  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  duration = GST_BUFFER_DURATION (buffer);

  ret = gst_pad_alloc_buffer_and_set_caps (mulawenc->srcpad,
      GST_BUFFER_OFFSET_NONE, mulaw_size, GST_PAD_CAPS (mulawenc->srcpad),
      &outbuf);
  if (ret != GST_FLOW_OK)
    goto alloc_failed;

  if (duration == -1) {
    duration = gst_util_uint64_scale_int (mulaw_size,
        GST_SECOND, mulawenc->rate * mulawenc->channels);
  }

  if (GST_BUFFER_SIZE (outbuf) < mulaw_size) {
    /* pad-alloc can suggest a smaller size */
    gst_buffer_unref (outbuf);
    outbuf = gst_buffer_new_and_alloc (mulaw_size);
  }

  mulaw_data = (guint8 *) GST_BUFFER_DATA (outbuf);

  /* copy discont flag */
  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);

  GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
  GST_BUFFER_DURATION (outbuf) = duration;

  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (mulawenc->srcpad));

  mulaw_encode (linear_data, mulaw_data, mulaw_size);

  gst_buffer_unref (buffer);

  ret = gst_pad_push (mulawenc->srcpad, outbuf);

done:
  gst_object_unref (mulawenc);

  return ret;

not_negotiated:
  {
    GST_DEBUG_OBJECT (mulawenc, "no format negotiated");
    ret = GST_FLOW_NOT_NEGOTIATED;
    gst_buffer_unref (buffer);
    goto done;
  }
alloc_failed:
  {
    GST_DEBUG_OBJECT (mulawenc, "pad alloc failed");
    gst_buffer_unref (buffer);
    goto done;
  }
}
Esempio n. 25
0
/* chain function
 * this function does the actual processing
 */
static GstFlowReturn
audio_trim_chain (GstPad * pad, GstBuffer * buf)
{
  AudioTrim *filter;

  g_assert(GST_BUFFER_OFFSET(buf) != GST_BUFFER_OFFSET_NONE);
  g_assert(GST_BUFFER_OFFSET_END(buf) != GST_BUFFER_OFFSET_NONE);
  
  filter = AUDIO_TRIM (GST_OBJECT_PARENT (pad));
  while(buf) {
    g_assert(GST_IS_BUFFER(buf));
    switch(filter->trim_state) {
    case AUDIO_TRIM_NOT_STARTED:
      filter->ref_time = (GST_BUFFER_OFFSET(buf)
			  + time_to_sample(filter, filter->start_skip));
      if (filter->empty_start_packet) {
	GstFlowReturn ret;
	GstBuffer *first;
	first = gst_buffer_new_and_alloc (sizeof(gfloat));
	*(gfloat*)GST_BUFFER_DATA(first) = 0.0;
	GST_BUFFER_SIZE(first) = 4;
	GST_BUFFER_OFFSET(first) = GST_BUFFER_OFFSET(buf); 
	GST_BUFFER_OFFSET_END(first) = GST_BUFFER_OFFSET(buf);
	GST_BUFFER_TIMESTAMP(first) = GST_BUFFER_TIMESTAMP(buf);
	GST_BUFFER_DURATION(first) = 0;
	GST_BUFFER_CAPS(first) = gst_caps_ref(GST_BUFFER_CAPS(buf));
	
	ret = gst_pad_push(filter->srcpad, first);
	if (ret != GST_FLOW_OK) {
	  gst_buffer_unref(buf);
	  return ret;
	}
      }
      filter->trim_state = AUDIO_TRIM_START_SKIP;
      break;
    case AUDIO_TRIM_START_SKIP:
      if (GST_BUFFER_OFFSET_END(buf) <= filter->ref_time) {
	gst_buffer_unref(buf); /* Ignore buffer completely */
      } else {
	GstBuffer *tail = buffer_tail(filter, buf, filter->ref_time);
	if (buf) gst_buffer_unref(buf);
	buf = tail;
	filter->trim_state = AUDIO_TRIM_START_SILENCE;
      }
      break;
    case AUDIO_TRIM_START_SILENCE:
      {
	guint64 offset = find_not_silence(filter, buf);
	if (offset == GST_BUFFER_OFFSET_NONE) {
	  while(filter->buffered > filter->pre_silence) {
	    GstBuffer *old = filter->buffers->data;
	    filter->buffered -= GST_BUFFER_DURATION(old);
	    gst_buffer_unref(old);
	    filter->buffers =
	      g_list_delete_link(filter->buffers, filter->buffers);
	  }
	  save_buffer(filter, buf);
	  buf = NULL;
	} else {
	  GstBuffer *head;
	  GstBuffer *tail;
	  GstFlowReturn ret;
	  gint64 clip_start;
	  clip_start = offset - time_to_sample(filter, filter->pre_silence);
	  ret = send_buffers_after(filter, clip_start);
	  if (ret != GST_FLOW_OK) {
	    gst_buffer_unref(buf);
	    return ret;
	  }
	  head = buffer_slice(filter, buf, clip_start, offset);
	  if (head) {
	    ret = gst_pad_push(filter->srcpad, head);
	    if (ret != GST_FLOW_OK) {
	      gst_buffer_unref(buf);
	      return ret;
	    }
	  }
	  tail = buffer_tail(filter, buf, offset);
	  filter->sound_duration =
	    sample_to_time(filter, GST_BUFFER_OFFSET_END(buf) - clip_start);
	  filter->ref_time = clip_start;
	  gst_buffer_unref(buf);
	  buf = tail;
	  filter->trim_state = AUDIO_TRIM_NOT_SILENCE;
	  g_debug("Got sound");
	}
      }
      break;
    case AUDIO_TRIM_NOT_SILENCE:
      {
	GstFlowReturn ret;
	filter->sound_duration += GST_BUFFER_DURATION(buf);
	while(filter->buffered > filter->max_silence_duration) {
	  GstBuffer *old = filter->buffers->data;
	  filter->buffered -= GST_BUFFER_DURATION(old);
	  filter->buffers = g_list_delete_link(filter->buffers,filter->buffers);
	  ret = gst_pad_push(filter->srcpad, old);
	   if (ret != GST_FLOW_OK) {
	     gst_buffer_unref(buf);
	     return ret;
	   }
	}
	save_buffer(filter, buf);
	buf = 0;
      }
      break;
    default:
      gst_buffer_unref(buf);
      buf = NULL;
    }
  }

  return GST_FLOW_OK;
}
Esempio n. 26
0
static OSErr
data_proc (SGChannel c, Ptr p, long len, long *offset, long chRefCon,
    TimeValue time, short writeType, long refCon)
{
  GstOSXVideoSrc *self;
  gint fps_n, fps_d;
  GstClockTime duration, timestamp, latency;
  CodecFlags flags;
  ComponentResult err;
  PixMapHandle hPixMap;
  Rect portRect;
  int pix_rowBytes;
  void *pix_ptr;
  int pix_height;
  int pix_size;

  self = GST_OSX_VIDEO_SRC (refCon);

  if (self->buffer != NULL) {
    gst_buffer_unref (self->buffer);
    self->buffer = NULL;
  }

  err = DecompressSequenceFrameS (self->dec_seq, p, len, 0, &flags, NULL);
  if (err != noErr) {
    GST_ERROR_OBJECT (self, "DecompressSequenceFrameS returned %d", (int) err);
    return err;
  }

  hPixMap = GetGWorldPixMap (self->world);
  LockPixels (hPixMap);
  GetPortBounds (self->world, &portRect);
  pix_rowBytes = (int) GetPixRowBytes (hPixMap);
  pix_ptr = GetPixBaseAddr (hPixMap);
  pix_height = (portRect.bottom - portRect.top);
  pix_size = pix_rowBytes * pix_height;

  GST_DEBUG_OBJECT (self, "num=%5d, height=%d, rowBytes=%d, size=%d",
      self->seq_num, pix_height, pix_rowBytes, pix_size);

  fps_n = FRAMERATE;
  fps_d = 1;

  duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
  latency = duration;

  timestamp = gst_clock_get_time (GST_ELEMENT_CAST (self)->clock);
  timestamp -= gst_element_get_base_time (GST_ELEMENT_CAST (self));
  if (timestamp > latency)
    timestamp -= latency;
  else
    timestamp = 0;

  self->buffer = gst_buffer_new_and_alloc (pix_size);
  GST_BUFFER_OFFSET (self->buffer) = self->seq_num;
  GST_BUFFER_TIMESTAMP (self->buffer) = timestamp;
  memcpy (GST_BUFFER_DATA (self->buffer), pix_ptr, pix_size);

  self->seq_num++;

  UnlockPixels (hPixMap);

  return noErr;
}
Esempio n. 27
0
static gboolean
gst_sub_parse_sink_event (GstPad * pad, GstEvent * event)
{
  GstSubParse *self = GST_SUBPARSE (gst_pad_get_parent (pad));
  gboolean ret = FALSE;

  GST_DEBUG ("Handling %s event", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_EOS:{
      /* Make sure the last subrip chunk is pushed out even
       * if the file does not have an empty line at the end */
      if (self->parser_type == GST_SUB_PARSE_FORMAT_SUBRIP ||
          self->parser_type == GST_SUB_PARSE_FORMAT_TMPLAYER ||
          self->parser_type == GST_SUB_PARSE_FORMAT_MPL2) {
        GstBuffer *buf = gst_buffer_new_and_alloc (2 + 1);

        GST_DEBUG ("EOS. Pushing remaining text (if any)");
        GST_BUFFER_DATA (buf)[0] = '\n';
        GST_BUFFER_DATA (buf)[1] = '\n';
        GST_BUFFER_DATA (buf)[2] = '\0';        /* play it safe */
        GST_BUFFER_SIZE (buf) = 2;
        GST_BUFFER_OFFSET (buf) = self->offset;
        gst_sub_parse_chain (pad, buf);
      }
      ret = gst_pad_event_default (pad, event);
      break;
    }
    case GST_EVENT_NEWSEGMENT:
    {
      GstFormat format;
      gdouble rate;
      gint64 start, stop, time;
      gboolean update;

      gst_event_parse_new_segment (event, &update, &rate, &format, &start,
          &stop, &time);

      GST_DEBUG_OBJECT (self, "newsegment (%s)", gst_format_get_name (format));

      if (format == GST_FORMAT_TIME) {
        gst_segment_set_newsegment (&self->segment, update, rate, format,
            start, stop, time);
      } else {
        /* if not time format, we'll either start with a 0 timestamp anyway or
         * it's following a seek in which case we'll have saved the requested
         * seek segment and don't want to overwrite it (remember that on a seek
         * we always just seek back to the start in BYTES format and just throw
         * away all text that's before the requested position; if the subtitles
         * come from an upstream demuxer, it won't be able to handle our BYTES
         * seek request and instead send us a newsegment from the seek request
         * it received via its video pads instead, so all is fine then too) */
      }

      ret = TRUE;
      gst_event_unref (event);
      break;
    }
    case GST_EVENT_FLUSH_START:
    {
      self->flushing = TRUE;

      ret = gst_pad_event_default (pad, event);
      break;
    }
    case GST_EVENT_FLUSH_STOP:
    {
      self->flushing = FALSE;

      ret = gst_pad_event_default (pad, event);
      break;
    }
    default:
      ret = gst_pad_event_default (pad, event);
      break;
  }

  gst_object_unref (self);

  return ret;
}
static GstFlowReturn
gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
  GstByteReader reader;
  GstBuffer *input;
  GstMapInfo map_info;
  GstCaps *caps;
  guint available;
  GstFlowReturn res = GST_FLOW_OK;

  GstFlxDec *flxdec;
  FlxHeader *flxh;

  g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
  flxdec = (GstFlxDec *) parent;
  g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR);

  gst_adapter_push (flxdec->adapter, buf);
  available = gst_adapter_available (flxdec->adapter);
  input = gst_adapter_get_buffer (flxdec->adapter, available);
  if (!gst_buffer_map (input, &map_info, GST_MAP_READ)) {
    GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
        ("%s", "Failed to map buffer"), (NULL));
    goto error;
  }
  gst_byte_reader_init (&reader, map_info.data, map_info.size);

  if (flxdec->state == GST_FLXDEC_READ_HEADER) {
    if (available >= FlxHeaderSize) {
      GstByteReader header;
      GstCaps *templ;

      if (!gst_byte_reader_get_sub_reader (&reader, &header, FlxHeaderSize)) {
        GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
            ("%s", "Could not read header"), (NULL));
        goto unmap_input_error;
      }
      gst_adapter_flush (flxdec->adapter, FlxHeaderSize);
      available -= FlxHeaderSize;

      if (!_read_flx_header (flxdec, &header, &flxdec->hdr)) {
        GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
            ("%s", "Failed to parse header"), (NULL));
        goto unmap_input_error;
      }

      flxh = &flxdec->hdr;

      /* check header */
      if (flxh->type != FLX_MAGICHDR_FLI &&
          flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) {
        GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
            ("not a flx file (type %x)", flxh->type));
        goto unmap_input_error;
      }

      GST_INFO_OBJECT (flxdec, "size      :  %d", flxh->size);
      GST_INFO_OBJECT (flxdec, "frames    :  %d", flxh->frames);
      GST_INFO_OBJECT (flxdec, "width     :  %d", flxh->width);
      GST_INFO_OBJECT (flxdec, "height    :  %d", flxh->height);
      GST_INFO_OBJECT (flxdec, "depth     :  %d", flxh->depth);
      GST_INFO_OBJECT (flxdec, "speed     :  %d", flxh->speed);

      flxdec->next_time = 0;

      if (flxh->type == FLX_MAGICHDR_FLI) {
        flxdec->frame_time = JIFFIE * flxh->speed;
      } else if (flxh->speed == 0) {
        flxdec->frame_time = GST_SECOND / 70;
      } else {
        flxdec->frame_time = flxh->speed * GST_MSECOND;
      }

      flxdec->duration = flxh->frames * flxdec->frame_time;
      GST_LOG ("duration   :  %" GST_TIME_FORMAT,
          GST_TIME_ARGS (flxdec->duration));

      templ = gst_pad_get_pad_template_caps (flxdec->srcpad);
      caps = gst_caps_copy (templ);
      gst_caps_unref (templ);
      gst_caps_set_simple (caps,
          "width", G_TYPE_INT, flxh->width,
          "height", G_TYPE_INT, flxh->height,
          "framerate", GST_TYPE_FRACTION, (gint) GST_MSECOND,
          (gint) flxdec->frame_time / 1000, NULL);

      gst_pad_set_caps (flxdec->srcpad, caps);
      gst_caps_unref (caps);

      if (flxdec->need_segment) {
        gst_pad_push_event (flxdec->srcpad,
            gst_event_new_segment (&flxdec->segment));
        flxdec->need_segment = FALSE;
      }

      /* zero means 8 */
      if (flxh->depth == 0)
        flxh->depth = 8;

      if (flxh->depth != 8) {
        GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE,
            ("%s", "Don't know how to decode non 8 bit depth streams"), (NULL));
        goto unmap_input_error;
      }

      flxdec->converter =
          flx_colorspace_converter_new (flxh->width, flxh->height);

      if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
        GST_INFO_OBJECT (flxdec, "(FLC) aspect_dx :  %d", flxh->aspect_dx);
        GST_INFO_OBJECT (flxdec, "(FLC) aspect_dy :  %d", flxh->aspect_dy);
        GST_INFO_OBJECT (flxdec, "(FLC) oframe1   :  0x%08x", flxh->oframe1);
        GST_INFO_OBJECT (flxdec, "(FLC) oframe2   :  0x%08x", flxh->oframe2);
      }

      flxdec->size = ((guint) flxh->width * (guint) flxh->height);
      if (flxdec->size >= G_MAXSIZE / 4) {
        GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
            ("%s", "Cannot allocate required memory"), (NULL));
        goto unmap_input_error;
      }

      /* create delta and output frame */
      flxdec->frame_data = g_malloc0 (flxdec->size);
      flxdec->delta_data = g_malloc0 (flxdec->size);

      flxdec->state = GST_FLXDEC_PLAYING;
    }
  } else if (flxdec->state == GST_FLXDEC_PLAYING) {
    GstBuffer *out;

    /* while we have enough data in the adapter */
    while (available >= FlxFrameChunkSize && res == GST_FLOW_OK) {
      guint32 size;
      guint16 type;

      if (!gst_byte_reader_get_uint32_le (&reader, &size))
        goto parse_error;
      if (available < size)
        goto need_more_data;

      available -= size;
      gst_adapter_flush (flxdec->adapter, size);

      if (!gst_byte_reader_get_uint16_le (&reader, &type))
        goto parse_error;

      switch (type) {
        case FLX_FRAME_TYPE:{
          GstByteReader chunks;
          GstByteWriter writer;
          guint16 n_chunks;
          GstMapInfo map;

          GST_LOG_OBJECT (flxdec, "Have frame type 0x%02x of size %d", type,
              size);

          if (!gst_byte_reader_get_sub_reader (&reader, &chunks,
                  size - FlxFrameChunkSize))
            goto parse_error;

          if (!gst_byte_reader_get_uint16_le (&chunks, &n_chunks))
            goto parse_error;
          GST_LOG_OBJECT (flxdec, "Have %d chunks", n_chunks);

          if (n_chunks == 0)
            break;
          if (!gst_byte_reader_skip (&chunks, 8))       /* reserved */
            goto parse_error;

          gst_byte_writer_init_with_data (&writer, flxdec->frame_data,
              flxdec->size, TRUE);

          /* decode chunks */
          if (!flx_decode_chunks (flxdec, n_chunks, &chunks, &writer)) {
            GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
                ("%s", "Could not decode chunk"), NULL);
            goto unmap_input_error;
          }
          gst_byte_writer_reset (&writer);

          /* save copy of the current frame for possible delta. */
          memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);

          out = gst_buffer_new_and_alloc (flxdec->size * 4);
          if (!gst_buffer_map (out, &map, GST_MAP_WRITE)) {
            GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
                ("%s", "Could not map output buffer"), NULL);
            gst_buffer_unref (out);
            goto unmap_input_error;
          }

          /* convert current frame. */
          flx_colorspace_convert (flxdec->converter, flxdec->frame_data,
              map.data);
          gst_buffer_unmap (out, &map);

          GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;
          flxdec->next_time += flxdec->frame_time;

          res = gst_pad_push (flxdec->srcpad, out);
          break;
        }
        default:
          GST_DEBUG_OBJECT (flxdec, "Unknown frame type 0x%02x, skipping %d",
              type, size);
          if (!gst_byte_reader_skip (&reader, size - FlxFrameChunkSize))
            goto parse_error;
          break;
      }
    }
  }

need_more_data:
  gst_buffer_unmap (input, &map_info);
  gst_buffer_unref (input);
  return res;

  /* ERRORS */
parse_error:
  GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
      ("%s", "Failed to parse stream"), (NULL));
unmap_input_error:
  gst_buffer_unmap (input, &map_info);
error:
  gst_buffer_unref (input);
  return GST_FLOW_ERROR;
}
Esempio n. 29
0
/* encodes frame according to info in xframe;
   - buf is input buffer, can be NULL if dummy
   - buf is disposed of prior to exit
   - resulting buffer is returned, NULL if no encoder output or error
*/
static inline GstBuffer *
gst_xvidenc_encode (GstXvidEnc * xvidenc, GstBuffer * buf,
    xvid_enc_frame_t xframe)
{
  GstBuffer *outbuf;
  gint ret;

  /* compressed frame should fit in the rough size of an uncompressed one */
  outbuf = gst_buffer_new_and_alloc (gst_xvid_image_get_size (xvidenc->csp,
          xvidenc->width, xvidenc->height));

  xframe.bitstream = (void *) GST_BUFFER_DATA (outbuf);
  xframe.length = GST_BUFFER_SIZE (outbuf);

  /* now provide input image data where-abouts, if needed */
  if (buf)
    gst_xvid_image_fill (&xframe.input, GST_BUFFER_DATA (buf), xvidenc->csp,
        xvidenc->width, xvidenc->height);

  GST_DEBUG_OBJECT (xvidenc, "encoding frame into buffer of size %d",
      GST_BUFFER_SIZE (outbuf));
  ret = xvid_encore (xvidenc->handle, XVID_ENC_ENCODE, &xframe, NULL);

  if (ret < 0) {
    /* things can be nasty if we are trying to flush, so don't signal error then */
    if (buf) {
      GST_ELEMENT_WARNING (xvidenc, LIBRARY, ENCODE, (NULL),
          ("Error encoding xvid frame: %s (%d)", gst_xvid_error (ret), ret));
      gst_buffer_unref (buf);
    }
    gst_buffer_unref (outbuf);
    return NULL;
  } else if (ret > 0) {         /* make sub-buffer */
    GstBuffer *sub;

    GST_DEBUG_OBJECT (xvidenc, "xvid produced output of size %d", ret);
    sub = gst_buffer_create_sub (outbuf, 0, ret);

    /* parent no longer needed, will go away with child buffer */
    gst_buffer_unref (outbuf);
    outbuf = sub;
  } else {                      /* encoder did not yet produce something */
    GST_DEBUG_OBJECT (xvidenc, "xvid produced no output");
    gst_buffer_unref (outbuf);
    g_queue_push_tail (xvidenc->delay, buf);
    return NULL;
  }

  /* finish decoration and return */
  if (!(xframe.out_flags & XVID_KEYFRAME))
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (xvidenc->srcpad));

  /* now we need the right buf to take timestamps from;
     note that timestamps from a display order input buffer can end up with
     another encode order output buffer, but other than this permutation,
     the overall time progress is tracked,
     and keyframes should have the correct stamp */
  if (!g_queue_is_empty (xvidenc->delay)) {
    if (buf)
      g_queue_push_tail (xvidenc->delay, buf);
    buf = g_queue_pop_head (xvidenc->delay);
  }
  if (buf) {
    GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
    GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
    gst_buffer_unref (buf);
  }

  return outbuf;
}
Esempio n. 30
0
static GstBuffer *
gst_rtp_amr_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
{
  GstRtpAMRDepay *rtpamrdepay;
  GstBuffer *outbuf = NULL;
  gint payload_len;
  gint *frame_size;

  rtpamrdepay = GST_RTP_AMR_DEPAY (depayload);

  /* setup frame size pointer */
  if (rtpamrdepay->mode == GST_RTP_AMR_DP_MODE_NB)
    frame_size = nb_frame_size;
  else
    frame_size = wb_frame_size;

  /* when we get here, 1 channel, 8000/16000 Hz, octet aligned, no CRC, 
   * no robust sorting, no interleaving data is to be depayloaded */
  {
    guint8 *payload, *p, *dp;
    guint8 CMR;
    gint i, num_packets, num_nonempty_packets;
    gint amr_len;
    gint ILL, ILP;
    gboolean marker;

    marker = gst_rtp_buffer_get_marker (buf);
    payload_len = gst_rtp_buffer_get_payload_len (buf);

    /* need at least 2 bytes for the header */
    if (payload_len < 2)
      goto too_small;

    payload = gst_rtp_buffer_get_payload (buf);

    /* depay CMR. The CMR is used by the sender to request
     * a new encoding mode.
     *
     *  0 1 2 3 4 5 6 7 
     * +-+-+-+-+-+-+-+-+
     * | CMR   |R|R|R|R|
     * +-+-+-+-+-+-+-+-+
     */
    CMR = (payload[0] & 0xf0) >> 4;

    /* strip CMR header now, pack FT and the data for the decoder */
    payload_len -= 1;
    payload += 1;

    GST_DEBUG_OBJECT (rtpamrdepay, "payload len %d", payload_len);

    if (rtpamrdepay->interleaving) {
      ILL = (payload[0] & 0xf0) >> 4;
      ILP = (payload[0] & 0x0f);

      payload_len -= 1;
      payload += 1;

      if (ILP > ILL)
        goto wrong_interleaving;
    }

    /* 
     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 
     * +-+-+-+-+-+-+-+-+..
     * |F|  FT   |Q|P|P| more FT..
     * +-+-+-+-+-+-+-+-+..
     */
    /* count number of packets by counting the FTs. Also
     * count number of amr data bytes and number of non-empty
     * packets (this is also the number of CRCs if present). */
    amr_len = 0;
    num_nonempty_packets = 0;
    num_packets = 0;
    for (i = 0; i < payload_len; i++) {
      gint fr_size;
      guint8 FT;

      FT = (payload[i] & 0x78) >> 3;

      fr_size = frame_size[FT];
      GST_DEBUG_OBJECT (rtpamrdepay, "frame size %d", fr_size);
      if (fr_size == -1)
        goto wrong_framesize;

      if (fr_size > 0) {
        amr_len += fr_size;
        num_nonempty_packets++;
      }
      num_packets++;

      if ((payload[i] & 0x80) == 0)
        break;
    }

    if (rtpamrdepay->crc) {
      /* data len + CRC len + header bytes should be smaller than payload_len */
      if (num_packets + num_nonempty_packets + amr_len > payload_len)
        goto wrong_length_1;
    } else {
      /* data len + header bytes should be smaller than payload_len */
      if (num_packets + amr_len > payload_len)
        goto wrong_length_2;
    }

    outbuf = gst_buffer_new_and_alloc (payload_len);

    /* point to destination */
    p = GST_BUFFER_DATA (outbuf);
    /* point to first data packet */
    dp = payload + num_packets;
    if (rtpamrdepay->crc) {
      /* skip CRC if present */
      dp += num_nonempty_packets;
    }

    for (i = 0; i < num_packets; i++) {
      gint fr_size;

      /* copy FT, clear F bit */
      *p++ = payload[i] & 0x7f;

      fr_size = frame_size[(payload[i] & 0x78) >> 3];
      if (fr_size > 0) {
        /* copy data packet, FIXME, calc CRC here. */
        memcpy (p, dp, fr_size);

        p += fr_size;
        dp += fr_size;
      }
    }
    /* we can set the duration because each packet is 20 milliseconds */
    GST_BUFFER_DURATION (outbuf) = num_packets * 20 * GST_MSECOND;

    if (marker) {
      /* marker bit marks a discont buffer after a talkspurt. */
      GST_DEBUG_OBJECT (depayload, "marker bit was set");
      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
      marker = FALSE;
    }

    GST_DEBUG_OBJECT (depayload, "pushing buffer of size %d",
        GST_BUFFER_SIZE (outbuf));
  }