Пример #1
0
/**
 * gst_adapter_take_buffer:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to take
 *
 * Returns a #GstBuffer containing the first @nbytes bytes of the
 * @adapter. The returned bytes will be flushed from the adapter.
 * This function is potentially more performant than gst_adapter_take()
 * since it can reuse the memory in pushed buffers by subbuffering
 * or merging.
 *
 * Note that no assumptions should be made as to whether certain buffer
 * flags such as the DISCONT flag are set on the returned buffer, or not.
 * The caller needs to explicitly set or unset flags that should be set or
 * unset.
 *
 * Caller owns a reference to the returned buffer. gst_buffer_unref() after
 * usage.
 *
 * Free-function: gst_buffer_unref
 *
 * Returns: (transfer full): a #GstBuffer containing the first @nbytes of
 *     the adapter, or #NULL if @nbytes bytes are not available.
 *     gst_buffer_unref() when no longer needed.
 */
GstBuffer *
gst_adapter_take_buffer (GstAdapter * adapter, gsize nbytes)
{
  GstBuffer *buffer;
  GstBuffer *cur;
  gsize hsize, skip;
  guint8 *data;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (nbytes > 0, NULL);

  GST_LOG_OBJECT (adapter, "taking buffer of %" G_GSIZE_FORMAT " bytes",
      nbytes);

  /* we don't have enough data, return NULL. This is unlikely
   * as one usually does an _available() first instead of grabbing a
   * random size. */
  if (G_UNLIKELY (nbytes > adapter->size))
    return NULL;

  cur = adapter->buflist->data;
  skip = adapter->skip;
  hsize = gst_buffer_get_size (cur);

  /* our head buffer has enough data left, return it */
  if (skip == 0 && hsize == nbytes) {
    GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " bytes"
        " as head buffer", nbytes);
    buffer = gst_buffer_ref (cur);
    goto done;
  } else if (hsize >= nbytes + skip) {
    GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " bytes"
        " via region copy", nbytes);
    buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, nbytes);
    goto done;
  }
#if 0
  if (gst_adapter_try_to_merge_up (adapter, nbytes)) {
    /* Merged something, let's try again for sub-buffering */
    cur = adapter->buflist->data;
    skip = adapter->skip;
    if (gst_buffer_get_size (cur) >= nbytes + skip) {
      GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " bytes"
          " via sub-buffer", nbytes);
      buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, nbytes);
      goto done;
    }
  }
#endif

  data = gst_adapter_take_internal (adapter, nbytes);

  buffer = gst_buffer_new_wrapped (data, nbytes);

done:
  gst_adapter_flush_unchecked (adapter, nbytes);

  return buffer;
}
Пример #2
0
static void udp_streaming (Encoder *encoder, GstBuffer *buffer)
{
        gsize buffer_size;
        gssize offset;
        GstFlowReturn ret;

        offset = 0;
        buffer_size = gst_buffer_get_size (buffer);
        while (buffer_size != 0) {
                if ((encoder->cache_size == 0) && (buffer_size < 1316)) {
                        encoder->cache_7x188 = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY, offset, buffer_size);
                        encoder->cache_size = buffer_size;
                        break;

                } else if (encoder->cache_size == 0) {
                        /* buffer_size >= 1316 */
                        encoder->cache_7x188 = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY, offset, 1316);
                        offset += 1316;
                        buffer_size -= 1316;

                } else if (encoder->cache_size + buffer_size >= 1316) {
                        gsize size;
                        gst_buffer_ref (buffer);
                        size = 1316 - encoder->cache_size;
                        encoder->cache_7x188 = gst_buffer_append_region (encoder->cache_7x188, buffer, offset, size);
                        offset += 1316 - encoder->cache_size;
                        buffer_size -= 1316 - encoder->cache_size;
                        encoder->cache_size = 0;

                } else {
                        /* encoder->cache_size + buffer_size < 1316 */
                        gst_buffer_ref (buffer);
                        encoder->cache_7x188 = gst_buffer_append_region (encoder->cache_7x188, buffer, offset, buffer_size);
                        encoder->cache_size += buffer_size;
                        break;
                }
                ret = gst_app_src_push_buffer ((GstAppSrc *)encoder->appsrc, encoder->cache_7x188);
                if (ret != GST_FLOW_OK) {
                        GST_ERROR ("appsrc push buffer failure, return %s.", gst_flow_get_name (ret));
                        gst_buffer_unref (encoder->cache_7x188);
                }
                encoder->cache_size = 0;
        }
}
Пример #3
0
static gboolean
gst_raw_video_parse_process (GstRawBaseParse * raw_base_parse,
    GstRawBaseParseConfig config, GstBuffer * in_data,
    G_GNUC_UNUSED gsize total_num_in_bytes,
    G_GNUC_UNUSED gsize num_valid_in_bytes, GstBuffer ** processed_data)
{
  GstRawVideoParse *raw_video_parse = GST_RAW_VIDEO_PARSE (raw_base_parse);
  GstRawVideoParseConfig *config_ptr =
      gst_raw_video_parse_get_config_ptr (raw_video_parse, config);
  guint frame_flags = 0;
  GstVideoInfo *video_info = &(config_ptr->info);
  GstVideoMeta *videometa;
  GstBuffer *out_data;

  /* In case of extra padding bytes, get a subbuffer without the padding bytes.
   * Otherwise, just add the video meta. */
  if (GST_VIDEO_INFO_SIZE (video_info) < config_ptr->frame_stride) {
    *processed_data = out_data =
        gst_buffer_copy_region (in_data,
        GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
        GST_BUFFER_COPY_MEMORY, 0, GST_VIDEO_INFO_SIZE (video_info));
  } else {
    out_data = in_data;
    *processed_data = NULL;
  }

  if (config_ptr->interlaced) {
    GST_BUFFER_FLAG_SET (out_data, GST_VIDEO_BUFFER_FLAG_INTERLACED);
    frame_flags |= GST_VIDEO_FRAME_FLAG_INTERLACED;

    if (config_ptr->top_field_first) {
      GST_BUFFER_FLAG_SET (out_data, GST_VIDEO_BUFFER_FLAG_TFF);
      frame_flags |= GST_VIDEO_FRAME_FLAG_TFF;
    } else
      GST_BUFFER_FLAG_UNSET (out_data, GST_VIDEO_BUFFER_FLAG_TFF);
  }

  /* Remove any existing videometa - it will be replaced by the new videometa
   * from here */
  while ((videometa = gst_buffer_get_video_meta (out_data))) {
    GST_LOG_OBJECT (raw_base_parse, "removing existing videometa from buffer");
    gst_buffer_remove_meta (out_data, (GstMeta *) videometa);
  }

  gst_buffer_add_video_meta_full (out_data,
      frame_flags,
      config_ptr->format,
      config_ptr->width,
      config_ptr->height,
      GST_VIDEO_INFO_N_PLANES (video_info),
      config_ptr->plane_offsets, config_ptr->plane_strides);


  return TRUE;
}
Пример #4
0
/**
 * gst_adapter_get_buffer_fast:
 * @adapter:  a #GstAdapter
 * @nbytes: the number of bytes to get
 *
 * Returns a #GstBuffer containing the first @nbytes of the @adapter, but
 * does not flush them from the adapter. See gst_adapter_take_buffer_fast()
 * for details.
 *
 * Caller owns a reference to the returned buffer. gst_buffer_unref() after
 * usage.
 *
 * Free-function: gst_buffer_unref
 *
 * Returns: (transfer full) (nullable): a #GstBuffer containing the first
 *     @nbytes of the adapter, or %NULL if @nbytes bytes are not available.
 *     gst_buffer_unref() when no longer needed.
 *
 * Since: 1.6
 */
GstBuffer *
gst_adapter_get_buffer_fast (GstAdapter * adapter, gsize nbytes)
{
  GstBuffer *buffer = NULL;
  GstBuffer *cur;
  GSList *item;
  gsize skip;
  gsize left = nbytes;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (nbytes > 0, NULL);

  GST_LOG_OBJECT (adapter, "getting buffer of %" G_GSIZE_FORMAT " bytes",
      nbytes);

  /* we don't have enough data, return NULL. This is unlikely
   * as one usually does an _available() first instead of grabbing a
   * random size. */
  if (G_UNLIKELY (nbytes > adapter->size))
    return NULL;

  skip = adapter->skip;
  cur = adapter->buflist->data;

  if (skip == 0 && gst_buffer_get_size (cur) == nbytes) {
    GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " bytes"
        " as head buffer", nbytes);
    buffer = gst_buffer_ref (cur);
    goto done;
  }

  for (item = adapter->buflist; item && left > 0; item = item->next) {
    gsize size, cur_size;

    cur = item->data;
    cur_size = gst_buffer_get_size (cur);
    size = MIN (cur_size - skip, left);

    GST_LOG_OBJECT (adapter, "appending %" G_GSIZE_FORMAT " bytes"
        " via region copy", size);
    if (buffer)
      gst_buffer_copy_into (buffer, cur,
          GST_BUFFER_COPY_MEMORY | GST_BUFFER_COPY_META, skip, size);
    else
      buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, size);
    skip = 0;
    left -= size;
  }

