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