コード例 #1
0
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;
}
コード例 #2
0
ファイル: gstclock.c プロジェクト: Distrotech/gstreamer
/**
 * 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;
}
コード例 #3
0
ファイル: gstshmsink.c プロジェクト: adesurya/gst-mobile
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;
}
コード例 #4
0
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");
}
コード例 #5
0
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;
  }
}
コード例 #6
0
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");
}
コード例 #7
0
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");
}
コード例 #8
0
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;
}
コード例 #9
0
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;
}
コード例 #10
0
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;
}
コード例 #11
0
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;
  }
}
コード例 #12
0
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;
  }
}
コード例 #13
0
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;
    }
}
コード例 #14
0
ファイル: gstshmsink.c プロジェクト: 0p1pp1/gst-plugins-bad
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;
}
コード例 #15
0
/**
 * 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;
  }
}
コード例 #17
0
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;
}
コード例 #18
0
/**
 * 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;
  }
}
コード例 #19
0
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;
}