コード例 #1
0
bool nvxio::GStreamerBaseRenderImpl::flush()
{
    if (!pipeline)
        return false;

    glfwMakeContextCurrent(window_);

    if (glfwWindowShouldClose(window_))
        return false;

    gl_->PixelStorei(GL_PACK_ALIGNMENT, 1);
    gl_->PixelStorei(GL_PACK_ROW_LENGTH, wndWidth_);

    {
        GstClockTime duration = GST_SECOND / (double)GSTREAMER_DEFAULT_FPS;
        GstClockTime timestamp = num_frames * duration;

#if GST_VERSION_MAJOR == 0
        GstBuffer * buffer = gst_buffer_try_new_and_alloc(wndHeight_ * wndWidth_ * 4);
        if (!buffer)
        {
            NVXIO_PRINT("Cannot create GStreamer buffer");
            FinalizeGStreamerPipeline();
            return false;
        }

        gl_->ReadPixels(0, 0, wndWidth_, wndHeight_, GL_RGBA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buffer));

        GST_BUFFER_TIMESTAMP(buffer) = timestamp;
        if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer))
            NVXIO_PRINT("Failed to setup timestamp");
#else
        GstBuffer * buffer = gst_buffer_new_allocate(NULL, wndHeight_ * wndWidth_ * 4, NULL);

        GstMapInfo info;
        gst_buffer_map(buffer, &info, GST_MAP_READ);
        gl_->ReadPixels(0, 0, wndWidth_, wndHeight_, GL_RGBA, GL_UNSIGNED_BYTE, info.data);
        gst_buffer_unmap(buffer, &info);

        GST_BUFFER_PTS(buffer) = timestamp;
        if (!GST_BUFFER_PTS_IS_VALID(buffer))
            NVXIO_PRINT("Failed to setup PTS");

        GST_BUFFER_DTS(buffer) = timestamp;
        if (!GST_BUFFER_DTS_IS_VALID(buffer))
            NVXIO_PRINT("Failed to setup DTS");
#endif
        GST_BUFFER_DURATION(buffer) = duration;
        if (!GST_BUFFER_DURATION_IS_VALID(buffer))
            NVXIO_PRINT("Failed to setup duration");

        GST_BUFFER_OFFSET(buffer) = num_frames++;
        if (!GST_BUFFER_OFFSET_IS_VALID(buffer))
            NVXIO_PRINT("Failed to setup offset");

        if (gst_app_src_push_buffer(appsrc, buffer) != GST_FLOW_OK)
        {
            NVXIO_PRINT("Error pushing buffer to GStreamer pipeline");
            FinalizeGStreamerPipeline();
            return false;
        }
    }

    // reset state
    gl_->PixelStorei(GL_PACK_ALIGNMENT, 4);
    gl_->PixelStorei(GL_PACK_ROW_LENGTH, 0);

    glfwSwapBuffers(window_);

    clearGlBuffer();

    return true;
}
コード例 #2
0
ファイル: gstfilesrc.c プロジェクト: spunktsch/svtplayer
static GstFlowReturn
gst_file_src_create_read (GstFileSrc * src, guint64 offset, guint length,
    GstBuffer ** buffer)
{
  int ret;
  GstBuffer *buf;

  if (G_UNLIKELY (src->read_position != offset)) {
    off_t res;

    res = lseek (src->fd, offset, SEEK_SET);
    if (G_UNLIKELY (res < 0 || res != offset))
      goto seek_failed;

    src->read_position = offset;
  }

  buf = gst_buffer_try_new_and_alloc (length);
  if (G_UNLIKELY (buf == NULL && length > 0)) {
    GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", length);
    return GST_FLOW_ERROR;
  }

  /* No need to read anything if length is 0 */
  if (length > 0) {
    GST_LOG_OBJECT (src, "Reading %d bytes at offset 0x%" G_GINT64_MODIFIER "x",
        length, offset);
    ret = read (src->fd, GST_BUFFER_DATA (buf), length);
    if (G_UNLIKELY (ret < 0))
      goto could_not_read;

    /* seekable regular files should have given us what we expected */
    if (G_UNLIKELY ((guint) ret < length && src->seekable))
      goto unexpected_eos;

    /* other files should eos if they read 0 and more was requested */
    if (G_UNLIKELY (ret == 0 && length > 0))
      goto eos;

    length = ret;
    GST_BUFFER_SIZE (buf) = length;
    GST_BUFFER_OFFSET (buf) = offset;
    GST_BUFFER_OFFSET_END (buf) = offset + length;

    src->read_position += length;
  }

  *buffer = buf;

  return GST_FLOW_OK;

  /* ERROR */
seek_failed:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
    return GST_FLOW_ERROR;
  }
