static GstFlowReturn gst_fd_sink_render_buffers (GstFdSink * sink, GstBuffer ** buffers, guint num_buffers, guint8 * mem_nums, guint total_mems) { GstFlowReturn ret; guint64 skip = 0; for (;;) { guint64 bytes_written = 0; ret = gst_writev_buffers (GST_OBJECT_CAST (sink), sink->fd, sink->fdset, buffers, num_buffers, mem_nums, total_mems, &bytes_written, skip); sink->bytes_written += bytes_written; sink->current_pos += bytes_written; skip += bytes_written; if (!sink->unlock) break; ret = gst_base_sink_wait_preroll (GST_BASE_SINK (sink)); if (ret != GST_FLOW_OK) return ret; } return ret; }
static GstFlowReturn gst_shout2send_render (GstBaseSink * basesink, GstBuffer * buf) { GstShout2send *sink; glong ret; gint delay; GstFlowReturn fret; GstMapInfo map; sink = GST_SHOUT2SEND (basesink); /* presumably we connect here because we need to know the format before * we can set up the connection, which we don't know yet in _start() */ if (!sink->connected) { if (!gst_shout2send_connect (sink)) return GST_FLOW_ERROR; } delay = shout_delay (sink->conn); if (delay > 0) { GST_LOG_OBJECT (sink, "waiting %d msec", delay); if (gst_poll_wait (sink->timer, GST_MSECOND * delay) == -1) { GST_LOG_OBJECT (sink, "unlocked"); fret = gst_base_sink_wait_preroll (basesink); if (fret != GST_FLOW_OK) return fret; } } else { GST_LOG_OBJECT (sink, "we're %d msec late", -delay); } gst_buffer_map (buf, &map, GST_MAP_READ); GST_LOG_OBJECT (sink, "sending %u bytes of data", (guint) map.size); ret = shout_send (sink->conn, map.data, map.size); gst_buffer_unmap (buf, &map); if (ret != SHOUTERR_SUCCESS) goto send_error; return GST_FLOW_OK; /* ERRORS */ send_error: { GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), ("shout_send() failed: %s", shout_get_error (sink->conn))); g_signal_emit (sink, gst_shout2send_signals[SIGNAL_CONNECTION_PROBLEM], 0, shout_get_errno (sink->conn)); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstShmSink *self = GST_SHM_SINK (bsink); int rv = 0; GstMapInfo map; gboolean need_new_memory = FALSE; GstFlowReturn ret = GST_FLOW_OK; GstMemory *memory = NULL; GstBuffer *sendbuf = NULL; gsize written_bytes; GST_OBJECT_LOCK (self); while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) GST_OBJECT_LOCK (self); else return ret; } } while (!gst_shm_sink_can_render (self, GST_BUFFER_TIMESTAMP (buf))) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) GST_OBJECT_LOCK (self); else return ret; } } if (gst_buffer_n_memory (buf) > 1) { GST_LOG_OBJECT (self, "Buffer %p has %d GstMemory, we only support a single" " one, need to do a memcpy", buf, gst_buffer_n_memory (buf)); need_new_memory = TRUE; } else { memory = gst_buffer_peek_memory (buf, 0); if (memory->allocator != GST_ALLOCATOR (self->allocator)) { need_new_memory = TRUE; GST_LOG_OBJECT (self, "Memory in buffer %p was not allocated by " "%" GST_PTR_FORMAT ", will memcpy", buf, memory->allocator); } } if (need_new_memory) { if (gst_buffer_get_size (buf) > sp_writer_get_max_buf_size (self->pipe)) { gsize area_size = sp_writer_get_max_buf_size (self->pipe); GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT, (NULL), ("Shared memory area of size %" G_GSIZE_FORMAT " is smaller than" "buffer of size %" G_GSIZE_FORMAT, area_size, gst_buffer_get_size (buf))); goto error; } while ((memory = gst_shm_sink_allocator_alloc_locked (self->allocator, gst_buffer_get_size (buf), &self->params)) == NULL) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) GST_OBJECT_LOCK (self); else return ret; } } while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) { GST_OBJECT_LOCK (self); } else { gst_memory_unref (memory); return ret; } } } if (!gst_memory_map (memory, &map, GST_MAP_WRITE)) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to map memory")); goto error; } GST_DEBUG_OBJECT (self, "Copying %" G_GSIZE_FORMAT " bytes into map of size %" G_GSIZE_FORMAT " bytes.", gst_buffer_get_size (buf), map.size); written_bytes = gst_buffer_extract (buf, 0, map.data, map.size); GST_DEBUG_OBJECT (self, "Copied %" G_GSIZE_FORMAT " bytes.", written_bytes); gst_memory_unmap (memory, &map); sendbuf = gst_buffer_new (); if (!gst_buffer_copy_into (sendbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1)) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to copy data into send buffer")); gst_buffer_unref (sendbuf); goto error; } gst_buffer_append_memory (sendbuf, memory); } else { sendbuf = gst_buffer_ref (buf); } if (!gst_buffer_map (sendbuf, &map, GST_MAP_READ)) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to map data into send buffer")); goto error; } /* Make the memory readonly as of now as we've sent it to the other side * We know it's not mapped for writing anywhere as we just mapped it for * reading */ rv = sp_writer_send_buf (self->pipe, (char *) map.data, map.size, sendbuf); if (rv == -1) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to send data over SHM")); gst_buffer_unmap (sendbuf, &map); goto error; } gst_buffer_unmap (sendbuf, &map); GST_OBJECT_UNLOCK (self); if (rv == 0) { GST_DEBUG_OBJECT (self, "No clients connected, unreffing buffer"); gst_buffer_unref (sendbuf); } return ret; error: GST_OBJECT_UNLOCK (self); return GST_FLOW_ERROR; }
static GstFlowReturn gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer) { GstFlowReturn ret; GstAppSink *appsink = GST_APP_SINK_CAST (psink); GstAppSinkPrivate *priv = appsink->priv; gboolean emit; restart: g_mutex_lock (&priv->mutex); if (priv->flushing) goto flushing; /* queue holding caps event might have been FLUSHed, * but caps state still present in pad caps */ if (G_UNLIKELY (!priv->last_caps && gst_pad_has_current_caps (GST_BASE_SINK_PAD (psink)))) { priv->last_caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (psink)); GST_DEBUG_OBJECT (appsink, "activating pad caps %" GST_PTR_FORMAT, priv->last_caps); } GST_DEBUG_OBJECT (appsink, "pushing render buffer %p on queue (%d)", buffer, priv->num_buffers); while (priv->max_buffers > 0 && priv->num_buffers >= priv->max_buffers) { if (priv->drop) { GstBuffer *old; /* we need to drop the oldest buffer and try again */ if ((old = dequeue_buffer (appsink))) { GST_DEBUG_OBJECT (appsink, "dropping old buffer %p", old); gst_buffer_unref (old); } } else { GST_DEBUG_OBJECT (appsink, "waiting for free space, length %d >= %d", priv->num_buffers, priv->max_buffers); if (priv->unlock) { /* we are asked to unlock, call the wait_preroll method */ g_mutex_unlock (&priv->mutex); if ((ret = gst_base_sink_wait_preroll (psink)) != GST_FLOW_OK) goto stopping; /* we are allowed to continue now */ goto restart; } /* wait for a buffer to be removed or flush */ g_cond_wait (&priv->cond, &priv->mutex); if (priv->flushing) goto flushing; } } /* we need to ref the buffer when pushing it in the queue */ g_queue_push_tail (priv->queue, gst_buffer_ref (buffer)); priv->num_buffers++; g_cond_signal (&priv->cond); emit = priv->emit_signals; g_mutex_unlock (&priv->mutex); if (priv->callbacks.new_sample) { ret = priv->callbacks.new_sample (appsink, priv->user_data); } else { ret = GST_FLOW_OK; if (emit) g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_SAMPLE], 0, &ret); } return ret; flushing: { GST_DEBUG_OBJECT (appsink, "we are flushing"); g_mutex_unlock (&priv->mutex); return GST_FLOW_FLUSHING; } stopping: { GST_DEBUG_OBJECT (appsink, "we are stopping"); return ret; } }