done:

  return buffer;
}
Пример #5
0
/**
 * gst_adapter_get_buffer_list:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to get
 *
 * Returns a #GstBufferList of buffers containing the first @nbytes bytes of
 * the @adapter but does not flush them from the adapter. See
 * gst_adapter_take_buffer_list() for details.
 *
 * Caller owns the returned list. Call gst_buffer_list_unref() to free
 * the list after usage.
 *
 * Returns: (transfer full) (nullable): a #GstBufferList of buffers containing
 *     the first @nbytes of the adapter, or %NULL if @nbytes bytes are not
 *     available
 *
 * Since: 1.6
 */
GstBufferList *
gst_adapter_get_buffer_list (GstAdapter * adapter, gsize nbytes)
{
  GstBufferList *buffer_list;
  GstBuffer *cur, *buffer;
  gsize hsize, skip, cur_size;
  guint n_bufs;
  GSList *g = NULL;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);

  if (nbytes > adapter->size)
    return NULL;

  GST_LOG_OBJECT (adapter, "getting %" G_GSIZE_FORMAT " bytes", nbytes);

  /* try to create buffer list with sufficient size, so no resize is done later */
  if (adapter->count < 64)
    n_bufs = adapter->count;
  else
    n_bufs = (adapter->count * nbytes * 1.2 / adapter->size) + 1;

  buffer_list = gst_buffer_list_new_sized (n_bufs);

  g = adapter->buflist;
  skip = adapter->skip;

  while (nbytes > 0) {
    cur = g->data;
    cur_size = gst_buffer_get_size (cur);
    hsize = MIN (nbytes, cur_size - skip);

    if (skip == 0 && cur_size == hsize) {
      GST_LOG_OBJECT (adapter,
          "inserting a buffer of %" G_GSIZE_FORMAT " bytes", hsize);
      buffer = gst_buffer_ref (cur);
    } else {
      GST_LOG_OBJECT (adapter, "inserting a buffer of %" G_GSIZE_FORMAT " bytes"
          " via region copy", hsize);
      buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, hsize);
    }

    gst_buffer_list_add (buffer_list, buffer);

    nbytes -= hsize;
    skip = 0;
    g = g_slist_next (g);
  }

  return buffer_list;
}
Пример #6
0
static GstBuffer *
gst_fake_src_create_buffer (GstFakeSrc * src, gsize * bufsize)
{
  GstBuffer *buf;
  gsize size = gst_fake_src_get_size (src);
  gboolean dump = src->dump;
  GstMapInfo info;

  *bufsize = size;

  switch (src->data) {
    case FAKE_SRC_DATA_ALLOCATE:
      buf = gst_fake_src_alloc_buffer (src, size);
      break;
    case FAKE_SRC_DATA_SUBBUFFER:
      /* see if we have a parent to subbuffer */
      if (!src->parent) {
        gst_fake_src_alloc_parent (src);
        g_assert (src->parent);
      }
      /* see if it's large enough */
      if ((src->parentsize - src->parentoffset) >= size) {
        buf =
            gst_buffer_copy_region (src->parent, GST_BUFFER_COPY_ALL,
            src->parentoffset, size);
        src->parentoffset += size;
      } else {
        /* the parent is useless now */
        gst_buffer_unref (src->parent);
        src->parent = NULL;
        /* try again (this will allocate a new parent) */
        return gst_fake_src_create_buffer (src, bufsize);
      }
      gst_buffer_map (buf, &info, GST_MAP_WRITE);
      gst_fake_src_prepare_buffer (src, info.data, info.size);
      gst_buffer_unmap (buf, &info);
      break;
    default:
      g_warning ("fakesrc: dunno how to allocate buffers !");
      buf = gst_buffer_new ();
      break;
  }
  if (dump) {
    gst_buffer_map (buf, &info, GST_MAP_READ);
    gst_util_dump_mem (info.data, info.size);
    gst_buffer_unmap (buf, &info);
  }

  return buf;
}
Пример #7
0
GstBuffer *
gst_rdt_packet_to_buffer (GstRDTPacket * packet)
{
  GstBuffer *result;

  g_return_val_if_fail (packet != NULL, NULL);
  g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID, NULL);

  result =
      gst_buffer_copy_region (packet->buffer, GST_BUFFER_COPY_ALL,
      packet->offset, packet->length);
  /* timestamp applies to all packets in this buffer */
  GST_BUFFER_TIMESTAMP (result) = GST_BUFFER_TIMESTAMP (packet->buffer);

  return result;
}
Пример #8
0
static GstFlowReturn
gst_data_uri_src_create (GstBaseSrc * basesrc, guint64 offset, guint size,
    GstBuffer ** buf)
{
  GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
  GstFlowReturn ret;

  GST_OBJECT_LOCK (src);

  if (!src->buffer)
    goto no_buffer;

  /* This is only correct because GstBaseSrc already clips size for us to be no
   * larger than the max. available size if a segment at the end is requested */
  if (offset + size > gst_buffer_get_size (src->buffer)) {
    ret = GST_FLOW_EOS;
  } else if (*buf != NULL) {
    GstMapInfo src_info;
    GstMapInfo dest_info;
    gsize fill_size;

    gst_buffer_map (src->buffer, &src_info, GST_MAP_READ);
    gst_buffer_map (*buf, &dest_info, GST_MAP_WRITE);

    fill_size = gst_buffer_fill (*buf, 0, src_info.data + offset, size);

    gst_buffer_unmap (*buf, &dest_info);
    gst_buffer_unmap (src->buffer, &src_info);
    gst_buffer_set_size (*buf, fill_size);
    ret = GST_FLOW_OK;
  } else {
    *buf =
        gst_buffer_copy_region (src->buffer, GST_BUFFER_COPY_ALL, offset, size);
    ret = GST_FLOW_OK;
  }
  GST_OBJECT_UNLOCK (src);

  return ret;

/* ERRORS */
no_buffer:
  {
    GST_OBJECT_UNLOCK (src);
    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), (NULL));
    return GST_FLOW_NOT_NEGOTIATED;
  }
}
Пример #9
0
static gboolean
gst_raw_audio_parse_process (GstRawBaseParse * raw_base_parse,
    GstRawBaseParseConfig config, GstBuffer * in_data, gsize total_num_in_bytes,
    gsize num_valid_in_bytes, GstBuffer ** processed_data)
{
  GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
  GstRawAudioParseConfig *config_ptr =
      gst_raw_audio_parse_get_config_ptr (raw_audio_parse, config);

  if ((config_ptr->format == GST_RAW_AUDIO_PARSE_FORMAT_PCM)
      && config_ptr->needs_channel_reordering) {
    /* Need to reorder samples, since they are in an invalid
     * channel order. */

    GstBuffer *outbuf;

    GST_LOG_OBJECT (raw_audio_parse,
        "using %" G_GSIZE_FORMAT " bytes out of the %" G_GSIZE_FORMAT
        " bytes from the input buffer with reordering", num_valid_in_bytes,
        total_num_in_bytes);

    outbuf =
        gst_buffer_copy_region (in_data,
        GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
        GST_BUFFER_COPY_META | GST_BUFFER_COPY_MEMORY, 0, num_valid_in_bytes);

    gst_audio_buffer_reorder_channels (outbuf,
        config_ptr->pcm_format,
        config_ptr->num_channels,
        config_ptr->channel_positions, config_ptr->reordered_channel_positions);

    *processed_data = outbuf;
  } else {
    /* Nothing needs to be done with the sample data.
     * Instruct the baseparse class to just take out_size bytes
     * from the input buffer */

    GST_LOG_OBJECT (raw_audio_parse,
        "using %" G_GSIZE_FORMAT " bytes out of the %" G_GSIZE_FORMAT
        " bytes from the input buffer without reordering", num_valid_in_bytes,
        total_num_in_bytes);

    *processed_data = NULL;
  }

  return TRUE;
}
Пример #10
0
/**
 * gst_adapter_get_list:
 * @adapter: a #GstAdapter
 * @nbytes: the number of bytes to get
 *
 * Returns a #GList of buffers containing the first @nbytes bytes of the
 * @adapter, but does not flush them from the adapter. See
 * gst_adapter_take_list() for details.
 *
 * Caller owns returned list and contained buffers. gst_buffer_unref() each
 * buffer in the list before freeing the list after usage.
 *
 * Returns: (element-type Gst.Buffer) (transfer full) (nullable): a #GList of
 *     buffers containing the first @nbytes of the adapter, or %NULL if @nbytes
 *     bytes are not available
 *
 * Since: 1.6
 */