could_not_read:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
unexpected_eos:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("unexpected end of file."));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
eos:
  {
    GST_DEBUG ("non-regular file hits EOS");
    gst_buffer_unref (buf);
    return GST_FLOW_UNEXPECTED;
  }
}
コード例 #3
0
static GstFlowReturn gst_devsound_src_create(GstBaseSrc *src, guint64 offset,
        guint size, GstBuffer **buf)
    {
    GstDevsoundSrc *dsrc= GST_DEVSOUND_SRC(src);
    int bufferpos=0;
    int ret = KErrNone;
    
    if(!g_queue_get_length(dataqueue) && (dsrc->eosreceived == TRUE))
        {
        pthread_mutex_lock(&(create_mutex1));
        pthread_cond_signal(&(create_condition1));
        pthread_mutex_unlock(&(create_mutex1));
        post_symbian_error( src,KErrCancel );
        return GST_FLOW_UNEXPECTED;
        }
    
    //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "gst_devsound_src_create ENTER ");

    //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "Before Buffer Alloc in CREATE ",NULL);
    *buf = gst_buffer_try_new_and_alloc(size);
    //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "AFter Buffer Alloc in CREATE ",NULL);
    if(*buf == NULL)
    {
        post_symbian_error( src,KErrNoMemory );
        return GST_FLOW_UNEXPECTED;
    }        
    
    while (size > 0)
        {
        if (dataleft >= size)
            {
            // if there is some data left in the popped buffer previously whose size
            // is more then the buffer which is incoming fresh to get filled, fill it
            //here. and if the data left in the popped buffer is 0, then unref it
            //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "dataleft >=size in CREATE ", NULL);
            memcpy(GST_BUFFER_DATA(*buf)+bufferpos,GST_BUFFER_DATA(popBuffer)+dataCopied,size);
            bufferpos+=size;
            dataCopied += size;
            dataleft = GST_BUFFER_SIZE(popBuffer) - dataCopied;
            size = 0;
            if (dataleft == 0)
                {
                dataCopied = 0;
                gst_buffer_unref(popBuffer);
                popBuffer = NULL;
                }
            }
        else
            {
            // if the dataleft in the popped buffer is greater then 0 and  less then
            // the size of data needed for the fresh buffer. copy the remaining data
            // from the popped buffer and then unref it.
            if (dataleft > 0)
                {
                //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "dataleft >0 in CREATE ",NULL);
                memcpy(GST_BUFFER_DATA(*buf)+bufferpos,GST_BUFFER_DATA(popBuffer)+dataCopied,dataleft);
                size -= dataleft;
                bufferpos += dataleft;
                dataCopied = 0;
                dataleft = 0;
                gst_buffer_unref(popBuffer);
                popBuffer = NULL;
                }

            // we wait here if the dataqueue length is 0 and we need data
            // to be filled in the queue from the DevSound Thread
            if (!g_queue_get_length(dataqueue))
                {
                //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "Before WAIT in CREATE ",NULL);
                if(dsrc->eosreceived == TRUE)
                    {
                    post_symbian_error( src,KErrCancel );
                    return GST_FLOW_UNEXPECTED;
                    }
                else
                    {
                    cmd = RECORDING;
                    return_error = KErrNone;
                    pthread_mutex_lock(&(create_mutex1));
                    pthread_cond_signal(&(create_condition1));
                    pthread_mutex_unlock(&(create_mutex1));
                    
                    pthread_mutex_lock(&(create_mutex1));
                    pthread_cond_wait(&(create_condition1), &(create_mutex1));
                    ret = return_error;
                    pthread_mutex_unlock(&(create_mutex1));
                    }
                //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "AFTER WAIT in CREATE ",NULL);
                }
            if( ret )
            { 
                post_symbian_error( src,ret );
                return GST_FLOW_UNEXPECTED;
            }
            //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "Before POP in CREATE ",NULL);
            GST_OBJECT_LOCK(dsrc);
            popBuffer = (GstBuffer*)g_queue_pop_tail(dataqueue);
            GST_OBJECT_UNLOCK(dsrc);
           
            if(!popBuffer )
            {
                post_symbian_error( src,KErrNoMemory );
                return GST_FLOW_UNEXPECTED;
            }
            if(dsrc->firstTimeInit != kPlayed)
                {        
                dsrc->prevbuffersize = gst_base_src_get_blocksize(src);
                gst_base_src_set_blocksize (src, GST_BUFFER_SIZE(popBuffer));
                (*buf)->size = GST_BUFFER_SIZE(popBuffer);
                }
            // copy the data from the popped buffer based on how much of the incoming
            //buffer size is left to fill. we might have filled the fresh buffer somewhat
            // where the size of the fresh buffer is more then the data remaining in the
            // popped buffer.
            if (size < GST_BUFFER_SIZE(popBuffer))
                {
                //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "SIZE < POPBUFFER CREATE ",NULL);
                memcpy(GST_BUFFER_DATA(*buf)+ bufferpos,GST_BUFFER_DATA(popBuffer),size);
                bufferpos+=size;
                dataCopied = size;
                dataleft = GST_BUFFER_SIZE(popBuffer) - dataCopied;
                size = 0;
                }
            else
                {
                //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "SIZE >= POPBUFFER CREATE ",NULL);
                memcpy(GST_BUFFER_DATA(*buf)+ bufferpos,GST_BUFFER_DATA(popBuffer),GST_BUFFER_SIZE(popBuffer));
                bufferpos+=GST_BUFFER_SIZE(popBuffer);
                dataCopied = 0;
                dataleft = 0;
                size = size - GST_BUFFER_SIZE(popBuffer);
                }

            if (!dataleft)
                {
                gst_buffer_unref(popBuffer);
                popBuffer = NULL;
                }
            }
        if (dsrc->firstTimeInit == kPlayBufferPreRoll)
            {
            gst_base_src_set_blocksize (src, dsrc->prevbuffersize);
            dsrc->firstTimeInit = kPlayed;
            return GST_FLOW_OK;
            }
        
        if (dsrc->firstTimeInit == kPausedToPlaying)
            {
            dsrc->firstTimeInit = kPlayBufferPreRoll;
            return GST_FLOW_OK;
            }
       }
    //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "gst_devsound_src_create EXIT ",NULL);
    return GST_FLOW_OK;
    }
