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; }
/** * gst_clock_wait_for_sync: * @clock: a GstClock * @timeout: timeout for waiting or %GST_CLOCK_TIME_NONE * * Waits until @clock is synced for reporting the current time. If @timeout * is %GST_CLOCK_TIME_NONE it will wait forever, otherwise it will time out * after @timeout nanoseconds. * * For asynchronous waiting, the GstClock::synced signal can be used. * * * This returns immediately with TRUE if GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC * is not set on the clock, or if the clock is already synced. * * Returns: %TRUE if waiting was successful, or %FALSE on timeout * * Since: 1.6 */ gboolean gst_clock_wait_for_sync (GstClock * clock, GstClockTime timeout) { gboolean timed_out = FALSE; g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE); GST_OBJECT_LOCK (clock); if (!GST_OBJECT_FLAG_IS_SET (clock, GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC) || clock->priv->synced) { GST_OBJECT_UNLOCK (clock); return TRUE; } if (timeout != GST_CLOCK_TIME_NONE) { gint64 end_time = g_get_monotonic_time () + gst_util_uint64_scale (timeout, G_TIME_SPAN_SECOND, GST_SECOND); while (!clock->priv->synced && !timed_out) { timed_out = !g_cond_wait_until (&clock->priv->sync_cond, GST_OBJECT_GET_LOCK (clock), end_time); } } else { timed_out = FALSE; while (!clock->priv->synced) { g_cond_wait (&clock->priv->sync_cond, GST_OBJECT_GET_LOCK (clock)); } } GST_OBJECT_UNLOCK (clock); return !timed_out; }
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; }
static void gst_curl_smtp_sink_wait_for_transfer_end_unlocked (GstCurlSmtpSink * sink) { GST_LOG ("waiting for final data do be sent: %d", sink->transfer_end); while (!sink->transfer_end) { g_cond_wait (&sink->cond_transfer_end, GST_OBJECT_GET_LOCK (sink)); } GST_LOG ("final data sent"); }
static GstFlowReturn gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool) { gint ret; GST_OBJECT_LOCK (pool); while (pool->empty) g_cond_wait (&pool->empty_cond, GST_OBJECT_GET_LOCK (pool)); GST_OBJECT_UNLOCK (pool); if (!pool->can_poll_device) goto done; GST_LOG_OBJECT (pool, "polling device"); again: ret = gst_poll_wait (pool->poll, GST_CLOCK_TIME_NONE); if (G_UNLIKELY (ret < 0)) { switch (errno) { case EBUSY: goto stopped; case EAGAIN: case EINTR: goto again; case ENXIO: GST_WARNING_OBJECT (pool, "v4l2 device doesn't support polling. Disabling" " using libv4l2 in this case may cause deadlocks"); pool->can_poll_device = FALSE; goto done; default: goto select_error; } } if (gst_poll_fd_has_error (pool->poll, &pool->pollfd)) goto select_error; done: return GST_FLOW_OK; /* ERRORS */ stopped: { GST_DEBUG_OBJECT (pool, "stop called"); return GST_FLOW_FLUSHING; } select_error: { GST_ELEMENT_ERROR (pool->obj->element, RESOURCE, READ, (NULL), ("poll error %d: %s (%d)", ret, g_strerror (errno), errno)); return GST_FLOW_ERROR; } }
static void gst_curl_base_sink_wait_for_response (GstCurlBaseSink * sink) { GST_LOG ("waiting for remote to send response code"); GST_OBJECT_LOCK (sink); while (sink->transfer_cond->wait_for_response) { g_cond_wait (&sink->transfer_cond->cond, GST_OBJECT_GET_LOCK (sink)); } GST_OBJECT_UNLOCK (sink); GST_LOG ("response code received"); }
static void gst_curl_base_sink_wait_for_transfer_thread_to_send_unlocked (GstCurlBaseSink * sink) { GST_LOG ("waiting for buffer send to complete"); /* this function should not check if the transfer thread is set to be closed * since that flag only can be set by the EOS event (by the pipeline thread). * This can therefore never happen while this function is running since this * function also is called by the pipeline thread (in the render function) */ while (!sink->transfer_cond->data_sent) { g_cond_wait (&sink->transfer_cond->cond, GST_OBJECT_GET_LOCK (sink)); } GST_LOG ("buffer send completed"); }
static GstFlowReturn gst_identity_do_sync (GstIdentity * identity, GstClockTime running_time) { GstFlowReturn ret = GST_FLOW_OK; if (identity->sync && GST_BASE_TRANSFORM_CAST (identity)->segment.format == GST_FORMAT_TIME) { GstClock *clock; GST_OBJECT_LOCK (identity); while (identity->blocked) g_cond_wait (&identity->blocked_cond, GST_OBJECT_GET_LOCK (identity)); if ((clock = GST_ELEMENT (identity)->clock)) { GstClockReturn cret; GstClockTime timestamp; timestamp = running_time + GST_ELEMENT (identity)->base_time + identity->upstream_latency; /* save id if we need to unlock */ identity->clock_id = gst_clock_new_single_shot_id (clock, timestamp); GST_OBJECT_UNLOCK (identity); cret = gst_clock_id_wait (identity->clock_id, NULL); GST_OBJECT_LOCK (identity); if (identity->clock_id) { gst_clock_id_unref (identity->clock_id); identity->clock_id = NULL; } if (cret == GST_CLOCK_UNSCHEDULED) ret = GST_FLOW_EOS; } GST_OBJECT_UNLOCK (identity); } return ret; }
static gboolean gst_v4l2_device_provider_start (GstDeviceProvider * provider) { GstV4l2DeviceProvider *self = GST_V4L2_DEVICE_PROVIDER (provider); GST_OBJECT_LOCK (self); g_assert (self->context == NULL); self->context = g_main_context_new (); self->loop = g_main_loop_new (self->context, FALSE); self->thread = g_thread_new ("v4l2-device-provider", provider_thread, g_object_ref (self)); while (self->started == FALSE) g_cond_wait (&self->started_cond, GST_OBJECT_GET_LOCK (self)); GST_OBJECT_UNLOCK (self); return TRUE; }
static gboolean gst_curl_base_sink_wait_for_data_unlocked (GstCurlBaseSink * sink) { gboolean data_available = FALSE; GST_LOG ("waiting for data"); while (!sink->transfer_cond->data_available && !sink->transfer_thread_close && !sink->new_file) { g_cond_wait (&sink->transfer_cond->cond, GST_OBJECT_GET_LOCK (sink)); } if (sink->transfer_thread_close) { GST_LOG ("wait for data aborted due to thread close"); } else if (sink->new_file) { GST_LOG ("wait for data aborted due to new file name"); } else { GST_LOG ("wait for data completed"); data_available = TRUE; } return data_available; }
static GstClockReturn gst_test_clock_wait (GstClock * clock, GstClockEntry * entry, GstClockTimeDiff * jitter) { GstTestClock *test_clock = GST_TEST_CLOCK (clock); GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock); GST_OBJECT_LOCK (test_clock); GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock, "requesting synchronous clock notification at %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry))); if (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED) goto was_unscheduled; if (gst_test_clock_lookup_entry_context (test_clock, entry) == NULL) gst_test_clock_add_entry (test_clock, entry, jitter); GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_BUSY; while (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_BUSY) g_cond_wait (&priv->entry_processed_cond, GST_OBJECT_GET_LOCK (test_clock)); GST_OBJECT_UNLOCK (test_clock); return GST_CLOCK_ENTRY_STATUS (entry); /* ERRORS */ was_unscheduled: { GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock, "entry was unscheduled"); GST_OBJECT_UNLOCK (test_clock); return GST_CLOCK_UNSCHEDULED; } }
gboolean gst_uri_downloader_stream_uri (GstUriDownloader * downloader, const gchar * uri, gint64 range_start, gint64 range_end, GstUriDownloaderChainFunction chain_func, gpointer user_data) { GstStateChangeReturn ret; GST_INFO_OBJECT (downloader, "fetching URI %s", uri); g_mutex_lock (&downloader->download_lock); downloader->chain = chain_func; downloader->priv = user_data; downloader->eos = FALSE; gst_pad_set_active (downloader->pad, TRUE); GST_OBJECT_LOCK (downloader); if (downloader->cancelled) goto quit; if (!gst_uri_downloader_set_uri (downloader, uri)) { GST_ERROR_OBJECT (downloader, "failed to set URI"); goto quit; } gst_bus_set_flushing (downloader->bus, FALSE); GST_OBJECT_UNLOCK (downloader); /* set to ready state first to allow setting range */ ret = gst_element_set_state (downloader->urisrc, GST_STATE_READY); GST_OBJECT_LOCK (downloader); if (ret == GST_STATE_CHANGE_FAILURE) { GST_ERROR_OBJECT (downloader, "failed to set src to READY"); goto quit; } if (downloader->cancelled) goto quit; if (!gst_uri_downloader_set_range (downloader, range_start, range_end)) { GST_ERROR_OBJECT (downloader, "failed to set range"); goto quit; } GST_OBJECT_UNLOCK (downloader); ret = gst_element_set_state (downloader->urisrc, GST_STATE_PLAYING); GST_OBJECT_LOCK (downloader); if (ret == GST_STATE_CHANGE_FAILURE) { GST_ERROR_OBJECT (downloader, "failed to set src to PLAYING"); goto quit; } if (downloader->cancelled) goto quit; if (!downloader->eos) { /* wait until: * - the download succeed (EOS in the src pad) * - the download failed (Error message on the fetcher bus) * - the download was canceled */ GST_DEBUG_OBJECT (downloader, "waiting to fetch the URI %s", uri); g_cond_wait (&downloader->cond, GST_OBJECT_GET_LOCK (downloader)); } quit: { gboolean ret = FALSE; if (downloader->cancelled) { GST_DEBUG_OBJECT (downloader, "download interrupted"); } else if (downloader->eos) { GST_DEBUG_OBJECT (downloader, "URI fetched successfully"); ret = TRUE; } downloader->cancelled = FALSE; gst_uri_downloader_stop (downloader); GST_OBJECT_UNLOCK (downloader); g_mutex_unlock (&downloader->download_lock); return ret; } }
static void gst_live_adder_loop (gpointer data) { GstLiveAdder *adder = GST_LIVE_ADDER (data); GstClockTime buffer_timestamp = 0; GstClockTime sync_time = 0; GstClock *clock = NULL; GstClockID id = NULL; GstClockReturn ret; GstBuffer *buffer = NULL; GstFlowReturn result; GstEvent *newseg_event = NULL; GST_OBJECT_LOCK (adder); again: for (;;) { if (adder->srcresult != GST_FLOW_OK) goto flushing; if (!g_queue_is_empty (adder->buffers)) break; if (check_eos_locked (adder)) goto eos; g_cond_wait (adder->not_empty_cond, GST_OBJECT_GET_LOCK (adder)); } buffer_timestamp = GST_BUFFER_TIMESTAMP (g_queue_peek_head (adder->buffers)); clock = GST_ELEMENT_CLOCK (adder); /* If we have no clock, then we can't do anything.. error */ if (!clock) { if (adder->playing) goto no_clock; else goto push_buffer; } GST_DEBUG_OBJECT (adder, "sync to timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (buffer_timestamp)); sync_time = buffer_timestamp + GST_ELEMENT_CAST (adder)->base_time; /* add latency, this includes our own latency and the peer latency. */ sync_time += adder->latency_ms * GST_MSECOND; sync_time += adder->peer_latency; /* create an entry for the clock */ id = adder->clock_id = gst_clock_new_single_shot_id (clock, sync_time); GST_OBJECT_UNLOCK (adder); ret = gst_clock_id_wait (id, NULL); GST_OBJECT_LOCK (adder); /* and free the entry */ gst_clock_id_unref (id); adder->clock_id = NULL; /* at this point, the clock could have been unlocked by a timeout, a new * head element was added to the queue or because we are shutting down. Check * for shutdown first. */ if (adder->srcresult != GST_FLOW_OK) goto flushing; if (ret == GST_CLOCK_UNSCHEDULED) { GST_DEBUG_OBJECT (adder, "Wait got unscheduled, will retry to push with new buffer"); goto again; } if (ret != GST_CLOCK_OK && ret != GST_CLOCK_EARLY) goto clock_error; push_buffer: buffer = g_queue_pop_head (adder->buffers); if (!buffer) goto again; /* * We make sure the timestamps are exactly contiguous * If its only small skew (due to rounding errors), we correct it * silently. Otherwise we put the discont flag */ if (GST_CLOCK_TIME_IS_VALID (adder->next_timestamp) && GST_BUFFER_TIMESTAMP (buffer) != adder->next_timestamp) { GstClockTimeDiff diff = GST_CLOCK_DIFF (GST_BUFFER_TIMESTAMP (buffer), adder->next_timestamp); if (diff < 0) diff = -diff; if (diff < GST_SECOND / adder->rate) { GST_BUFFER_TIMESTAMP (buffer) = adder->next_timestamp; GST_DEBUG_OBJECT (adder, "Correcting slight skew"); GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT); } else { GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); GST_DEBUG_OBJECT (adder, "Expected buffer at %" GST_TIME_FORMAT ", but is at %" GST_TIME_FORMAT ", setting discont", GST_TIME_ARGS (adder->next_timestamp), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); } } else { GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT); } GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE; if (GST_BUFFER_DURATION_IS_VALID (buffer)) adder->next_timestamp = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer); else adder->next_timestamp = GST_CLOCK_TIME_NONE; if (adder->segment_pending) { /* * We set the start at 0, because we re-timestamps to the running time */ newseg_event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0, GST_FORMAT_TIME, 0, -1, 0); adder->segment_pending = FALSE; } GST_OBJECT_UNLOCK (adder); if (newseg_event) gst_pad_push_event (adder->srcpad, newseg_event); GST_LOG_OBJECT (adder, "About to push buffer time:%" GST_TIME_FORMAT " duration:%" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer))); result = gst_pad_push (adder->srcpad, buffer); if (result != GST_FLOW_OK) goto pause; return; flushing: { GST_DEBUG_OBJECT (adder, "we are flushing"); gst_pad_pause_task (adder->srcpad); GST_OBJECT_UNLOCK (adder); return; } clock_error: { gst_pad_pause_task (adder->srcpad); GST_OBJECT_UNLOCK (adder); GST_ELEMENT_ERROR (adder, STREAM, MUX, ("Error with the clock"), ("Error with the clock: %d", ret)); GST_ERROR_OBJECT (adder, "Error with the clock: %d", ret); return; } no_clock: { gst_pad_pause_task (adder->srcpad); GST_OBJECT_UNLOCK (adder); GST_ELEMENT_ERROR (adder, STREAM, MUX, ("No available clock"), ("No available clock")); GST_ERROR_OBJECT (adder, "No available clock"); return; } pause: { GST_DEBUG_OBJECT (adder, "pausing task, reason %s", gst_flow_get_name (result)); GST_OBJECT_LOCK (adder); /* store result */ adder->srcresult = result; /* we don't post errors or anything because upstream will do that for us * when we pass the return value upstream. */ gst_pad_pause_task (adder->srcpad); GST_OBJECT_UNLOCK (adder); return; } eos: { /* store result, we are flushing now */ GST_DEBUG_OBJECT (adder, "We are EOS, pushing EOS downstream"); adder->srcresult = GST_FLOW_UNEXPECTED; gst_pad_pause_task (adder->srcpad); GST_OBJECT_UNLOCK (adder); gst_pad_push_event (adder->srcpad, gst_event_new_eos ()); return; } }
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; }
/** * gst_uri_downloader_fetch_uri_with_range: * @downloader: the #GstUriDownloader * @uri: the uri * @range_start: the starting byte index * @range_end: the final byte index, use -1 for unspecified * * Returns the downloaded #GstFragment */ GstFragment * gst_uri_downloader_fetch_uri_with_range (GstUriDownloader * downloader, const gchar * uri, gint64 range_start, gint64 range_end) { GstStateChangeReturn ret; GstFragment *download = NULL; GST_DEBUG_OBJECT (downloader, "Fetching URI %s", uri); g_mutex_lock (&downloader->priv->download_lock); GST_OBJECT_LOCK (downloader); if (downloader->priv->cancelled) { GST_DEBUG_OBJECT (downloader, "Cancelled, aborting fetch"); goto quit; } if (!gst_uri_downloader_set_uri (downloader, uri)) { GST_WARNING_OBJECT (downloader, "Failed to set URI"); goto quit; } gst_bus_set_flushing (downloader->priv->bus, FALSE); downloader->priv->download = gst_fragment_new (); GST_OBJECT_UNLOCK (downloader); ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_READY); GST_OBJECT_LOCK (downloader); if (ret == GST_STATE_CHANGE_FAILURE || downloader->priv->download == NULL) { GST_WARNING_OBJECT (downloader, "Failed to set src to READY"); goto quit; } /* might have been cancelled because of failures in state change */ if (downloader->priv->cancelled) { goto quit; } if (!gst_uri_downloader_set_range (downloader, range_start, range_end)) { GST_WARNING_OBJECT (downloader, "Failed to set range"); goto quit; } GST_OBJECT_UNLOCK (downloader); ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_PLAYING); GST_OBJECT_LOCK (downloader); if (ret == GST_STATE_CHANGE_FAILURE) { if (downloader->priv->download) { g_object_unref (downloader->priv->download); downloader->priv->download = NULL; } goto quit; } /* might have been cancelled because of failures in state change */ if (downloader->priv->cancelled) { goto quit; } /* wait until: * - the download succeed (EOS in the src pad) * - the download failed (Error message on the fetcher bus) * - the download was canceled */ GST_DEBUG_OBJECT (downloader, "Waiting to fetch the URI %s", uri); while (!downloader->priv->cancelled && !downloader->priv->download->completed) g_cond_wait (&downloader->priv->cond, GST_OBJECT_GET_LOCK (downloader)); if (downloader->priv->cancelled) { if (downloader->priv->download) { g_object_unref (downloader->priv->download); downloader->priv->download = NULL; } goto quit; } download = downloader->priv->download; downloader->priv->download = NULL; if (download != NULL) GST_INFO_OBJECT (downloader, "URI fetched successfully"); else GST_INFO_OBJECT (downloader, "Error fetching URI"); quit: { if (downloader->priv->urisrc) { GstPad *pad; GstElement *urisrc; GST_DEBUG_OBJECT (downloader, "Stopping source element %s", GST_ELEMENT_NAME (downloader->priv->urisrc)); /* remove the bus' sync handler */ gst_bus_set_sync_handler (downloader->priv->bus, NULL, NULL, NULL); /* unlink the source element from the internal pad */ pad = gst_pad_get_peer (downloader->priv->pad); if (pad) { gst_pad_unlink (pad, downloader->priv->pad); gst_object_unref (pad); } urisrc = downloader->priv->urisrc; downloader->priv->urisrc = NULL; GST_OBJECT_UNLOCK (downloader); GST_DEBUG_OBJECT (downloader, "Stopping source element %s", GST_ELEMENT_NAME (urisrc)); /* set the element state to NULL */ gst_bus_set_flushing (downloader->priv->bus, TRUE); gst_element_set_state (urisrc, GST_STATE_NULL); gst_element_get_state (urisrc, NULL, NULL, GST_CLOCK_TIME_NONE); gst_element_set_bus (urisrc, NULL); gst_object_unref (urisrc); } else { GST_OBJECT_UNLOCK (downloader); } g_mutex_unlock (&downloader->priv->download_lock); return download; } }
static GstFlowReturn gst_audio_ringbuffer_get_range (GstPad * pad, guint64 offset, guint length, GstBuffer ** buffer) { GstAudioRingbuffer *ringbuffer; GstRingBuffer *rbuf; GstFlowReturn ret; ringbuffer = GST_AUDIO_RINGBUFFER_CAST (gst_pad_get_parent (pad)); rbuf = ringbuffer->buffer; if (ringbuffer->pulling) { GST_DEBUG_OBJECT (ringbuffer, "proxy pulling range"); ret = gst_pad_pull_range (ringbuffer->sinkpad, offset, length, buffer); } else { guint8 *data; guint len; guint64 sample; gint bps, segsize, segtotal, sps; gint sampleslen, segdone; gint readseg, sampleoff; guint8 *dest; GST_DEBUG_OBJECT (ringbuffer, "pulling data at %" G_GUINT64_FORMAT ", length %u", offset, length); if (offset != ringbuffer->src_segment.last_stop) { GST_DEBUG_OBJECT (ringbuffer, "expected offset %" G_GINT64_FORMAT, ringbuffer->src_segment.last_stop); } /* first wait till we have something in the ringbuffer and it * is running */ GST_OBJECT_LOCK (ringbuffer); if (ringbuffer->flushing) goto flushing; while (ringbuffer->waiting) { GST_DEBUG_OBJECT (ringbuffer, "waiting for unlock"); g_cond_wait (ringbuffer->cond, GST_OBJECT_GET_LOCK (ringbuffer)); GST_DEBUG_OBJECT (ringbuffer, "unlocked"); if (ringbuffer->flushing) goto flushing; } GST_OBJECT_UNLOCK (ringbuffer); bps = rbuf->spec.bytes_per_sample; if (G_UNLIKELY (length % bps) != 0) goto wrong_size; segsize = rbuf->spec.segsize; segtotal = rbuf->spec.segtotal; sps = rbuf->samples_per_seg; dest = GST_BUFFER_DATA (rbuf->data); sample = offset / bps; len = length / bps; *buffer = gst_buffer_new_and_alloc (length); data = GST_BUFFER_DATA (*buffer); while (len) { gint diff; /* figure out the segment and the offset inside the segment where * the sample should be read from. */ readseg = sample / sps; sampleoff = (sample % sps); segdone = g_atomic_int_get (&rbuf->segdone) - rbuf->segbase; diff = readseg - segdone; /* we can read now */ readseg = readseg % segtotal; sampleslen = MIN (sps - sampleoff, len); GST_DEBUG_OBJECT (ringbuffer, "read @%p seg %d, off %d, sampleslen %d, diff %d", dest + readseg * segsize, readseg, sampleoff, sampleslen, diff); memcpy (data, dest + (readseg * segsize) + (sampleoff * bps), (sampleslen * bps)); if (diff > 0) gst_ring_buffer_advance (rbuf, diff); len -= sampleslen; sample += sampleslen; data += sampleslen * bps; } ringbuffer->src_segment.last_stop += length; ret = GST_FLOW_OK; } gst_object_unref (ringbuffer); return ret; /* ERRORS */ flushing: { GST_DEBUG_OBJECT (ringbuffer, "we are flushing"); GST_OBJECT_UNLOCK (ringbuffer); gst_object_unref (ringbuffer); return GST_FLOW_WRONG_STATE; } wrong_size: { GST_DEBUG_OBJECT (ringbuffer, "wrong size"); GST_ELEMENT_ERROR (ringbuffer, STREAM, WRONG_TYPE, (NULL), ("asked to pull buffer of wrong size.")); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_shmdata_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstShmdataSink *self = GST_SHMDATA_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); 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) > shmdata_get_shmmax(NULL)) { gsize area_size = shmdata_get_shmmax(NULL); 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_shmdata_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; } 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 */ shmdata_notify_clients(self->access, map.size); self->bytes_since_last_request += map.size; shmdata_release_one_write_access(self->access); // wait for client to read and take the write lock self->access = shmdata_get_one_write_access(self->shmwriter); gst_buffer_unmap (sendbuf, &map); GST_OBJECT_UNLOCK (self); GST_DEBUG_OBJECT (self, "No clients connected, unreffing buffer"); gst_buffer_unref (sendbuf); /* If we allocated our own memory, then unmap it */ return ret; flushing: GST_OBJECT_UNLOCK (self); return GST_FLOW_FLUSHING; }
/** * gst_uri_downloader_fetch_uri_with_range: * @downloader: the #GstUriDownloader * @uri: the uri * @range_start: the starting byte index * @range_end: the final byte index, use -1 for unspecified * * Returns the downloaded #GstFragment */ GstFragment * gst_uri_downloader_fetch_uri_with_range (GstUriDownloader * downloader, const gchar * uri, const gchar * referer, gboolean compress, gboolean refresh, gboolean allow_cache, gint64 range_start, gint64 range_end, GError ** err) { GstStateChangeReturn ret; GstFragment *download = NULL; GST_DEBUG_OBJECT (downloader, "Fetching URI %s", uri); g_mutex_lock (&downloader->priv->download_lock); downloader->priv->err = NULL; downloader->priv->got_buffer = FALSE; GST_OBJECT_LOCK (downloader); if (downloader->priv->cancelled) { GST_DEBUG_OBJECT (downloader, "Cancelled, aborting fetch"); goto quit; } if (!gst_uri_downloader_set_uri (downloader, uri, referer, compress, refresh, allow_cache)) { GST_WARNING_OBJECT (downloader, "Failed to set URI"); goto quit; } gst_bus_set_flushing (downloader->priv->bus, FALSE); if (downloader->priv->download) g_object_unref (downloader->priv->download); downloader->priv->download = gst_fragment_new (); downloader->priv->download->range_start = range_start; downloader->priv->download->range_end = range_end; GST_OBJECT_UNLOCK (downloader); ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_READY); GST_OBJECT_LOCK (downloader); if (ret == GST_STATE_CHANGE_FAILURE || downloader->priv->download == NULL) { GST_WARNING_OBJECT (downloader, "Failed to set src to READY"); goto quit; } /* might have been cancelled because of failures in state change */ if (downloader->priv->cancelled) { goto quit; } if (range_start < 0 && range_end < 0) { if (!gst_uri_downloader_set_method (downloader, "HEAD")) { GST_WARNING_OBJECT (downloader, "Failed to set HTTP method"); goto quit; } } else { if (!gst_uri_downloader_set_range (downloader, range_start, range_end)) { GST_WARNING_OBJECT (downloader, "Failed to set range"); goto quit; } } GST_OBJECT_UNLOCK (downloader); ret = gst_element_set_state (downloader->priv->urisrc, GST_STATE_PLAYING); GST_OBJECT_LOCK (downloader); if (ret == GST_STATE_CHANGE_FAILURE) { if (downloader->priv->download) { g_object_unref (downloader->priv->download); downloader->priv->download = NULL; } goto quit; } /* might have been cancelled because of failures in state change */ if (downloader->priv->cancelled) { goto quit; } /* wait until: * - the download succeed (EOS in the src pad) * - the download failed (Error message on the fetcher bus) * - the download was canceled */ GST_DEBUG_OBJECT (downloader, "Waiting to fetch the URI %s", uri); while (!downloader->priv->cancelled && !downloader->priv->download->completed) g_cond_wait (&downloader->priv->cond, GST_OBJECT_GET_LOCK (downloader)); if (downloader->priv->cancelled) { if (downloader->priv->download) { g_object_unref (downloader->priv->download); downloader->priv->download = NULL; } goto quit; } download = downloader->priv->download; downloader->priv->download = NULL; if (!downloader->priv->got_buffer) { if (download->range_start < 0 && download->range_end < 0) { /* HEAD request, so we don't expect a response */ } else { g_object_unref (download); download = NULL; GST_ERROR_OBJECT (downloader, "Didn't retrieve a buffer before EOS"); } } if (download != NULL) GST_INFO_OBJECT (downloader, "URI fetched successfully"); else GST_INFO_OBJECT (downloader, "Error fetching URI"); quit: { if (downloader->priv->urisrc) { GstPad *pad; GstElement *urisrc; urisrc = downloader->priv->urisrc; GST_DEBUG_OBJECT (downloader, "Stopping source element %s", GST_ELEMENT_NAME (urisrc)); /* remove the bus' sync handler */ gst_bus_set_sync_handler (downloader->priv->bus, NULL, NULL, NULL); gst_bus_set_flushing (downloader->priv->bus, TRUE); /* set the element state to NULL */ GST_OBJECT_UNLOCK (downloader); if (download == NULL) { gst_element_set_state (urisrc, GST_STATE_NULL); } else { GstQuery *query; /* Download successfull, let's query the URI */ query = gst_query_new_uri (); if (gst_element_query (urisrc, query)) { gst_query_parse_uri (query, &download->uri); gst_query_parse_uri_redirection (query, &download->redirect_uri); gst_query_parse_uri_redirection_permanent (query, &download->redirect_permanent); } gst_query_unref (query); gst_element_set_state (urisrc, GST_STATE_READY); } GST_OBJECT_LOCK (downloader); gst_element_set_bus (urisrc, NULL); /* unlink the source element from the internal pad */ pad = gst_pad_get_peer (downloader->priv->pad); if (pad) { gst_pad_unlink (pad, downloader->priv->pad); gst_object_unref (pad); } } GST_OBJECT_UNLOCK (downloader); if (download == NULL) { if (!downloader->priv->err) { g_set_error (err, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_OPEN_READ, "Failed to download '%s'", uri); } else { g_propagate_error (err, downloader->priv->err); downloader->priv->err = NULL; } } downloader->priv->cancelled = FALSE; g_mutex_unlock (&downloader->priv->download_lock); return download; } }
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; }