GList *
gst_adapter_get_list (GstAdapter * adapter, gsize nbytes)
{
  GQueue queue = G_QUEUE_INIT;
  GstBuffer *cur, *buffer;
  gsize hsize, skip, cur_size;
  GSList *g = NULL;

  g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
  g_return_val_if_fail (nbytes <= adapter->size, NULL);

  GST_LOG_OBJECT (adapter, "getting %" G_GSIZE_FORMAT " bytes", nbytes);

  g = adapter->buflist;
  skip = adapter->skip;

  while (nbytes > 0) {
    cur = g->data;
    cur_size = gst_buffer_get_size (cur);
    hsize = MIN (nbytes, cur_size - skip);

    if (skip == 0 && cur_size == hsize) {
      GST_LOG_OBJECT (adapter,
          "inserting a buffer of %" G_GSIZE_FORMAT " bytes", hsize);
      buffer = gst_buffer_ref (cur);
    } else {
      GST_LOG_OBJECT (adapter, "inserting a buffer of %" G_GSIZE_FORMAT " bytes"
          " via region copy", hsize);
      buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, hsize);
    }

    g_queue_push_tail (&queue, buffer);

    nbytes -= hsize;
    skip = 0;
    g = g_slist_next (g);
  }

  return queue.head;
}
Пример #11
0
/**
 * gst_audio_buffer_clip:
 * @buffer: (transfer full): The buffer to clip.
 * @segment: Segment in %GST_FORMAT_TIME or %GST_FORMAT_DEFAULT to which
 *           the buffer should be clipped.
 * @rate: sample rate.
 * @bpf: size of one audio frame in bytes. This is the size of one sample
 * * channels.
 *
 * Clip the buffer to the given %GstSegment.
 *
 * After calling this function the caller does not own a reference to
 * @buffer anymore.
 *
 * Returns: (transfer full): %NULL if the buffer is completely outside the configured segment,
 * otherwise the clipped buffer is returned.
 *
 * If the buffer has no timestamp, it is assumed to be inside the segment and
 * is not clipped
 */