コード例 #4
0
ファイル: tags.c プロジェクト: Sandec/openjfx-8u-dev-rt
/**
 * gst_tag_image_data_to_image_buffer:
 * @image_data: the (encoded) image
 * @image_data_len: the length of the encoded image data at @image_data
 * @image_type: type of the image, or #GST_TAG_IMAGE_TYPE_UNDEFINED. Pass
 *     #GST_TAG_IMAGE_TYPE_NONE if no image type should be set at all (e.g.
 *     for preview images)
 *
 * Helper function for tag-reading plugins to create a #GstBuffer suitable to
 * add to a #GstTagList as an image tag (such as #GST_TAG_IMAGE or
 * #GST_TAG_PREVIEW_IMAGE) from the encoded image data and an (optional) image
 * type.
 *
 * Background: cover art and other images in tags are usually stored as a
 * blob of binary image data, often accompanied by a MIME type or some other
 * content type string (e.g. 'png', 'jpeg', 'jpg'). Sometimes there is also an
 * 'image type' to indicate what kind of image this is (e.g. front cover,
 * back cover, artist, etc.). The image data may also be an URI to the image
 * rather than the image itself.
 *
 * In GStreamer, image tags are #GstBuffer<!-- -->s containing the raw image
 * data, with the buffer caps describing the content type of the image
 * (e.g. image/jpeg, image/png, text/uri-list). The buffer caps may contain
 * an additional 'image-type' field of #GST_TYPE_TAG_IMAGE_TYPE to describe
 * the type of image (front cover, back cover etc.). #GST_TAG_PREVIEW_IMAGE
 * tags should not carry an image type, their type is already indicated via
 * the special tag name.
 *
 * This function will do various checks and typefind the encoded image
 * data (we can't trust the declared mime type).
 *
 * Returns: a newly-allocated image buffer for use in tag lists, or NULL
 *
 * Since: 0.10.20
 */
