Esempio n. 1
0
static GstBuffer *
gst_wavenc_create_header_buf (GstWavEnc * wavenc, guint audio_data_size)
{
  struct wave_header wave;
  GstBuffer *buf;
  GstMapInfo map;
  guint8 *header;

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

  wave.common.wChannels = wavenc->channels;
  wave.common.wBitsPerSample = wavenc->width;
  wave.common.dwSamplesPerSec = wavenc->rate;

  /* Fill out our wav-header with some information */
  memcpy (wave.riff.id, "RIFF", 4);
  wave.riff.len = audio_data_size + WAV_HEADER_LEN - 8;
  memcpy (wave.riff.wav_id, "WAVE", 4);

  memcpy (wave.format.id, "fmt ", 4);
  wave.format.len = 16;

  wave.common.wFormatTag = wavenc->format;
  wave.common.wBlockAlign = (wavenc->width / 8) * wave.common.wChannels;
  wave.common.dwAvgBytesPerSec =
      wave.common.wBlockAlign * wave.common.dwSamplesPerSec;

  memcpy (wave.data.id, "data", 4);
  wave.data.len = audio_data_size;

  memcpy (header, (char *) wave.riff.id, 4);
  GST_WRITE_UINT32_LE (header + 4, wave.riff.len);
  memcpy (header + 8, (char *) wave.riff.wav_id, 4);
  memcpy (header + 12, (char *) wave.format.id, 4);
  GST_WRITE_UINT32_LE (header + 16, wave.format.len);
  GST_WRITE_UINT16_LE (header + 20, wave.common.wFormatTag);
  GST_WRITE_UINT16_LE (header + 22, wave.common.wChannels);
  GST_WRITE_UINT32_LE (header + 24, wave.common.dwSamplesPerSec);
  GST_WRITE_UINT32_LE (header + 28, wave.common.dwAvgBytesPerSec);
  GST_WRITE_UINT16_LE (header + 32, wave.common.wBlockAlign);
  GST_WRITE_UINT16_LE (header + 34, wave.common.wBitsPerSample);
  memcpy (header + 36, (char *) wave.data.id, 4);
  GST_WRITE_UINT32_LE (header + 40, wave.data.len);

  gst_buffer_unmap (buf, &map);

  return buf;
}
Esempio n. 2
0
static void
gst_mim_enc_create_tcp_header (GstMimEnc * mimenc, guint8 * p,
    guint32 payload_size, GstClockTime ts, gboolean keyframe, gboolean paused)
{
  p[0] = 24;
  p[1] = paused ? 1 : 0;
  GST_WRITE_UINT16_LE (p + 2, mimenc->width);
  GST_WRITE_UINT16_LE (p + 4, mimenc->height);
  GST_WRITE_UINT16_LE (p + 6, keyframe ? 1 : 0);
  GST_WRITE_UINT32_LE (p + 8, payload_size);
  GST_WRITE_UINT32_LE (p + 12, paused ? 0 :
      GST_MAKE_FOURCC ('M', 'L', '2', '0'));
  GST_WRITE_UINT32_LE (p + 16, 0);
  GST_WRITE_UINT32_LE (p + 20, ts / GST_MSECOND);
}
Esempio n. 3
0
static GstFlowReturn
mxf_d10_sound_handle_essence_element (const MXFUL * key, GstBuffer * buffer,
    GstCaps * caps,
    MXFMetadataTimelineTrack * track,
    MXFMetadataSourceClip * component, gpointer mapping_data,
    GstBuffer ** outbuf)
{
  guint i, j, nsamples;
  const guint8 *indata;
  guint8 *outdata;
  MXFD10AudioMappingData *data = mapping_data;

  g_return_val_if_fail (data != NULL, GST_FLOW_ERROR);
  g_return_val_if_fail (data->channels != 0
      && data->width != 0, GST_FLOW_ERROR);

  /* SMPTE 386M 5.3.1 */
  if (key->u[12] != 0x06 || key->u[13] != 0x01 || key->u[14] != 0x10) {
    GST_ERROR ("Invalid D10 sound essence element");
    return GST_FLOW_ERROR;
  }

  /* Now transform raw AES3 into raw audio, see SMPTE 331M */
  if ((GST_BUFFER_SIZE (buffer) - 4) % 32 != 0) {
    GST_ERROR ("Invalid D10 sound essence buffer size");
    return GST_FLOW_ERROR;
  }

  nsamples = ((GST_BUFFER_SIZE (buffer) - 4) / 4) / 8;

  *outbuf = gst_buffer_new_and_alloc (nsamples * data->width * data->channels);
  gst_buffer_copy_metadata (*outbuf, buffer,
      GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
      GST_BUFFER_COPY_CAPS);

  indata = GST_BUFFER_DATA (buffer);
  outdata = GST_BUFFER_DATA (*outbuf);

  /* Skip 32 bit header */
  indata += 4;

  for (i = 0; i < nsamples; i++) {
    for (j = 0; j < data->channels; j++) {
      guint32 in = GST_READ_UINT32_LE (indata);

      /* Remove first 4 and last 4 bits as they only
       * contain status data. Shift the 24 bit samples
       * to the correct width afterwards. */
      if (data->width == 2) {
        in = (in >> 12) & 0xffff;
        GST_WRITE_UINT16_LE (outdata, in);
      } else if (data->width == 3) {
        in = (in >> 4) & 0xffffff;
        GST_WRITE_UINT24_LE (outdata, in);
      }
Esempio n. 4
0
static void fill_bmp_header(guint8 *image_data, guint image_width, guint image_height)
{
    guint dib_image_row_size = ((DIB_BITS_PER_PIXEL * image_width + 31) / 32) * 4;
    guint dib_image_size = dib_image_row_size * image_height;
    guint8 *data = image_data;

    *data = 'B';
    data++;
    *data = 'M';
    data++;
    GST_WRITE_UINT32_LE(data, (BMP_HEADER_SIZE + dib_image_size));
    data += 4;
    GST_WRITE_UINT16_LE(data, BMP_RESERVED);
    data += 2;
    GST_WRITE_UINT16_LE(data, BMP_RESERVED);
    data += 2;
    GST_WRITE_UINT32_LE(data, BMP_HEADER_SIZE);
    data += 4;
    GST_WRITE_UINT32_LE(data, DIB_HEADER_SIZE);
    data += 4;
    GST_WRITE_UINT32_LE(data, image_width);
    data += 4;
    GST_WRITE_UINT32_LE(data, image_height);
    data += 4;
    GST_WRITE_UINT16_LE(data, DIB_COLOR_PLANES);
    data += 2;
    GST_WRITE_UINT16_LE(data, DIB_BITS_PER_PIXEL);
    data += 2;
    GST_WRITE_UINT32_LE(data, DIB_COMPRESSION);
    data += 4;
    GST_WRITE_UINT32_LE(data, dib_image_size);
    data += 4;
    GST_WRITE_UINT32_LE(data, DIB_HORIZONTAL_RESOLUTION);
    data += 4;
    GST_WRITE_UINT32_LE(data, DIB_VERTICAL_RESOLUTION);
    data += 4;
    GST_WRITE_UINT32_LE(data, DIB_COLORS_IN_PALETTE);
    data += 4;
    GST_WRITE_UINT32_LE(data, DIB_IMPORTANT_COLORS);
    data += 4;
}
Esempio n. 5
0
/* create a CMML ident header buffer
 */
static GstFlowReturn
gst_cmml_enc_new_ident_header (GstCmmlEnc * enc, GstBuffer ** buffer)
{
  guint8 ident_header[CMML_IDENT_HEADER_SIZE];
  guint8 *wptr = ident_header;

  memcpy (wptr, "CMML\0\0\0\0", 8);
  wptr += 8;
  GST_WRITE_UINT16_LE (wptr, enc->major);
  wptr += 2;
  GST_WRITE_UINT16_LE (wptr, enc->minor);
  wptr += 2;
  GST_WRITE_UINT64_LE (wptr, enc->granulerate_n);
  wptr += 8;
  GST_WRITE_UINT64_LE (wptr, enc->granulerate_d);
  wptr += 8;
  *wptr = enc->granuleshift;

  return gst_cmml_enc_new_buffer (enc,
      (guchar *) & ident_header, CMML_IDENT_HEADER_SIZE, buffer);
}
Esempio n. 6
0
static GstBuffer *
gst_mimenc_create_tcp_header (GstMimEnc * mimenc, guint32 payload_size,
    GstClockTime timestamp, gboolean keyframe, gboolean paused)
{
  // 24 bytes
  GstBuffer *buf_header = gst_buffer_new_and_alloc (24);
  guchar *p = (guchar *) GST_BUFFER_DATA (buf_header);

  GST_BUFFER_TIMESTAMP (buf_header) = timestamp;

  p[0] = 24;
  p[1] = paused ? 1 : 0;
  GST_WRITE_UINT16_LE (p + 2, mimenc->width);
  GST_WRITE_UINT16_LE (p + 4, mimenc->height);
  GST_WRITE_UINT16_LE (p + 6, keyframe ? 1 : 0);
  GST_WRITE_UINT32_LE (p + 8, payload_size);
  GST_WRITE_UINT32_LE (p + 12, paused ? 0 :
      GST_MAKE_FOURCC ('M', 'L', '2', '0'));
  GST_WRITE_UINT32_LE (p + 16, 0);
  GST_WRITE_UINT32_LE (p + 20, timestamp / GST_MSECOND);

  return buf_header;
}
Esempio n. 7
0
static void
gst_exif_writer_write_short_tag (GstExifWriter * writer, guint16 tag,
    guint16 value)
{
  guint32 offset = 0;

  if (writer->byte_order == G_LITTLE_ENDIAN) {
    GST_WRITE_UINT16_LE ((guint8 *) & offset, value);
  } else {
    GST_WRITE_UINT16_BE ((guint8 *) & offset, value);
  }

  gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_SHORT,
      1, offset, TRUE);
}
Esempio n. 8
0
/* Correctly format samples with width!=depth for the wav format, i.e.
 * have the data in the highest depth bits and all others zero */
static void
gst_wavenc_format_samples (GstBuffer * buf, guint width, guint depth)
{
  guint8 *data = GST_BUFFER_DATA (buf);
  guint nsamples = (GST_BUFFER_SIZE (buf) * 8) / width;
  guint32 tmp;

  for (; nsamples; nsamples--) {
    switch (width) {

      case 8:
        tmp = *data;
        *data = *data << (width - depth);
        data += 1;
        break;
      case 16:
        tmp = GST_READ_UINT16_LE (data);
        tmp = tmp << (width - depth);
        GST_WRITE_UINT16_LE (data, tmp);
        data += 2;
        break;
      case 24:
        tmp = READ24_FROM_LE (data);
        tmp = tmp << (width - depth);
        WRITE24_TO_LE (data, tmp);
        data += 3;
        break;
      case 32:
        tmp = GST_READ_UINT32_LE (data);
        tmp = tmp << (width - depth);
        GST_WRITE_UINT32_LE (data, tmp);
        data += 4;
        break;
    }
  }
}
Esempio n. 9
0
static gboolean
gst_real_video_dec_setcaps (GstPad * pad, GstCaps * caps)
{
  GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad));
  GstStructure *s = gst_caps_get_structure (caps, 0);
  gint version, res, width, height, format, subformat;
  gint framerate_num, framerate_denom;
  gchar data[36];
  gboolean bres;
  const GValue *v;

  if (!gst_structure_get_int (s, "rmversion", &version) ||
      !gst_structure_get_int (s, "width", (gint *) & width) ||
      !gst_structure_get_int (s, "height", (gint *) & height) ||
      !gst_structure_get_int (s, "format", &format) ||
      !gst_structure_get_int (s, "subformat", &subformat) ||
      !gst_structure_get_fraction (s, "framerate", &framerate_num,
          &framerate_denom))
    goto missing_keys;

  GST_LOG_OBJECT (dec, "Setting version to %d", version);

  close_library (dec, &dec->lib);

  if (!open_library (dec, version, &dec->lib))
    goto open_failed;

  /* Initialize REAL driver. */
  GST_WRITE_UINT16_LE (data + 0, 11);
  GST_WRITE_UINT16_LE (data + 2, width);
  GST_WRITE_UINT16_LE (data + 4, height);
  GST_WRITE_UINT16_LE (data + 6, 0);
  GST_WRITE_UINT32_LE (data + 8, 0);
  GST_WRITE_UINT32_LE (data + 12, subformat);
  GST_WRITE_UINT32_LE (data + 16, 1);
  GST_WRITE_UINT32_LE (data + 20, format);

  if ((res = dec->lib.Init (&data, &dec->lib.context)))
    goto could_not_initialize;

  if ((v = gst_structure_get_value (s, "codec_data"))) {
    GstBuffer *buf;
    guint32 *msgdata;
    guint i;
    guint8 *bufdata;
    guint bufsize;
    struct
    {
      guint32 type;
      guint32 msg;
      gpointer data;
      guint32 extra[6];
    } msg;

    buf = g_value_peek_pointer (v);

    bufdata = GST_BUFFER_DATA (buf);
    bufsize = GST_BUFFER_SIZE (buf);

    /* skip format and subformat */
    bufdata += 8;
    bufsize -= 8;

    GST_LOG_OBJECT (dec, "Creating custom message of length %d", bufsize);

    msgdata = g_new0 (guint32, bufsize + 2);
    if (!msgdata)
      goto could_not_allocate;

    msg.type = 0x24;
    msg.msg = 1 + ((subformat >> 16) & 7);
    msg.data = msgdata;
    for (i = 0; i < 6; i++)
      msg.extra[i] = 0;
    msgdata[0] = width;
    msgdata[1] = height;
    for (i = 0; i < bufsize; i++)
      msgdata[i + 2] = 4 * (guint32) bufdata[i];

    res = dec->lib.Message (&msg, dec->lib.context);

    g_free (msgdata);
    if (res)
      goto could_not_send_message;
  }
Esempio n. 10
0
static GstFlowReturn
gst_opus_parse_parse_frame (GstBaseParse * base, GstBaseParseFrame * frame)
{
  guint64 duration;
  GstOpusParse *parse;
  gboolean is_idheader, is_commentheader;
  GstMapInfo map;
  GstAudioClippingMeta *cmeta =
      gst_buffer_get_audio_clipping_meta (frame->buffer);

  parse = GST_OPUS_PARSE (base);

  g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);

  is_idheader = gst_opus_header_is_id_header (frame->buffer);
  is_commentheader = gst_opus_header_is_comment_header (frame->buffer);

  if (!parse->got_headers || !parse->header_sent) {
    GstCaps *caps;

    /* Opus streams can decode to 1 or 2 channels, so use the header
       value if we have one, or 2 otherwise */
    if (is_idheader) {
      gst_buffer_replace (&parse->id_header, frame->buffer);
      GST_DEBUG_OBJECT (parse, "Found ID header, keeping");
      return GST_BASE_PARSE_FLOW_DROPPED;
    } else if (is_commentheader) {
      gst_buffer_replace (&parse->comment_header, frame->buffer);
      GST_DEBUG_OBJECT (parse, "Found comment header, keeping");
      return GST_BASE_PARSE_FLOW_DROPPED;
    }

    parse->got_headers = TRUE;

    if (cmeta && cmeta->start) {
      parse->pre_skip += cmeta->start;

      gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
      duration = packet_duration_opus (map.data, map.size);
      gst_buffer_unmap (frame->buffer, &map);

      /* Queue frame for later once we know all initial padding */
      if (duration == cmeta->start) {
        frame->flags |= GST_BASE_PARSE_FRAME_FLAG_QUEUE;
      }
    }

    if (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_QUEUE)) {
      if (FALSE && parse->id_header && parse->comment_header) {
        guint16 pre_skip;

        gst_buffer_map (parse->id_header, &map, GST_MAP_READWRITE);
        pre_skip = GST_READ_UINT16_LE (map.data + 10);
        if (pre_skip != parse->pre_skip) {
          GST_DEBUG_OBJECT (parse,
              "Fixing up pre-skip %u -> %" G_GUINT64_FORMAT, pre_skip,
              parse->pre_skip);
          GST_WRITE_UINT16_LE (map.data + 10, parse->pre_skip);
        }
        gst_buffer_unmap (parse->id_header, &map);

        caps =
            gst_codec_utils_opus_create_caps_from_header (parse->id_header,
            parse->comment_header);
      } else {
        GstCaps *sink_caps;
        guint32 sample_rate = 48000;
        guint8 n_channels, n_streams, n_stereo_streams, channel_mapping_family;
        guint8 channel_mapping[256];
        GstBuffer *id_header;

        sink_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (parse));
        if (!sink_caps
            || !gst_codec_utils_opus_parse_caps (sink_caps, &sample_rate,
                &n_channels, &channel_mapping_family, &n_streams,
                &n_stereo_streams, channel_mapping)) {
          GST_INFO_OBJECT (parse,
              "No headers and no caps, blindly setting up canonical stereo");
          n_channels = 2;
          n_streams = 1;
          n_stereo_streams = 1;
          channel_mapping_family = 0;
          channel_mapping[0] = 0;
          channel_mapping[1] = 1;
        }
        if (sink_caps)
          gst_caps_unref (sink_caps);

        id_header =
            gst_codec_utils_opus_create_header (sample_rate, n_channels,
            channel_mapping_family, n_streams, n_stereo_streams,
            channel_mapping, parse->pre_skip, 0);
        caps = gst_codec_utils_opus_create_caps_from_header (id_header, NULL);
        gst_buffer_unref (id_header);
      }

      gst_buffer_replace (&parse->id_header, NULL);
      gst_buffer_replace (&parse->comment_header, NULL);

      gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
      gst_caps_unref (caps);
      parse->header_sent = TRUE;
    }
  }

  GST_BUFFER_TIMESTAMP (frame->buffer) = parse->next_ts;

  gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
  duration = packet_duration_opus (map.data, map.size);
  gst_buffer_unmap (frame->buffer, &map);
  parse->next_ts += duration;

  GST_BUFFER_DURATION (frame->buffer) = duration;
  GST_BUFFER_OFFSET_END (frame->buffer) =
      gst_util_uint64_scale (parse->next_ts, 48000, GST_SECOND);
  GST_BUFFER_OFFSET (frame->buffer) = parse->next_ts;

  return GST_FLOW_OK;
}
Esempio n. 11
0
gint
mve_compress_audio (guint8 * dest, const guint8 * src, guint16 len,
    guint8 channels)
{
  gint16 prev[2], s;
  gint delta, real_res;
  gint cur_chan;
  guint8 v;

  for (cur_chan = 0; cur_chan < channels; ++cur_chan) {
    prev[cur_chan] = GST_READ_UINT16_LE (src);
    GST_WRITE_UINT16_LE (dest, prev[cur_chan]);
    src += 2;
    dest += 2;
    len -= 2;
  }

  cur_chan = 0;
  while (len > 0) {
    s = GST_READ_UINT16_LE (src);
    src += 2;

    delta = s - prev[cur_chan];

    if (delta >= 0)

      v = mve_enc_delta (delta);

    else

      v = 256 - mve_enc_delta (-delta);


    real_res = dec_table[v] + prev[cur_chan];

    if (real_res < -32768 || real_res > 32767) {

      /* correct overflow */
      /* GST_DEBUG ("co:%d + %d = %d -> new v:%d, dec_table:%d will be %d",
         prev[cur_chan], dec_table[v], real_res,
         v, dec_table[v], prev[cur_chan]+dec_table[v]); */
      if (s > 0) {

        if (real_res > 32767)
          --v;

      } else {

        if (real_res < -32768)
          ++v;

      }

      real_res = dec_table[v] + prev[cur_chan];

    }

    if (G_UNLIKELY (abs (real_res - s) > 32767)) {
      GST_ERROR ("sign loss left unfixed in audio stream, deviation:%d",
          real_res - s);
      return -1;
    }


    *dest++ = v;

    --len;
    /* use previous output instead of input. That way output will not go too far from input. */
    prev[cur_chan] += dec_table[v];
    cur_chan = channels - 1 - cur_chan;

  }

  return 0;
}
Esempio n. 12
0
static GstFlowReturn
gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
{
  GstBaseRTPPayload *rtppay;
  GstAsfPacketInfo *packetinfo;
  guint8 flags;
  guint8 *data;
  guint32 packet_util_size;
  guint32 packet_offset;
  guint32 size_left;
  GstFlowReturn ret = GST_FLOW_OK;

  rtppay = GST_BASE_RTP_PAYLOAD (rtpasfpay);
  packetinfo = &rtpasfpay->packetinfo;

  if (!gst_asf_parse_packet (buffer, packetinfo, TRUE,
          rtpasfpay->asfinfo.packet_size)) {
    GST_ERROR_OBJECT (rtpasfpay, "Error while parsing asf packet");
    gst_buffer_unref (buffer);
    return GST_FLOW_ERROR;
  }

  if (packetinfo->packet_size == 0)
    packetinfo->packet_size = rtpasfpay->asfinfo.packet_size;

  GST_LOG_OBJECT (rtpasfpay, "Packet size: %" G_GUINT32_FORMAT
      ", padding: %" G_GUINT32_FORMAT, packetinfo->packet_size,
      packetinfo->padding);

  /* update padding field to 0 */
  if (packetinfo->padding > 0) {
    GstAsfPacketInfo info;
    /* find padding field offset */
    guint offset = packetinfo->err_cor_len + 2 +
        gst_asf_get_var_size_field_len (packetinfo->packet_field_type) +
        gst_asf_get_var_size_field_len (packetinfo->seq_field_type);
    buffer = gst_buffer_make_writable (buffer);
    switch (packetinfo->padd_field_type) {
      case ASF_FIELD_TYPE_DWORD:
        GST_WRITE_UINT32_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0);
        break;
      case ASF_FIELD_TYPE_WORD:
        GST_WRITE_UINT16_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0);
        break;
      case ASF_FIELD_TYPE_BYTE:
        GST_BUFFER_DATA (buffer)[offset] = 0;
        break;
      case ASF_FIELD_TYPE_NONE:
      default:
        break;
    }
    gst_asf_parse_packet (buffer, &info, FALSE, 0);
  }

  if (packetinfo->padding != 0)
    packet_util_size = rtpasfpay->asfinfo.packet_size - packetinfo->padding;
  else
    packet_util_size = packetinfo->packet_size;
  packet_offset = 0;
  while (packet_util_size > 0) {
    /* Even if we don't fill completely an output buffer we
     * push it when we add an fragment. Because it seems that
     * it is not possible to determine where a asf packet
     * fragment ends inside a rtp packet payload.
     * This flag tells us to push the packet.
     */
    gboolean force_push = FALSE;

    /* we have no output buffer pending, create one */
    if (rtpasfpay->current == NULL) {
      GST_LOG_OBJECT (rtpasfpay, "Creating new output buffer");
      rtpasfpay->current =
          gst_rtp_buffer_new_allocate_len (GST_BASE_RTP_PAYLOAD_MTU (rtpasfpay),
          0, 0);
      rtpasfpay->cur_off = gst_rtp_buffer_get_header_len (rtpasfpay->current);
      rtpasfpay->has_ts = FALSE;
      rtpasfpay->marker = FALSE;
    }
    data = GST_BUFFER_DATA (rtpasfpay->current) + rtpasfpay->cur_off;
    size_left = GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off;

    GST_DEBUG_OBJECT (rtpasfpay, "Input buffer bytes consumed: %"
        G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, packet_offset,
        GST_BUFFER_SIZE (buffer));

    GST_DEBUG_OBJECT (rtpasfpay, "Output rtpbuffer status");
    GST_DEBUG_OBJECT (rtpasfpay, "Current offset: %" G_GUINT32_FORMAT,
        rtpasfpay->cur_off);
    GST_DEBUG_OBJECT (rtpasfpay, "Size left: %" G_GUINT32_FORMAT, size_left);
    GST_DEBUG_OBJECT (rtpasfpay, "Has ts: %s",
        rtpasfpay->has_ts ? "yes" : "no");
    if (rtpasfpay->has_ts) {
      GST_DEBUG_OBJECT (rtpasfpay, "Ts: %" G_GUINT32_FORMAT, rtpasfpay->ts);
    }

    flags = 0;
    if (packetinfo->has_keyframe) {
      flags = flags | 0x80;
    }
    flags = flags | 0x20;       /* Relative timestamp is present */

    if (!rtpasfpay->has_ts) {
      /* this is the first asf packet, its send time is the 
       * rtp packet timestamp */
      rtpasfpay->has_ts = TRUE;
      rtpasfpay->ts = packetinfo->send_time;
    }

    if (GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off >=
        packet_util_size + 8) {
      /* enough space for the rest of the packet */
      if (packet_offset == 0) {
        flags = flags | 0x40;
        GST_WRITE_UINT24_BE (data + 1, packet_util_size);
      } else {
        GST_WRITE_UINT24_BE (data + 1, packet_offset);
        force_push = TRUE;
      }
      data[0] = flags;
      GST_WRITE_UINT32_BE (data + 4,
          (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
      memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset,
          packet_util_size);

      /* updating status variables */
      rtpasfpay->cur_off += 8 + packet_util_size;
      size_left -= packet_util_size + 8;
      packet_offset += packet_util_size;
      packet_util_size = 0;
      rtpasfpay->marker = TRUE;
    } else {
      /* fragment packet */
      data[0] = flags;
      GST_WRITE_UINT24_BE (data + 1, packet_offset);
      GST_WRITE_UINT32_BE (data + 4,
          (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
      memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset,
          size_left - 8);

      /* updating status variables */
      rtpasfpay->cur_off += size_left;
      packet_offset += size_left - 8;
      packet_util_size -= size_left - 8;
      size_left = 0;
      force_push = TRUE;
    }

    /* there is not enough room for any more buffers */
    if (force_push || size_left <= 8) {

      if (size_left != 0) {
        /* trim remaining bytes not used */
        GstBuffer *aux = gst_buffer_create_sub (rtpasfpay->current, 0,
            GST_BUFFER_SIZE (rtpasfpay->current) - size_left);
        gst_buffer_unref (rtpasfpay->current);
        rtpasfpay->current = aux;
      }
      gst_rtp_buffer_set_ssrc (rtpasfpay->current, rtppay->current_ssrc);
      gst_rtp_buffer_set_marker (rtpasfpay->current, rtpasfpay->marker);
      gst_rtp_buffer_set_payload_type (rtpasfpay->current,
          GST_BASE_RTP_PAYLOAD_PT (rtppay));
      gst_rtp_buffer_set_seq (rtpasfpay->current, rtppay->seqnum + 1);
      gst_rtp_buffer_set_timestamp (rtpasfpay->current, packetinfo->send_time);

      GST_BUFFER_TIMESTAMP (rtpasfpay->current) = GST_BUFFER_TIMESTAMP (buffer);

      gst_buffer_set_caps (rtpasfpay->current,
          GST_PAD_CAPS (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay)));

      rtppay->seqnum++;
      rtppay->timestamp = packetinfo->send_time;

      GST_DEBUG_OBJECT (rtpasfpay, "Pushing rtp buffer");
      ret =
          gst_pad_push (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay),
          rtpasfpay->current);
      rtpasfpay->current = NULL;
      if (ret != GST_FLOW_OK) {
        gst_buffer_unref (buffer);
        return ret;
      }
    }
  }
  gst_buffer_unref (buffer);
  return ret;
}