GstBuffer *
gst_audio_buffer_clip (GstBuffer * buffer, GstSegment * segment, gint rate,
    gint bpf)
{
  GstBuffer *ret;
  GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
  guint64 offset = GST_BUFFER_OFFSET_NONE, offset_end = GST_BUFFER_OFFSET_NONE;
  gsize trim, size, osize;
  gboolean change_duration = TRUE, change_offset = TRUE, change_offset_end =
      TRUE;

  g_return_val_if_fail (segment->format == GST_FORMAT_TIME ||
      segment->format == GST_FORMAT_DEFAULT, buffer);
  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);

  if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
    /* No timestamp - assume the buffer is completely in the segment */
    return buffer;

  /* Get copies of the buffer metadata to change later.
   * Calculate the missing values for the calculations,
   * they won't be changed later though. */

  trim = 0;
  osize = size = gst_buffer_get_size (buffer);

  /* no data, nothing to clip */
  if (!size)
    return buffer;

  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  GST_DEBUG ("timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
  if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
    duration = GST_BUFFER_DURATION (buffer);
  } else {
    change_duration = FALSE;
    duration = gst_util_uint64_scale (size / bpf, GST_SECOND, rate);
  }

  if (GST_BUFFER_OFFSET_IS_VALID (buffer)) {
    offset = GST_BUFFER_OFFSET (buffer);
  } else {
    change_offset = FALSE;
    offset = 0;
  }

  if (GST_BUFFER_OFFSET_END_IS_VALID (buffer)) {
    offset_end = GST_BUFFER_OFFSET_END (buffer);
  } else {
    change_offset_end = FALSE;
    offset_end = offset + size / bpf;
  }

  if (segment->format == GST_FORMAT_TIME) {
    /* Handle clipping for GST_FORMAT_TIME */

    guint64 start, stop, cstart, cstop, diff;

    start = timestamp;
    stop = timestamp + duration;

    if (gst_segment_clip (segment, GST_FORMAT_TIME,
            start, stop, &cstart, &cstop)) {

      diff = cstart - start;
      if (diff > 0) {
        timestamp = cstart;

        if (change_duration)
          duration -= diff;

        diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
        if (change_offset)
          offset += diff;
        trim += diff * bpf;
        size -= diff * bpf;
      }

      diff = stop - cstop;
      if (diff > 0) {
        /* duration is always valid if stop is valid */
        duration -= diff;

        diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
        if (change_offset_end)
          offset_end -= diff;
        size -= diff * bpf;
      }
    } else {
      gst_buffer_unref (buffer);
      return NULL;
    }
  } else {
    /* Handle clipping for GST_FORMAT_DEFAULT */
    guint64 start, stop, cstart, cstop, diff;

    g_return_val_if_fail (GST_BUFFER_OFFSET_IS_VALID (buffer), buffer);

    start = offset;
    stop = offset_end;

    if (gst_segment_clip (segment, GST_FORMAT_DEFAULT,
            start, stop, &cstart, &cstop)) {

      diff = cstart - start;
      if (diff > 0) {
        offset = cstart;

        timestamp = gst_util_uint64_scale (cstart, GST_SECOND, rate);

        if (change_duration)
          duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);

        trim += diff * bpf;
        size -= diff * bpf;
      }

      diff = stop - cstop;
      if (diff > 0) {
        offset_end = cstop;

        if (change_duration)
          duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);

        size -= diff * bpf;
      }
    } else {
      gst_buffer_unref (buffer);
      return NULL;
    }
  }

  if (trim == 0 && size == osize) {
    ret = buffer;

    if (GST_BUFFER_TIMESTAMP (ret) != timestamp) {
      ret = gst_buffer_make_writable (ret);
      GST_BUFFER_TIMESTAMP (ret) = timestamp;
    }
    if (GST_BUFFER_DURATION (ret) != duration) {
      ret = gst_buffer_make_writable (ret);
      GST_BUFFER_DURATION (ret) = duration;
    }
  } else {
    /* Get a writable buffer and apply all changes */
    GST_DEBUG ("trim %" G_GSIZE_FORMAT " size %" G_GSIZE_FORMAT, trim, size);
    ret = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, trim, size);
    gst_buffer_unref (buffer);

    GST_DEBUG ("timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
    GST_BUFFER_TIMESTAMP (ret) = timestamp;

    if (change_duration)
      GST_BUFFER_DURATION (ret) = duration;
    if (change_offset)
      GST_BUFFER_OFFSET (ret) = offset;
    if (change_offset_end)
      GST_BUFFER_OFFSET_END (ret) = offset_end;
  }
  return ret;
}
static GstFlowReturn gst_mpeg4p2unpack_chain(GstPad *pad, GstObject *parent, GstBuffer *buffer)
{
	guint8 *data;
	gsize data_len;
	GstMapInfo buffermap;
	GstFlowReturn ret = GST_FLOW_OK;
	GstMpeg4P2Unpack *self = GST_MPEG4P2UNPACK(GST_PAD_PARENT(pad));

	if (self->buffer_duration == GST_CLOCK_TIME_NONE)
	{
		if (!GST_BUFFER_DURATION_IS_VALID(buffer))
		{
			GST_WARNING_OBJECT(self, "Cannot retrieve buffer duration, dropping");
			gst_buffer_unref(buffer);
			return GST_FLOW_OK;
		}
		self->buffer_duration = GST_BUFFER_DURATION(buffer);
	}

	gst_buffer_map(buffer, &buffermap, GST_MAP_READ);
	data = buffermap.data;
	data_len = buffermap.size;

	int pos_p = -1, nb_vop = 0, pos_vop2 = -1;
	mpeg4p2_scan_buffer(data, data_len, &pos_p, &nb_vop, &pos_vop2);
	// GST_LOG_OBJECT(self, "pos_p=%d, num_vop=%d, pos_vop2=%d", pos_p, nb_vop, pos_vop2);

	/* if we don't have userdata we can unmap buffer */
	if (pos_p < 0)
	{
		gst_buffer_unmap(buffer, &buffermap);
		data = NULL;
	}

	if (pos_vop2 >= 0)
	{
		if (self->b_frame)
		{
			GST_WARNING_OBJECT(self, "Missing one N-VOP packet, discarding one B-frame");
			gst_buffer_unref(self->b_frame);
			self->b_frame = NULL;
		}
		// GST_LOG_OBJECT(self, "Storing B-Frame of packed PB-Frame");
		self->b_frame = gst_buffer_copy_region(buffer, GST_BUFFER_COPY_ALL, pos_vop2, data_len - pos_vop2);
		GST_BUFFER_DTS(self->b_frame) = GST_BUFFER_DTS(buffer) + self->buffer_duration;
	}

	if (nb_vop > 2)
	{
		GST_WARNING_OBJECT(self, "Found %d VOP headers in one packet, only unpacking one.", nb_vop);
	}

	if (nb_vop == 1 && self->b_frame)
	{
		// GST_LOG_OBJECT(self, "Push previous B-Frame");
		ret = gst_mpeg4p2unpack_handle_frame(self, self->b_frame);
		if (data_len <= MPEG4P2_MAX_NVOP_SIZE)
		{
			// GST_LOG_OBJECT(self, "Skipping N-VOP");
			self->b_frame = NULL;
			gst_buffer_unref(buffer);
		}
		else
		{
			// GST_LOG_OBJECT(self, "Store B-Frame");
			GST_BUFFER_DTS(buffer) = GST_BUFFER_DTS(self->b_frame) + self->buffer_duration;
			self->b_frame = buffer;
		}
	}
	else if (nb_vop >= 2)
	{
		// GST_LOG_OBJECT(self, "Push P-frame of packed PB-Frame");
		GstBuffer *p_frame = gst_buffer_copy_region(buffer, GST_BUFFER_COPY_ALL, 0, pos_vop2);
		ret = gst_mpeg4p2unpack_handle_frame(self, p_frame);
		gst_buffer_unref(buffer);
	}
	else if (pos_p >= 0)
	{
		// GST_LOG_OBJECT(self, "Updating DivX userdata (replacing trailing 'p')");
		gst_buffer_unmap(buffer, &buffermap);
		gst_buffer_map(buffer, &buffermap, GST_MAP_WRITE);
		data = buffermap.data;
		data[pos_p] = 'n';
		gst_buffer_unmap(buffer, &buffermap);
		data = NULL;
		ret = gst_mpeg4p2unpack_handle_frame(self, buffer);
	}
	else
	{
		ret = gst_mpeg4p2unpack_handle_frame(self, buffer);
	}
	return ret;
}
Пример #13
0
static gboolean
theora_dec_set_format (GstVideoDecoder * bdec, GstVideoCodecState * state)
{
  GstTheoraDec *dec;

  dec = GST_THEORA_DEC (bdec);

  /* Keep a copy of the input state */
  if (dec->input_state)
    gst_video_codec_state_unref (dec->input_state);
  dec->input_state = gst_video_codec_state_ref (state);

  /* FIXME : Interesting, we always accept any kind of caps ? */
  if (state->codec_data) {
    GstBuffer *buffer;
    GstMapInfo minfo;
    guint8 *data;
    guint size;
    guint offset;

    buffer = state->codec_data;
    gst_buffer_map (buffer, &minfo, GST_MAP_READ);

    offset = 0;
    size = minfo.size;
    data = (guint8 *) minfo.data;

    while (size > 2) {
      guint psize;
      GstBuffer *buf;

      psize = (data[0] << 8) | data[1];
      /* skip header */
      data += 2;
      size -= 2;
      offset += 2;

      /* make sure we don't read too much */
      psize = MIN (psize, size);

      buf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);

      /* first buffer is a discont buffer */
      if (offset == 2)
        GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);

      /* now feed it to the decoder we can ignore the error */
      theora_dec_decode_buffer (dec, buf, NULL);
      gst_buffer_unref (buf);

      /* skip the data */
      size -= psize;
      data += psize;
      offset += psize;
    }

    gst_buffer_unmap (buffer, &minfo);
  }

  GST_DEBUG_OBJECT (dec, "Done");

  return TRUE;
}
Пример #14
0
static GstFlowReturn
gst_pngenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
    GstPngEnc *pngenc;
    gint row_index;
    png_byte **row_pointers;
    GstFlowReturn ret = GST_FLOW_OK;
    GstBuffer *encoded_buf = NULL;
    GstVideoFrame frame;

    pngenc = GST_PNGENC (parent);

    GST_DEBUG_OBJECT (pngenc, "BEGINNING");

    if (G_UNLIKELY (pngenc->width <= 0 || pngenc->height <= 0)) {
        ret = GST_FLOW_NOT_NEGOTIATED;
        goto exit;
    }

    if (!gst_video_frame_map (&frame, &pngenc->info, buf, GST_MAP_READ)) {
        GST_ELEMENT_ERROR (pngenc, STREAM, FORMAT, (NULL),
                           ("Failed to map video frame, caps problem?"));
        ret = GST_FLOW_ERROR;
        goto exit;
    }

    /* 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_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) {
        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) {
        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);

    png_set_IHDR (pngenc->png_struct_ptr,
                  pngenc->png_info_ptr,
                  pngenc->width,
                  pngenc->height,
                  pngenc->depth,
                  pngenc->png_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);

    row_pointers = g_new (png_byte *, pngenc->height);

    for (row_index = 0; row_index < pngenc->height; row_index++) {
        row_pointers[row_index] = GST_VIDEO_FRAME_COMP_DATA (&frame, 0) +
                                  (row_index * GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0));
    }

    /* allocate the output buffer */
    pngenc->buffer_out =
        gst_buffer_new_and_alloc (pngenc->height * pngenc->width);
    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);

    g_free (row_pointers);

    GST_DEBUG_OBJECT (pngenc, "written %d", pngenc->written);

    encoded_buf =
        gst_buffer_copy_region (pngenc->buffer_out, GST_BUFFER_COPY_MEMORY,
                                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_TIMESTAMP (encoded_buf) = GST_BUFFER_TIMESTAMP (buf);
    GST_BUFFER_DURATION (encoded_buf) = GST_BUFFER_DURATION (buf);

    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_EOS;
    }

done:
    gst_video_frame_unmap (&frame);