GstBuffer *
gst_tag_image_data_to_image_buffer (const guint8 * image_data,
    guint image_data_len, GstTagImageType image_type)
{
  const gchar *name;

  GstBuffer *image;

  GstCaps *caps;

  g_return_val_if_fail (image_data != NULL, NULL);
  g_return_val_if_fail (image_data_len > 0, NULL);
  g_return_val_if_fail (gst_tag_image_type_is_valid (image_type), NULL);

  GST_DEBUG ("image data len: %u bytes", image_data_len);

  /* allocate space for a NUL terminator for an uri too */
  image = gst_buffer_try_new_and_alloc (image_data_len + 1);
  if (image == NULL) {
    GST_WARNING ("failed to allocate buffer of %d for image", image_data_len);
    return NULL;
  }

  memcpy (GST_BUFFER_DATA (image), image_data, image_data_len);
  GST_BUFFER_DATA (image)[image_data_len] = '\0';

  /* Find GStreamer media type, can't trust declared type */
  caps = gst_type_find_helper_for_buffer (NULL, image, NULL);

  if (caps == NULL)
    goto no_type;

  GST_DEBUG ("Found GStreamer media type: %" GST_PTR_FORMAT, caps);

  /* sanity check: make sure typefound/declared caps are either URI or image */
  name = gst_structure_get_name (gst_caps_get_structure (caps, 0));

  if (!g_str_has_prefix (name, "image/") &&
      !g_str_has_prefix (name, "video/") &&
      !g_str_equal (name, "text/uri-list")) {
    GST_DEBUG ("Unexpected image type '%s', ignoring image frame", name);
    goto error;
  }

  /* Decrease size by 1 if we don't have an URI list
   * to keep the original size of the image
   */
  if (!g_str_equal (name, "text/uri-list"))
    GST_BUFFER_SIZE (image) = image_data_len;

  if (image_type != GST_TAG_IMAGE_TYPE_NONE) {
    GST_LOG ("Setting image type: %d", image_type);
    caps = gst_caps_make_writable (caps);
    gst_caps_set_simple (caps, "image-type", GST_TYPE_TAG_IMAGE_TYPE,
        image_type, NULL);
  }

  gst_buffer_set_caps (image, caps);
  gst_caps_unref (caps);
  return image;

/* ERRORS */
no_type:
  {
    GST_DEBUG ("Could not determine GStreamer media type, ignoring image");
    /* fall through */
  }
error:
  {
    if (image)
      gst_buffer_unref (image);
    if (caps)
      gst_caps_unref (caps);
    return NULL;
  }
}
コード例 #5
0
ファイル: gstfdsrc.c プロジェクト: JERUKA9/gstreamer
static GstFlowReturn
gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
{
  GstFdSrc *src;
  GstBuffer *buf;
  gssize readbytes;
  guint blocksize;
  GstClockTime timeout;

#ifndef HAVE_WIN32
  gboolean try_again;
  gint retval;
#endif

  src = GST_FD_SRC (psrc);

  if (src->timeout > 0) {
    timeout = src->timeout * GST_USECOND;
  } else {
    timeout = GST_CLOCK_TIME_NONE;
  }

#ifndef HAVE_WIN32
  do {
    try_again = FALSE;

    GST_LOG_OBJECT (src, "doing poll, timeout %" GST_TIME_FORMAT,
        GST_TIME_ARGS (src->timeout));

    retval = gst_poll_wait (src->fdset, timeout);
    GST_LOG_OBJECT (src, "poll returned %d", retval);

    if (G_UNLIKELY (retval == -1)) {
      if (errno == EINTR || errno == EAGAIN) {
        /* retry if interrupted */
        try_again = TRUE;
      } else if (errno == EBUSY) {
        goto stopped;
      } else {
        goto poll_error;
      }
    } else if (G_UNLIKELY (retval == 0)) {
      try_again = TRUE;
      /* timeout, post element message */
      gst_element_post_message (GST_ELEMENT_CAST (src),
          gst_message_new_element (GST_OBJECT_CAST (src),
              gst_structure_new ("GstFdSrcTimeout",
                  "timeout", G_TYPE_UINT64, src->timeout, NULL)));
    }
  } while (G_UNLIKELY (try_again));     /* retry if interrupted or timeout */
#endif

  blocksize = GST_BASE_SRC (src)->blocksize;

  /* create the buffer */
  buf = gst_buffer_try_new_and_alloc (blocksize);
  if (G_UNLIKELY (buf == NULL)) {
    GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", blocksize);
    return GST_FLOW_ERROR;
  }

  do {
    readbytes = read (src->fd, GST_BUFFER_DATA (buf), blocksize);
    GST_LOG_OBJECT (src, "read %" G_GSSIZE_FORMAT, readbytes);
  } while (readbytes == -1 && errno == EINTR);  /* retry if interrupted */

  if (readbytes < 0)
    goto read_error;

  if (readbytes == 0)
    goto eos;

  GST_BUFFER_OFFSET (buf) = src->curoffset;
  GST_BUFFER_SIZE (buf) = readbytes;
  GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
  src->curoffset += readbytes;

  GST_LOG_OBJECT (psrc, "Read buffer of size %" G_GSSIZE_FORMAT, readbytes);

  /* we're done, return the buffer */
  *outbuf = buf;

  return GST_FLOW_OK;

  /* ERRORS */
#ifndef HAVE_WIN32
poll_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("poll on file descriptor: %s.", g_strerror (errno)));
    GST_DEBUG_OBJECT (psrc, "Error during poll");
    return GST_FLOW_ERROR;
  }
