static GstFlowReturn gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstShmSink *self = GST_SHM_SINK (bsink); int rv; GstMapInfo map; 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); return GST_FLOW_FLUSHING; } } 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); return GST_FLOW_FLUSHING; } } gst_buffer_map (buf, &map, GST_MAP_READ); rv = sp_writer_send_buf (self->pipe, (char *) map.data, map.size, GST_BUFFER_TIMESTAMP (buf)); gst_buffer_unmap (buf, &map); if (rv == -1) { ShmBlock *block = NULL; gchar *shmbuf = NULL; while ((block = sp_writer_alloc_block (self->pipe, gst_buffer_get_size (buf))) == NULL) { g_cond_wait (self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); return GST_FLOW_FLUSHING; } } while (self->wait_for_connection && !self->clients) { g_cond_wait (self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { sp_writer_free_block (block); GST_OBJECT_UNLOCK (self); return GST_FLOW_FLUSHING; } } shmbuf = sp_writer_block_get_buf (block); gst_buffer_extract (buf, 0, shmbuf, gst_buffer_get_size (buf)); sp_writer_send_buf (self->pipe, shmbuf, gst_buffer_get_size (buf), GST_BUFFER_TIMESTAMP (buf)); sp_writer_free_block (block); } GST_OBJECT_UNLOCK (self); return GST_FLOW_OK; }
static GstFlowReturn gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstShmSink *self = GST_SHM_SINK (bsink); int rv; 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); return GST_FLOW_WRONG_STATE; } } rv = sp_writer_send_buf (self->pipe, (char *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); if (rv == -1) { ShmBlock *block = NULL; gchar *shmbuf = NULL; while ((block = sp_writer_alloc_block (self->pipe, GST_BUFFER_SIZE (buf))) == NULL) { g_cond_wait (self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); return GST_FLOW_WRONG_STATE; } } while (self->wait_for_connection && !self->clients) { g_cond_wait (self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { sp_writer_free_block (block); GST_OBJECT_UNLOCK (self); return GST_FLOW_WRONG_STATE; } } shmbuf = sp_writer_block_get_buf (block); memcpy (shmbuf, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); sp_writer_send_buf (self->pipe, shmbuf, GST_BUFFER_SIZE (buf)); sp_writer_free_block (block); } GST_OBJECT_UNLOCK (self); return GST_FLOW_OK; }
/** * shm_writer_send_buffer * @self: the #ShmWriter with which to send the data buffer * @buffer: the data buffer to send to all connected clients * @len: the length of the data @buffer * * Sends a buffer of data to all connected clients. The data is internally * copied into the appropriate shm area so the passed buffer doesn't need * to be saved. * * Returns: the number of clients the buffer was successfully sent to or %-1 * on error. This number only signifies that it was sent successfully, * not that the clients processed it successfully. */ int shm_writer_send_buffer (ShmWriter *self, const gchar *buffer, gsize len) { ShmWriterPrivate *priv = self->priv; ShmBlock *block; gchar *buf; int ret; if (!priv->open) { g_debug ("ShmWriter not open"); return SHM_WRITER_FAILURE; } /* Allocating, copying, and freeing all this may seem silly, * but the data needs to be in the correct range in memory * in order to share it with other processes */ g_mutex_lock (priv->lock); block = sp_writer_alloc_block (priv->writer, len); if (block == NULL) { g_debug ("ShmWriter: unable to allocate block"); g_mutex_unlock (priv->lock); return SHM_WRITER_FAILURE; } buf = sp_writer_block_get_buf (block); memcpy (buf, buffer, len); ret = sp_writer_send_buf (priv->writer, buf, len); sp_writer_free_block (block); g_mutex_unlock (priv->lock); return ret; }
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_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; GST_OBJECT_LOCK (self); while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) goto flushing; } while (!gst_shm_sink_can_render (self, GST_BUFFER_TIMESTAMP (buf))) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) goto flushing; } 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_OBJECT_UNLOCK (self); GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT, ("Shared memory area is too small"), ("Shared memory area of size %" G_GSIZE_FORMAT " is smaller than" "buffer of size %" G_GSIZE_FORMAT, area_size, gst_buffer_get_size (buf))); return GST_FLOW_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) goto flushing; } while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { gst_memory_unref (memory); GST_OBJECT_UNLOCK (self); return GST_FLOW_FLUSHING; } } gst_memory_map (memory, &map, GST_MAP_WRITE); gst_buffer_extract (buf, 0, map.data, map.size); gst_memory_unmap (memory, &map); sendbuf = gst_buffer_new (); gst_buffer_copy_into (sendbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1); gst_buffer_append_memory (sendbuf, memory); } else { sendbuf = gst_buffer_ref (buf); } gst_buffer_map (sendbuf, &map, GST_MAP_READ); /* 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); 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); } else if (rv == -1) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Invalid allocated buffer"), ("The shmpipe library rejects our buffer, this is a bug")); ret = GST_FLOW_ERROR; } /* If we allocated our own memory, then unmap it */ return ret; flushing: GST_OBJECT_UNLOCK (self); return GST_FLOW_FLUSHING; }