exit:
    gst_buffer_unref (buf);
    GST_DEBUG_OBJECT (pngenc, "END, ret:%d", ret);

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

    return ret;
}
Пример #15
0
static GstFlowReturn
gst_rtp_asf_pay_handle_buffer (GstRTPBasePayload * rtppay, GstBuffer * buffer)
{
  GstRtpAsfPay *rtpasfpay = GST_RTP_ASF_PAY_CAST (rtppay);

  if (G_UNLIKELY (rtpasfpay->state == ASF_END)) {
    GST_LOG_OBJECT (rtpasfpay,
        "Dropping buffer as we already pushed all packets");
    gst_buffer_unref (buffer);
    return GST_FLOW_EOS;        /* we already finished our job */
  }

  /* receive headers 
   * we only accept if they are in a single buffer */
  if (G_UNLIKELY (rtpasfpay->state == ASF_NOT_STARTED)) {
    guint64 header_size;

    if (gst_buffer_get_size (buffer) < 24) {    /* guid+object size size */
      GST_ERROR_OBJECT (rtpasfpay,
          "Buffer too small, smaller than a Guid and object size");
      gst_buffer_unref (buffer);
      return GST_FLOW_ERROR;
    }

    header_size = gst_asf_match_and_peek_obj_size_buf (buffer,
        &(guids[ASF_HEADER_OBJECT_INDEX]));
    if (header_size > 0) {
      GST_DEBUG_OBJECT (rtpasfpay, "ASF header guid received, size %"
          G_GUINT64_FORMAT, header_size);

      if (gst_buffer_get_size (buffer) < header_size) {
        GST_ERROR_OBJECT (rtpasfpay, "Headers should be contained in a single"
            " buffer");
        gst_buffer_unref (buffer);
        return GST_FLOW_ERROR;
      } else {
        rtpasfpay->state = ASF_DATA_OBJECT;

        /* clear previous headers, if any */
        if (rtpasfpay->headers) {
          gst_buffer_unref (rtpasfpay->headers);
        }

        GST_DEBUG_OBJECT (rtpasfpay, "Storing headers");
        if (gst_buffer_get_size (buffer) == header_size) {
          rtpasfpay->headers = buffer;
          return GST_FLOW_OK;
        } else {
          /* headers are a subbuffer of thie buffer */
          GstBuffer *aux = gst_buffer_copy_region (buffer,
              GST_BUFFER_COPY_ALL, header_size,
              gst_buffer_get_size (buffer) - header_size);
          rtpasfpay->headers = gst_buffer_copy_region (buffer,
              GST_BUFFER_COPY_ALL, 0, header_size);
          gst_buffer_replace (&buffer, aux);
        }
      }
    } else {
      GST_ERROR_OBJECT (rtpasfpay, "Missing ASF header start");
      gst_buffer_unref (buffer);
      return GST_FLOW_ERROR;
    }
  }

  if (G_UNLIKELY (rtpasfpay->state == ASF_DATA_OBJECT)) {
    GstMapInfo map;

    if (gst_buffer_get_size (buffer) != ASF_DATA_OBJECT_SIZE) {
      GST_ERROR_OBJECT (rtpasfpay, "Received buffer of different size of "
          "the data object header");
      gst_buffer_unref (buffer);
      return GST_FLOW_ERROR;
    }

    gst_buffer_map (buffer, &map, GST_MAP_READ);
    if (gst_asf_match_guid (map.data, &(guids[ASF_DATA_OBJECT_INDEX]))) {
      gst_buffer_unmap (buffer, &map);
      GST_DEBUG_OBJECT (rtpasfpay, "Received data object header");
      rtpasfpay->headers = gst_buffer_append (rtpasfpay->headers, buffer);
      rtpasfpay->state = ASF_PACKETS;

      return gst_rtp_asf_pay_parse_headers (rtpasfpay);
    } else {
      gst_buffer_unmap (buffer, &map);
      GST_ERROR_OBJECT (rtpasfpay, "Unexpected object received (was expecting "
          "data object)");
      gst_buffer_unref (buffer);
      return GST_FLOW_ERROR;
    }
  }

  if (G_LIKELY (rtpasfpay->state == ASF_PACKETS)) {
    /* in broadcast mode we can't trust the packets count information
     * from the headers
     * We assume that if this is on broadcast mode it is a live stream
     * and we are going to keep receiving packets indefinitely
     */
    if (rtpasfpay->asfinfo.broadcast ||
        rtpasfpay->packets_count < rtpasfpay->asfinfo.packets_count) {
      GST_DEBUG_OBJECT (rtpasfpay, "Received packet %"
          G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
          rtpasfpay->packets_count, rtpasfpay->asfinfo.packets_count);
      rtpasfpay->packets_count++;
      return gst_rtp_asf_pay_handle_packet (rtpasfpay, buffer);
    } else {
      GST_INFO_OBJECT (rtpasfpay, "Packets ended");
      rtpasfpay->state = ASF_END;
      gst_buffer_unref (buffer);
      return GST_FLOW_EOS;
    }
  }

  gst_buffer_unref (buffer);
  return GST_FLOW_OK;
}
Пример #16
0
static gboolean
gst_ogg_avi_parse_setcaps (GstPad * pad, GstCaps * caps)
{
  GstOggAviParse *ogg;
  GstStructure *structure;
  const GValue *codec_data;
  GstBuffer *buffer;
  GstMapInfo map;
  guint8 *ptr;
  gsize left;
  guint32 sizes[3];
  GstCaps *outcaps;
  gint i, offs;

  ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad));

  structure = gst_caps_get_structure (caps, 0);

  /* take codec data */
  codec_data = gst_structure_get_value (structure, "codec_data");
  if (codec_data == NULL)
    goto no_data;

  /* only buffers are valid */
  if (G_VALUE_TYPE (codec_data) != GST_TYPE_BUFFER)
    goto wrong_format;

  /* Now parse the data */
  buffer = gst_value_get_buffer (codec_data);

  /* first 22 bytes are bits_per_sample, channel_mask, GUID
   * Then we get 3 LE guint32 with the 3 header sizes
   * then we get the bytes of the 3 headers. */
  gst_buffer_map (buffer, &map, GST_MAP_READ);

  ptr = map.data;
  left = map.size;

  GST_LOG_OBJECT (ogg, "configuring codec_data of size %" G_GSIZE_FORMAT, left);

  /* skip headers */
  ptr += 22;
  left -= 22;

  /* we need at least 12 bytes for the packet sizes of the 3 headers */
  if (left < 12)
    goto buffer_too_small;

  /* read sizes of the 3 headers */
  sizes[0] = GST_READ_UINT32_LE (ptr);
  sizes[1] = GST_READ_UINT32_LE (ptr + 4);
  sizes[2] = GST_READ_UINT32_LE (ptr + 8);

  GST_DEBUG_OBJECT (ogg, "header sizes: %u %u %u", sizes[0], sizes[1],
      sizes[2]);

  left -= 12;

  /* and we need at least enough data for all the headers */
  if (left < sizes[0] + sizes[1] + sizes[2])
    goto buffer_too_small;

  /* set caps */
  outcaps = gst_caps_new_empty_simple ("audio/x-vorbis");
  gst_pad_set_caps (ogg->srcpad, outcaps);
  gst_caps_unref (outcaps);

  /* copy header data */
  offs = 34;
  for (i = 0; i < 3; i++) {
    GstBuffer *out;

    /* now output the raw vorbis header packets */
    out = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offs, sizes[i]);
    gst_pad_push (ogg->srcpad, out);

    offs += sizes[i];
  }
  gst_buffer_unmap (buffer, &map);

  return TRUE;

  /* ERRORS */
no_data:
  {
    GST_DEBUG_OBJECT (ogg, "no codec_data found in caps");
    return FALSE;
  }
wrong_format:
  {
    GST_DEBUG_OBJECT (ogg, "codec_data is not a buffer");
    return FALSE;
  }
buffer_too_small:
  {
    GST_DEBUG_OBJECT (ogg, "codec_data is too small");
    gst_buffer_unmap (buffer, &map);
    return FALSE;
  }
}
Пример #17
0
static GstFlowReturn
gst_ivf_parse_handle_frame_data (GstIvfParse * ivf, GstBaseParseFrame * frame,
    gint * skipsize)
{
  GstBuffer *const buffer = frame->buffer;
  GstMapInfo map;
  GstFlowReturn ret = GST_FLOW_OK;
  GstBuffer *out_buffer;

  gst_buffer_map (buffer, &map, GST_MAP_READ);
  if (map.size >= IVF_FILE_HEADER_SIZE) {
    guint32 frame_size = GST_READ_UINT32_LE (map.data);
    guint64 frame_pts = GST_READ_UINT64_LE (map.data + 4);

    GST_LOG_OBJECT (ivf,
        "Read frame header: size %u, pts %" G_GUINT64_FORMAT, frame_size,
        frame_pts);

    if (map.size < IVF_FRAME_HEADER_SIZE + frame_size) {
      gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (ivf),
          IVF_FRAME_HEADER_SIZE + frame_size);
      gst_buffer_unmap (buffer, &map);
      *skipsize = 0;
      goto end;
    }

    gst_buffer_unmap (buffer, &map);

    /* Eventually, we would need the buffer memory in a merged state anyway */
    out_buffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_FLAGS |
        GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META |
        GST_BUFFER_COPY_MEMORY | GST_BUFFER_COPY_MERGE,
        IVF_FRAME_HEADER_SIZE, frame_size);
    if (!out_buffer) {
      GST_ERROR_OBJECT (ivf, "Failed to copy frame buffer");
      ret = GST_FLOW_ERROR;
      *skipsize = IVF_FRAME_HEADER_SIZE + frame_size;
      goto end;
    }
    gst_buffer_replace (&frame->out_buffer, out_buffer);
    gst_buffer_unref (out_buffer);

    /* Detect resolution changes on key frames */
    if (gst_buffer_map (frame->out_buffer, &map, GST_MAP_READ)) {
      guint32 width, height;

      if (ivf->fourcc == GST_MAKE_FOURCC ('V', 'P', '8', '0')) {
        guint32 frame_tag;
        frame_tag = GST_READ_UINT24_LE (map.data);
        if (!(frame_tag & 0x01) && map.size >= 10) {    /* key frame */
          GST_DEBUG_OBJECT (ivf, "key frame detected");

          width = GST_READ_UINT16_LE (map.data + 6) & 0x3fff;
          height = GST_READ_UINT16_LE (map.data + 8) & 0x3fff;
          gst_ivf_parse_set_size (ivf, width, height);
        }
      } else if (ivf->fourcc == GST_MAKE_FOURCC ('V', 'P', '9', '0')) {
        /* Fixme: Add vp9 frame header parsing? */
      } else if (ivf->fourcc == GST_MAKE_FOURCC ('A', 'V', '0', '1')) {
        /* Fixme: Add av1 frame header parsing? */
        /* This would allow to parse dynamic resolution changes */
        /* implement when gstav1parser is ready */
      }
      gst_buffer_unmap (frame->out_buffer, &map);
    }

    if (ivf->fps_n > 0) {
      GST_BUFFER_TIMESTAMP (out_buffer) =
          gst_util_uint64_scale_int (GST_SECOND * frame_pts, ivf->fps_d,
          ivf->fps_n);
    }

    gst_ivf_parse_update_src_caps (ivf);

    ret = gst_base_parse_finish_frame (GST_BASE_PARSE_CAST (ivf), frame,
        IVF_FRAME_HEADER_SIZE + frame_size);
    *skipsize = 0;
  } else {
    GST_LOG_OBJECT (ivf, "Frame data not yet available.");
    gst_buffer_unmap (buffer, &map);
    *skipsize = 0;
  }