stopped:
  {
    GST_DEBUG_OBJECT (psrc, "Poll stopped");
    return GST_FLOW_WRONG_STATE;
  }
#endif
eos:
  {
    GST_DEBUG_OBJECT (psrc, "Read 0 bytes. EOS.");
    gst_buffer_unref (buf);
    return GST_FLOW_UNEXPECTED;
  }
read_error:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("read on file descriptor: %s.", g_strerror (errno)));
    GST_DEBUG_OBJECT (psrc, "Error reading from fd");
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
}
コード例 #6
0
/*
 * Read a new buffer from src->reqoffset, takes care of events
 * and seeking and such.
 */
static GstFlowReturn
gst_gnome_vfs_src_create (GstBaseSrc * basesrc, guint64 offset, guint size,
    GstBuffer ** buffer)
{
  GnomeVFSResult res;
  GstBuffer *buf;
  GnomeVFSFileSize readbytes;
  guint8 *data;
  guint todo;
  GstGnomeVFSSrc *src;
  gboolean interrupted = FALSE;

  src = GST_GNOME_VFS_SRC (basesrc);

  GST_DEBUG ("now at %" G_GINT64_FORMAT ", reading from %" G_GUINT64_FORMAT
      ", size %u", src->curoffset, offset, size);

  /* seek if required */
  if (G_UNLIKELY (src->curoffset != offset)) {
    GST_DEBUG ("need to seek");
    if (src->seekable) {
      GST_DEBUG ("seeking to %" G_GUINT64_FORMAT, offset);
      res = gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_START, offset);
      if (res != GNOME_VFS_OK)
        goto seek_failed;
      src->curoffset = offset;
    } else {
      goto cannot_seek;
    }
  }

  buf = gst_buffer_try_new_and_alloc (size);
  if (G_UNLIKELY (buf == NULL)) {
    GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", size);
    return GST_FLOW_ERROR;
  }

  data = GST_BUFFER_DATA (buf);

  todo = size;
  while (!src->interrupted && todo > 0) {
    /* this can return less that we ask for */
    res =
        gnome_vfs_read_cancellable (src->handle, data, todo, &readbytes,
        src->context);

    if (G_UNLIKELY (res == GNOME_VFS_ERROR_CANCELLED)) {
      GST_DEBUG_OBJECT (src, "interrupted");

      /* Just take what we've so far gotten and return */
      size = size - todo;
      GST_BUFFER_SIZE (buf) = size;
      todo = 0;
      interrupted = TRUE;
      break;
    }

    if (G_UNLIKELY (res == GNOME_VFS_ERROR_EOF || (res == GNOME_VFS_OK
                && readbytes == 0)))
      goto eos;

    if (G_UNLIKELY (res != GNOME_VFS_OK))
      goto read_failed;

    if (readbytes < todo) {
      data = &data[readbytes];
      todo -= readbytes;
    } else {
      todo = 0;
    }
    GST_LOG ("  got size %" G_GUINT64_FORMAT, readbytes);
  }

  if (interrupted)
    goto interrupted;

  GST_BUFFER_OFFSET (buf) = src->curoffset;
  src->curoffset += size;

  /* we're done, return the buffer */
  *buffer = buf;

  return GST_FLOW_OK;

seek_failed:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL),
        ("Failed to seek to requested position %" G_GINT64_FORMAT ": %s",
            offset, gnome_vfs_result_to_string (res)));
    return GST_FLOW_ERROR;
  }
cannot_seek:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL),
        ("Requested seek from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT
            " on non-seekable stream", src->curoffset, offset));
    return GST_FLOW_ERROR;
  }