end:
  return ret;
}
Пример #18
0
static GstFlowReturn
gst_dtsdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstDtsDec *dts = GST_DTSDEC (parent);
  gint first_access;

  if (dts->dvdmode) {
    guint8 data[2];
    gsize size;
    gint offset, len;
    GstBuffer *subbuf;

    size = gst_buffer_get_size (buf);
    if (size < 2)
      goto not_enough_data;

    gst_buffer_extract (buf, 0, data, 2);
    first_access = (data[0] << 8) | data[1];

    /* Skip the first_access header */
    offset = 2;

    if (first_access > 1) {
      /* Length of data before first_access */
      len = first_access - 1;

      if (len <= 0 || offset + len > size)
        goto bad_first_access_parameter;

      subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len);
      GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
      ret = dts->base_chain (pad, parent, subbuf);
      if (ret != GST_FLOW_OK) {
        gst_buffer_unref (buf);
        goto done;
      }

      offset += len;
      len = size - offset;

      if (len > 0) {
        subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len);
        GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);

        ret = dts->base_chain (pad, parent, subbuf);
      }
      gst_buffer_unref (buf);
    } else {
      /* first_access = 0 or 1, so if there's a timestamp it applies to the first byte */
      subbuf =
          gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset,
          size - offset);
      GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
      ret = dts->base_chain (pad, parent, subbuf);
      gst_buffer_unref (buf);
    }
  } else {
    ret = dts->base_chain (pad, parent, buf);
  }

done:
  return ret;

/* ERRORS */
not_enough_data:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dts), STREAM, DECODE, (NULL),
        ("Insufficient data in buffer. Can't determine first_acess"));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
bad_first_access_parameter:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dts), STREAM, DECODE, (NULL),
        ("Bad first_access parameter (%d) in buffer", first_access));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
}
Пример #19
0
/* FIXME: this entire function looks completely wrong, if there is or
 * was a bug in GStreamer it should be fixed there (tpm) */
static GstPadProbeReturn
brasero_transcode_buffer_handler (GstPad *pad,
                                  GstPadProbeInfo *info,
                                  gpointer user_data)
{
	BraseroTranscodePrivate *priv;
	BraseroTranscode *self = user_data;
	GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
	GstPad *peer;
	gint64 size;

	priv = BRASERO_TRANSCODE_PRIVATE (self);

	size = gst_buffer_get_size (buffer);

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

	/* 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 GST_PAD_PROBE_DROP;
	}

	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_copy_region (buffer, GST_BUFFER_COPY_METADATA, 0, data_size);

		/* FIXME: we can now modify the probe buffer in 0.11 */
		/* 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 GST_PAD_PROBE_DROP;
	}

	/* 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 GST_PAD_PROBE_DROP;
		}

		/* 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_copy_region (buffer, GST_BUFFER_COPY_METADATA, size - data_size, data_size);
		/* FIXME: this looks dodgy (tpm) */
		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;

		/* FIXME: we can now modify the probe buffer in 0.11 */
		/* 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 GST_PAD_PROBE_DROP;
	}

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

	return GST_PAD_PROBE_OK;
}
static GstFlowReturn
gst_rtp_klv_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstBufferList *list = NULL;
  GstRtpKlvPay *pay;
  GstMapInfo map;
  GstBuffer *outbuf = NULL;
  gsize offset;
  guint mtu, rtp_header_size, max_payload_size;

  pay = GST_RTP_KLV_PAY (basepayload);
  mtu = GST_RTP_BASE_PAYLOAD_MTU (basepayload);

  rtp_header_size = gst_rtp_buffer_calc_header_len (0);
  max_payload_size = mtu - rtp_header_size;

  gst_buffer_map (buf, &map, GST_MAP_READ);

  if (map.size == 0)
    goto done;

  /* KLV coding shall use and only use a fixed 16-byte SMPTE-administered
   * Universal Label, according to SMPTE 298M as Key (Rec. ITU R-BT.1653-1) */
  if (map.size < 16 || GST_READ_UINT32_BE (map.data) != 0x060E2B34)
    goto bad_input;

  if (map.size > max_payload_size)
    list = gst_buffer_list_new ();

  GST_LOG_OBJECT (pay, "%" G_GSIZE_FORMAT " bytes of data to payload",
      map.size);

  offset = 0;
  while (offset < map.size) {
    GstBuffer *payloadbuf;
    GstRTPBuffer rtp = { NULL };
    guint payload_size;
    guint bytes_left;

    bytes_left = map.size - offset;
    payload_size = MIN (bytes_left, max_payload_size);

    outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);

    if (payload_size == bytes_left) {
      GST_LOG_OBJECT (pay, "last packet of KLV unit");
      gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
      gst_rtp_buffer_set_marker (&rtp, 1);
      gst_rtp_buffer_unmap (&rtp);
    }

    GST_LOG_OBJECT (pay, "packet with payload size %u", payload_size);

    gst_rtp_copy_meta (GST_ELEMENT_CAST (pay), outbuf, buf, 0);

    payloadbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_MEMORY,
        offset, payload_size);

    /* join rtp header + payload memory parts */
    outbuf = gst_buffer_append (outbuf, payloadbuf);

    GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf);
    GST_BUFFER_DTS (outbuf) = GST_BUFFER_DTS (buf);

    /* and add to list */
    if (list != NULL)
      gst_buffer_list_insert (list, -1, outbuf);

    offset += payload_size;
  }

done:

  gst_buffer_unmap (buf, &map);
  gst_buffer_unref (buf);

  if (list != NULL)
    ret = gst_rtp_base_payload_push_list (basepayload, list);
  else if (outbuf != NULL)
    ret = gst_rtp_base_payload_push (basepayload, outbuf);

  return ret;

/* ERRORS */
bad_input:
  {
    GST_ERROR_OBJECT (pay, "Input doesn't look like a KLV packet, ignoring");
    goto done;
  }
}
Пример #21
0
/**
 * gst_v4l2_buffer_pool_process:
 * @bpool: a #GstBufferPool
 * @buf: a #GstBuffer, maybe be replaced
 *
 * Process @buf in @bpool. For capture devices, this functions fills @buf with
 * data from the device. For output devices, this functions send the contents of
 * @buf to the device for playback.
 *
 * Returns: %GST_FLOW_OK on success.
 */
GstFlowReturn
gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstBufferPool *bpool = GST_BUFFER_POOL_CAST (pool);
  GstV4l2Object *obj = pool->obj;

  GST_DEBUG_OBJECT (pool, "process buffer %p", buf);

  g_return_val_if_fail (gst_buffer_pool_is_active (bpool), GST_FLOW_ERROR);

  if (GST_BUFFER_POOL_IS_FLUSHING (pool))
    return GST_FLOW_FLUSHING;

  switch (obj->type) {
    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
    case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
      /* capture */
      switch (obj->mode) {
        case GST_V4L2_IO_RW:
          /* capture into the buffer */
          ret = gst_v4l2_do_read (pool, *buf);
          break;

        case GST_V4L2_IO_MMAP:
        case GST_V4L2_IO_DMABUF:
        {
          GstBuffer *tmp;

          if ((*buf)->pool == bpool) {
            if (gst_buffer_get_size (*buf) == 0)
              goto eos;

            /* start copying buffers when we are running low on buffers */
            if (g_atomic_int_get (&pool->num_queued) < pool->copy_threshold) {
              GstBuffer *copy;

              if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) {

                if (gst_buffer_pool_acquire_buffer (bpool, &copy,
                        NULL) == GST_FLOW_OK) {
                  gst_v4l2_buffer_pool_release_buffer (bpool, copy);
                  goto done;
                }
              }

              /* copy the buffer */
              copy = gst_buffer_copy_region (*buf,
                  GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP, 0, -1);
              GST_LOG_OBJECT (pool, "copy buffer %p->%p", *buf, copy);

              /* and requeue so that we can continue capturing */
              gst_buffer_unref (*buf);
              *buf = copy;
            }

            /* nothing, data was inside the buffer when we did _acquire() */
            goto done;
          }

          /* buffer not from our pool, grab a frame and copy it into the target */
          if ((ret = gst_v4l2_buffer_pool_dqbuf (pool, &tmp)) != GST_FLOW_OK)
            goto done;

          /* An empty buffer on capture indicates the end of stream */
          if (gst_buffer_get_size (tmp) == 0) {
            gst_v4l2_buffer_pool_release_buffer (bpool, tmp);
            goto eos;
          }

          ret = gst_v4l2_buffer_pool_copy_buffer (pool, *buf, tmp);

          /* an queue the buffer again after the copy */
          gst_v4l2_buffer_pool_release_buffer (bpool, tmp);

          if (ret != GST_FLOW_OK)
            goto copy_failed;
          break;
        }

        case GST_V4L2_IO_USERPTR:
        {
          struct UserPtrData *data;

          /* Replace our buffer with downstream allocated buffer */
          data = gst_mini_object_steal_qdata (GST_MINI_OBJECT (*buf),
              GST_V4L2_IMPORT_QUARK);
          gst_buffer_replace (buf, data->buffer);
          _unmap_userptr_frame (data);
          break;
        }

        case GST_V4L2_IO_DMABUF_IMPORT:
        {
          GstBuffer *tmp;

          /* Replace our buffer with downstream allocated buffer */
          tmp = gst_mini_object_steal_qdata (GST_MINI_OBJECT (*buf),
              GST_V4L2_IMPORT_QUARK);
          gst_buffer_replace (buf, tmp);
          gst_buffer_unref (tmp);
          break;
        }

        default:
          g_assert_not_reached ();
          break;
      }
      break;

    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
      /* playback */
      switch (obj->mode) {
        case GST_V4L2_IO_RW:
          /* FIXME, do write() */
          GST_WARNING_OBJECT (pool, "implement write()");
          break;

        case GST_V4L2_IO_USERPTR:
        case GST_V4L2_IO_DMABUF_IMPORT:
        case GST_V4L2_IO_DMABUF:
        case GST_V4L2_IO_MMAP:
        {
          GstBuffer *to_queue = NULL;
          GstV4l2MemoryGroup *group;
          gint index;

          if ((*buf)->pool != bpool)
            goto copying;

          if (!gst_v4l2_is_buffer_valid (*buf, &group))
            goto copying;

          index = group->buffer.index;

          GST_LOG_OBJECT (pool, "processing buffer %i from our pool", index);

          index = group->buffer.index;
          if (pool->buffers[index] != NULL) {
            GST_LOG_OBJECT (pool, "buffer %i already queued, copying", index);
            goto copying;
          }

          /* we can queue directly */
          to_queue = gst_buffer_ref (*buf);

        copying:
          if (to_queue == NULL) {
            GstBufferPoolAcquireParams params = { 0 };

            GST_LOG_OBJECT (pool, "alloc buffer from our pool");

            /* this can return EOS if all buffers are outstanding which would
             * be strange because we would expect the upstream element to have
             * allocated them and returned to us.. */
            params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
            ret = gst_buffer_pool_acquire_buffer (bpool, &to_queue, &params);
            if (ret != GST_FLOW_OK)
              goto acquire_failed;

            ret = gst_v4l2_buffer_pool_prepare_buffer (pool, to_queue, *buf);
            if (ret != GST_FLOW_OK) {
              gst_buffer_unref (to_queue);
              goto prepare_failed;
            }
          }

          if ((ret = gst_v4l2_buffer_pool_qbuf (pool, to_queue)) != GST_FLOW_OK)
            goto queue_failed;

          /* if we are not streaming yet (this is the first buffer, start
           * streaming now */
          if (!gst_v4l2_buffer_pool_streamon (pool)) {
            /* don't check return value because qbuf would have failed */
            gst_v4l2_is_buffer_valid (to_queue, &group);

            /* qbuf has taken the ref of the to_queue buffer but we are no in
             * streaming state, so the flush logic won't be performed.
             * To avoid leaks, flush the allocator and restore the queued
             * buffer as non-queued */
            gst_v4l2_allocator_flush (pool->vallocator);

            pool->buffers[group->buffer.index] = NULL;

            gst_mini_object_set_qdata (GST_MINI_OBJECT (to_queue),
                GST_V4L2_IMPORT_QUARK, NULL, NULL);
            gst_buffer_unref (to_queue);
            g_atomic_int_add (&pool->num_queued, -1);
            goto start_failed;
          }

          if (g_atomic_int_get (&pool->num_queued) >= pool->min_latency) {
            GstBuffer *out;
            /* all buffers are queued, try to dequeue one and release it back
             * into the pool so that _acquire can get to it again. */
            ret = gst_v4l2_buffer_pool_dqbuf (pool, &out);
            if (ret == GST_FLOW_OK)
              /* release the rendered buffer back into the pool. This wakes up any
               * thread waiting for a buffer in _acquire(). */
              gst_buffer_unref (out);
          }
          break;
        }
        default:
          g_assert_not_reached ();
          break;
      }
      break;
    default:
      g_assert_not_reached ();
      break;
  }
done:
  return ret;

  /* ERRORS */
copy_failed:
  {
    GST_ERROR_OBJECT (pool, "failed to copy buffer");
    return ret;
  }
eos:
  {
    GST_DEBUG_OBJECT (pool, "end of stream reached");
    return GST_FLOW_EOS;
  }
acquire_failed:
  {
    if (ret == GST_FLOW_FLUSHING)
      GST_DEBUG_OBJECT (pool, "flushing");
    else
      GST_WARNING_OBJECT (pool, "failed to acquire a buffer: %s",
          gst_flow_get_name (ret));
    return ret;
  }
prepare_failed:
  {
    GST_ERROR_OBJECT (pool, "failed to prepare data");
    return ret;
  }
queue_failed:
  {
    GST_ERROR_OBJECT (pool, "failed to queue buffer");
    return ret;
  }