read_failed:
  {
    gst_buffer_unref (buf);
    GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
        ("Failed to read data: %s", gnome_vfs_result_to_string (res)));
    return GST_FLOW_ERROR;
  }
interrupted:
  {
    gst_buffer_unref (buf);
    return GST_FLOW_WRONG_STATE;
  }
eos:
  {
    gst_buffer_unref (buf);
    GST_DEBUG_OBJECT (src, "Reading data gave EOS");
    return GST_FLOW_UNEXPECTED;
  }
}
コード例 #7
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_create_sub (src->cache,
        offset - GST_BUFFER_OFFSET (src->cache), size);

    GST_BUFFER_OFFSET (buf) = offset;
    GST_BUFFER_OFFSET_END (buf) = offset + size;
    GST_BUFFER_SIZE (buf) = size;
  } else {
    guint cachesize = MAX (4096, size);

    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_try_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. */
    read = 0;
    while (size - read > 0 && (res =
            g_input_stream_read (G_INPUT_STREAM (src->stream),
                GST_BUFFER_DATA (src->cache) + read, cachesize - read,
                src->cancel, &err)) > 0) {
      read += res;
    }

    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_SIZE (src->cache) = 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_create_sub (src->cache, 0, MIN (size, read));

      GST_BUFFER_OFFSET (buf) = offset;
      GST_BUFFER_OFFSET_END (buf) = offset + MIN (size, read);
      GST_BUFFER_SIZE (buf) = 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_UNEXPECTED;
  }

  *buf_return = buf;

  return ret;
}
コード例 #8
0
psych_bool PsychAddAudioBufferToMovie(int moviehandle, unsigned int nrChannels, unsigned int nrSamples, double* buffer)
{
	PsychMovieWriterRecordType* pwriterRec = PsychGetMovieWriter(moviehandle, FALSE);

	GstFlowReturn       ret;
	float*              fwordptr;
	float               v;
	unsigned int        n, i;
	GstBuffer*          pushBuffer;
    
	// Child protection: Audio writing enabled for this movie?
	if (NULL == pwriterRec->ptbaudioappsrc) {
		PsychErrorExitMsg(PsychError_user, "Tried to add audio data to a movie which was created without an audio track.");
	}
    
	// nrChannels and nrSamples are already validated by high level code.
	// Just calculate total sample count and required buffer size:
	n = nrChannels * nrSamples;
    
	// Create GstBuffer for audio data:
	pushBuffer = gst_buffer_try_new_and_alloc(n * sizeof(float));

	// Out of memory condition!
	if (NULL == pushBuffer) {
		PsychErrorExitMsg(PsychError_outofMemory, "Out of memory when trying to add audio data to movie! (Part I)");
		return(FALSE);
	}

	// Double-check:
	if (NULL == GST_BUFFER_DATA(pushBuffer)) {
		PsychErrorExitMsg(PsychError_outofMemory, "Out of memory when trying to add audio data to movie! (Part II)");
		return(FALSE);
	}
    
	// Convert and copy sample data:
	fwordptr = (float*) GST_BUFFER_DATA(pushBuffer);
	for (i = 0; i < n; i++) {
		// Fetch and convert from double to float:
		v = (float) *(buffer++);;

		// Clip:
		if (v < -1.0) v = -1.0;
		if (v > +1.0) v = +1.0;

		// Push to float buffer:
		*(fwordptr++) = v; 
	}
    
	// Add encoded buffer to movie:
	g_signal_emit_by_name(pwriterRec->ptbaudioappsrc, "push-buffer", pushBuffer, &ret);

	// Unref it - it is now owned and memory managed by the pipeline:
	gst_buffer_unref(pushBuffer);
	pushBuffer = NULL;

	if (ret != GST_FLOW_OK) {
		// Oopsie! Error encountered - Abort.
		if (PsychPrefStateGet_Verbosity() > 0) printf("PTB-ERROR:In AddAudioBufferToMovie: Adding current audio buffer to moviehandle %i failed [push-buffer returned error code %i]!\n", moviehandle, (int) ret);
		return(FALSE);
	}

	// Do a bit of event processing for handling of potential GStreamer messages:
	PsychGSProcessMovieContext(pwriterRec->Context, FALSE);

	if (PsychPrefStateGet_Verbosity() > 5) printf("PTB-DEBUG:In AddAudioBufferToMovie: Added new audio buffer to moviehandle %i.\n", moviehandle);

	// Return success:
	return(TRUE);
}