start_failed:
  {
    GST_ERROR_OBJECT (pool, "failed to start streaming");
    return GST_FLOW_ERROR;
  }
}
Пример #22
0
static GstFlowReturn
gst_opus_parse_handle_frame (GstBaseParse * base,
    GstBaseParseFrame * frame, gint * skip)
{
  GstOpusParse *parse;
  guint8 *data;
  gsize size;
  guint32 packet_size;
  int ret = FALSE;
  const unsigned char *frames[48];
  unsigned char toc;
  short frame_sizes[48];
  int payload_offset;
  int packet_offset = 0;
  gboolean is_header, is_idheader, is_commentheader;
  GstMapInfo map;

  parse = GST_OPUS_PARSE (base);

  *skip = -1;

  gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
  data = map.data;
  size = map.size;
  GST_DEBUG_OBJECT (parse,
      "Checking for frame, %" G_GSIZE_FORMAT " bytes in buffer", size);

  /* check for headers */
  is_idheader = gst_opus_header_is_id_header (frame->buffer);
  is_commentheader = gst_opus_header_is_comment_header (frame->buffer);
  is_header = is_idheader || is_commentheader;

  if (!is_header) {
    int nframes;

    /* Next, check if there's an Opus packet there */
    nframes =
        opus_packet_parse (data, size, &toc, frames, frame_sizes,
        &payload_offset);

    if (nframes < 0) {
      /* Then, check for the test vector framing */
      GST_DEBUG_OBJECT (parse,
          "No Opus packet found, trying test vector framing");
      if (size < 4) {
        GST_DEBUG_OBJECT (parse, "Too small");
        goto beach;
      }
      packet_size = GST_READ_UINT32_BE (data);
      GST_DEBUG_OBJECT (parse, "Packet size: %u bytes", packet_size);
      if (packet_size > MAX_PAYLOAD_BYTES) {
        GST_DEBUG_OBJECT (parse, "Too large");
        goto beach;
      }
      if (packet_size > size - 4) {
        GST_DEBUG_OBJECT (parse, "Truncated");
        goto beach;
      }
      nframes =
          opus_packet_parse (data + 8, packet_size, &toc, frames, frame_sizes,
          &payload_offset);
      if (nframes < 0) {
        GST_DEBUG_OBJECT (parse, "No test vector framing either");
        goto beach;
      }

      packet_offset = 8;

      /* for ad hoc framing, heed the framing, so we eat any padding */
      payload_offset = packet_size;
    } else {
      /* Add up all the frame sizes found */
      int f;
      for (f = 0; f < nframes; ++f)
        payload_offset += frame_sizes[f];
    }
  }

  if (is_header) {
    *skip = 0;
  } else {
    *skip = packet_offset;
    size = payload_offset;
  }

  GST_DEBUG_OBJECT (parse,
      "Got Opus packet at offset %d, %" G_GSIZE_FORMAT " bytes", *skip, size);
  ret = TRUE;

beach:
  gst_buffer_unmap (frame->buffer, &map);

  /* convert old style result to new one */
  if (!ret) {
    if (*skip < 0)
      *skip = 1;
    return GST_FLOW_OK;
  }

  /* always skip first if needed */
  if (*skip > 0)
    return GST_FLOW_OK;

  /* normalize again */
  if (*skip < 0)
    *skip = 0;

  /* not enough */
  if (size > map.size)
    return GST_FLOW_OK;

  /* FIXME some day ... should not mess with buffer itself */
  if (!parse->got_headers) {
    gst_buffer_replace (&frame->buffer,
        gst_buffer_copy_region (frame->buffer, GST_BUFFER_COPY_ALL, 0, size));
    gst_buffer_unref (frame->buffer);
  }

  ret = gst_opus_parse_parse_frame (base, frame);

  if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
    ret = GST_FLOW_OK;
  }
  if (ret == GST_FLOW_OK)
    ret = gst_base_parse_finish_frame (base, frame, size);

  return ret;
}
Пример #23
0
static GstFlowReturn
gst_gio_base_src_create (GstBaseSrc * base_src, guint64 offset, guint size,
    GstBuffer ** buf_return)
{
  GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
  GstBuffer *buf;
  GstFlowReturn ret = GST_FLOW_OK;

  g_return_val_if_fail (G_IS_INPUT_STREAM (src->stream), GST_FLOW_ERROR);

  /* If we have the requested part in our cache take a subbuffer of that,
   * otherwise fill the cache again with at least 4096 bytes from the
   * requested offset and return a subbuffer of that.
   *
   * We need caching because every read/seek operation will need to go
   * over DBus if our backend is GVfs and this is painfully slow. */
  if (src->cache && offset >= GST_BUFFER_OFFSET (src->cache) &&
      offset + size <= GST_BUFFER_OFFSET_END (src->cache)) {
    GST_DEBUG_OBJECT (src, "Creating subbuffer from cached buffer: offset %"
        G_GUINT64_FORMAT " length %u", offset, size);

    buf = gst_buffer_copy_region (src->cache, GST_BUFFER_COPY_ALL,
        offset - GST_BUFFER_OFFSET (src->cache), size);

    GST_BUFFER_OFFSET (buf) = offset;
    GST_BUFFER_OFFSET_END (buf) = offset + size;
  } else {
    guint cachesize = MAX (4096, size);
    GstMapInfo map;
    gssize read, res;
    gboolean success, eos;
    GError *err = NULL;

    if (src->cache) {
      gst_buffer_unref (src->cache);
      src->cache = NULL;
    }

    if (G_UNLIKELY (offset != src->position)) {
      if (!GST_GIO_STREAM_IS_SEEKABLE (src->stream))
        return GST_FLOW_NOT_SUPPORTED;

      GST_DEBUG_OBJECT (src, "Seeking to position %" G_GUINT64_FORMAT, offset);
      ret = gst_gio_seek (src, G_SEEKABLE (src->stream), offset, src->cancel);

      if (ret == GST_FLOW_OK)
        src->position = offset;
      else
        return ret;
    }

    src->cache = gst_buffer_new_and_alloc (cachesize);
    if (G_UNLIKELY (src->cache == NULL)) {
      GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", cachesize);
      return GST_FLOW_ERROR;
    }

    GST_LOG_OBJECT (src, "Reading %u bytes from offset %" G_GUINT64_FORMAT,
        cachesize, offset);

    /* GIO sometimes gives less bytes than requested although
     * it's not at the end of file. SMB for example only
     * supports reads up to 64k. So we loop here until we get at
     * at least the requested amount of bytes or a read returns
     * nothing. */
    gst_buffer_map (src->cache, &map, GST_MAP_WRITE);
    read = 0;
    while (size - read > 0 && (res =
            g_input_stream_read (G_INPUT_STREAM (src->stream),
                map.data + read, cachesize - read, src->cancel, &err)) > 0) {
      read += res;
    }
    gst_buffer_unmap (src->cache, &map);

    success = (read >= 0);
    eos = (cachesize > 0 && read == 0);

    if (!success && !gst_gio_error (src, "g_input_stream_read", &err, &ret)) {
      GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
          ("Could not read from stream: %s", err->message));
      g_clear_error (&err);
    }

    if (success && !eos) {
      src->position += read;

      GST_BUFFER_OFFSET (src->cache) = offset;
      GST_BUFFER_OFFSET_END (src->cache) = offset + read;

      GST_DEBUG_OBJECT (src, "Read successful");
      GST_DEBUG_OBJECT (src, "Creating subbuffer from new "
          "cached buffer: offset %" G_GUINT64_FORMAT " length %u", offset,
          size);

      buf =
          gst_buffer_copy_region (src->cache, GST_BUFFER_COPY_ALL, 0, MIN (size,
              read));

      GST_BUFFER_OFFSET (buf) = offset;
      GST_BUFFER_OFFSET_END (buf) = offset + MIN (size, read);
    } else {
      GST_DEBUG_OBJECT (src, "Read not successful");
      gst_buffer_unref (src->cache);
      src->cache = NULL;
      buf = NULL;
    }

    if (eos)
      ret = GST_FLOW_EOS;
  }

  *buf_return = buf;

  return ret;
}
Пример #24
0
static GstFlowReturn
gst_ac3_parse_chain_priv (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
  GstAc3Parse *ac3parse = GST_AC3_PARSE (parent);
  GstFlowReturn ret;
  gsize size;
  guint8 data[2];
  gint offset;
  gint len;
  GstBuffer *subbuf;
  gint first_access;

  size = gst_buffer_get_size (buf);
  if (size < 2)
    goto not_enough_data;

  gst_buffer_extract (buf, 0, data, 2);
  first_access = (data[0] << 8) | data[1];

  /* Skip the first_access header */
  offset = 2;

  if (first_access > 1) {
    /* Length of data before first_access */
    len = first_access - 1;

    if (len <= 0 || offset + len > size)
      goto bad_first_access_parameter;

    subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len);
    GST_BUFFER_DTS (subbuf) = GST_CLOCK_TIME_NONE;
    GST_BUFFER_PTS (subbuf) = GST_CLOCK_TIME_NONE;
    ret = ac3parse->baseparse_chainfunc (pad, parent, subbuf);
    if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
      gst_buffer_unref (buf);
      goto done;
    }

    offset += len;
    len = size - offset;

    if (len > 0) {
      subbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset, len);
      GST_BUFFER_PTS (subbuf) = GST_BUFFER_PTS (buf);
      GST_BUFFER_DTS (subbuf) = GST_BUFFER_DTS (buf);

      ret = ac3parse->baseparse_chainfunc (pad, parent, subbuf);
    }
    gst_buffer_unref (buf);
  } else {
    /* first_access = 0 or 1, so if there's a timestamp it applies to the first byte */
    subbuf =
        gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset,
        size - offset);
    GST_BUFFER_PTS (subbuf) = GST_BUFFER_PTS (buf);
    GST_BUFFER_DTS (subbuf) = GST_BUFFER_DTS (buf);
    gst_buffer_unref (buf);
    ret = ac3parse->baseparse_chainfunc (pad, parent, subbuf);
  }

done:
  return ret;

/* ERRORS */
not_enough_data:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (ac3parse), STREAM, FORMAT, (NULL),
        ("Insufficient data in buffer. Can't determine first_acess"));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
bad_first_access_parameter:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (ac3parse), STREAM, FORMAT, (NULL),
        ("Bad first_access parameter (%d) in buffer", first_access));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
}