Пример #1
0
StreamStatusMessagePtr StreamStatusMessage::create(const ObjectPtr & source,
                                                   StreamStatusType type, const ElementPtr & owner)
{
    GstMessage *m = gst_message_new_stream_status(source, static_cast<GstStreamStatusType>(type), owner);
    return StreamStatusMessagePtr::wrap(m, false);
}
Пример #2
0
static gpointer
render_thread_func (GstEglGlesSink * eglglessink)
{
  GstMessage *message;
  GValue val = { 0 };
  GstDataQueueItem *item = NULL;
  GstFlowReturn last_flow = GST_FLOW_OK;

  g_value_init (&val, G_TYPE_POINTER);
  g_value_set_pointer (&val, g_thread_self ());
  message = gst_message_new_stream_status (GST_OBJECT_CAST (eglglessink),
      GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (eglglessink));
  gst_message_set_stream_status_object (message, &val);
  GST_DEBUG_OBJECT (eglglessink, "posting ENTER stream status");
  gst_element_post_message (GST_ELEMENT_CAST (eglglessink), message);
  g_value_unset (&val);

  gst_egl_adaptation_bind_API (eglglessink->egl_context);

  while (gst_data_queue_pop (eglglessink->queue, &item)) {
    GstBuffer *buf = NULL;
    GstMiniObject *object = item->object;

    GST_DEBUG_OBJECT (eglglessink, "Handling object %" GST_PTR_FORMAT, object);

    if (GST_IS_BUFFER (object)) {
      GstCaps *caps;

      buf = GST_BUFFER_CAST (item->object);
      caps = GST_BUFFER_CAPS (buf);
      if (caps != eglglessink->configured_caps) {
        if (!gst_eglglessink_configure_caps (eglglessink, caps)) {
          g_mutex_lock (eglglessink->render_lock);
          eglglessink->last_flow = GST_FLOW_NOT_NEGOTIATED;
          g_cond_broadcast (eglglessink->render_cond);
          g_mutex_unlock (eglglessink->render_lock);
          item->destroy (item);
          break;
        }
      }
      if (eglglessink->configured_caps) {
        last_flow = gst_eglglessink_upload (eglglessink, buf);
        if (last_flow == GST_FLOW_OK) {
          last_flow = gst_eglglessink_render (eglglessink);
        }
      } else {
        GST_DEBUG_OBJECT (eglglessink,
            "No caps configured yet, not drawing anything");
      }
    } else if (!object) {
      if (eglglessink->configured_caps) {
        last_flow = gst_eglglessink_render (eglglessink);
      } else {
        last_flow = GST_FLOW_OK;
        GST_DEBUG_OBJECT (eglglessink,
            "No caps configured yet, not drawing anything");
      }
    } else {
      g_assert_not_reached ();
    }

    item->destroy (item);
    g_mutex_lock (eglglessink->render_lock);
    eglglessink->last_flow = last_flow;
    g_cond_broadcast (eglglessink->render_cond);
    g_mutex_unlock (eglglessink->render_lock);

    if (last_flow != GST_FLOW_OK)
      break;
    GST_DEBUG_OBJECT (eglglessink, "Successfully handled object");
  }

  if (last_flow == GST_FLOW_OK) {
    g_mutex_lock (eglglessink->render_lock);
    eglglessink->last_flow = GST_FLOW_WRONG_STATE;
    g_cond_broadcast (eglglessink->render_cond);
    g_mutex_unlock (eglglessink->render_lock);
  }

  GST_DEBUG_OBJECT (eglglessink, "Shutting down thread");

  /* EGL/GLES cleanup */
  gst_egl_adaptation_cleanup (eglglessink->egl_context);

  if (eglglessink->configured_caps) {
    gst_caps_unref (eglglessink->configured_caps);
    eglglessink->configured_caps = NULL;
  }

  g_value_init (&val, G_TYPE_POINTER);
  g_value_set_pointer (&val, g_thread_self ());
  message = gst_message_new_stream_status (GST_OBJECT_CAST (eglglessink),
      GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (eglglessink));
  gst_message_set_stream_status_object (message, &val);
  GST_DEBUG_OBJECT (eglglessink, "posting LEAVE stream status");
  gst_element_post_message (GST_ELEMENT_CAST (eglglessink), message);
  g_value_unset (&val);

  return NULL;
}
Пример #3
0
/* this internal thread does nothing else but read samples from the audio device.
 * It will read each segment in the ringbuffer and will update the play
 * pointer. 
 * The start/stop methods control the thread.
 */
static void
audioringbuffer_thread_func (GstRingBuffer * buf)
{
  GstAudioSrc *src;
  GstAudioSrcClass *csrc;
  GstAudioRingBuffer *abuf = GST_AUDIORING_BUFFER (buf);
  ReadFunc readfunc;
  GstMessage *message;
  GValue val = { 0 };

  src = GST_AUDIO_SRC (GST_OBJECT_PARENT (buf));
  csrc = GST_AUDIO_SRC_GET_CLASS (src);

  GST_DEBUG_OBJECT (src, "enter thread");

  readfunc = csrc->read;
  if (readfunc == NULL)
    goto no_function;

  /* FIXME: maybe we should at least use a custom pointer type here? */
  g_value_init (&val, G_TYPE_POINTER);
  g_value_set_pointer (&val, src->thread);
  message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
      GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (src));
  gst_message_set_stream_status_object (message, &val);
  GST_DEBUG_OBJECT (src, "posting ENTER stream status");
  gst_element_post_message (GST_ELEMENT_CAST (src), message);

  while (TRUE) {
    gint left, len;
    guint8 *readptr;
    gint readseg;

    if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
      gint read;

      left = len;
      do {
        read = readfunc (src, readptr, left);
        GST_LOG_OBJECT (src, "transfered %d bytes of %d to segment %d", read,
            left, readseg);
        if (read < 0 || read > left) {
          GST_WARNING_OBJECT (src,
              "error reading data %d (reason: %s), skipping segment", read,
              g_strerror (errno));
          break;
        }
        left -= read;
        readptr += read;
      } while (left > 0);

      /* we read one segment */
      gst_ring_buffer_advance (buf, 1);
    } else {
      GST_OBJECT_LOCK (abuf);
      if (!abuf->running)
        goto stop_running;
      GST_DEBUG_OBJECT (src, "signal wait");
      GST_AUDIORING_BUFFER_SIGNAL (buf);
      GST_DEBUG_OBJECT (src, "wait for action");
      GST_AUDIORING_BUFFER_WAIT (buf);
      GST_DEBUG_OBJECT (src, "got signal");
      if (!abuf->running)
        goto stop_running;
      GST_DEBUG_OBJECT (src, "continue running");
      GST_OBJECT_UNLOCK (abuf);
    }
  }

  /* Will never be reached */
  g_assert_not_reached ();
  return;

  /* ERROR */
no_function:
  {
    GST_DEBUG ("no write function, exit thread");
    return;
  }
stop_running:
  {
    GST_OBJECT_UNLOCK (abuf);
    GST_DEBUG ("stop running, exit thread");
    message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
        GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (src));
    gst_message_set_stream_status_object (message, &val);
    GST_DEBUG_OBJECT (src, "posting LEAVE stream status");
    gst_element_post_message (GST_ELEMENT_CAST (src), message);
    return;
  }
}
Пример #4
0
/* this internal thread does nothing else but write samples to the audio device.
 * It will write each segment in the ringbuffer and will update the play
 * pointer.
 * The start/stop methods control the thread.
 */
static void
audioringbuffer_thread_func (GstRingBuffer * buf)
{
  GstAudioSink *sink;
  GstAudioSinkClass *csink;
  GstAudioRingBuffer *abuf = GST_AUDIORING_BUFFER_CAST (buf);
  WriteFunc writefunc;
  GstMessage *message;
  GValue val = { 0 };

  sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
  csink = GST_AUDIO_SINK_GET_CLASS (sink);

  GST_DEBUG_OBJECT (sink, "enter thread");

  GST_OBJECT_LOCK (abuf);
  GST_DEBUG_OBJECT (sink, "signal wait");
  GST_AUDIORING_BUFFER_SIGNAL (buf);
  GST_OBJECT_UNLOCK (abuf);

  writefunc = csink->write;
  if (writefunc == NULL)
    goto no_function;

  g_value_init (&val, G_TYPE_POINTER);
  g_value_set_pointer (&val, sink->thread);
  message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
      GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
  gst_message_set_stream_status_object (message, &val);
  GST_DEBUG_OBJECT (sink, "posting ENTER stream status");
  gst_element_post_message (GST_ELEMENT_CAST (sink), message);

  while (TRUE) {
    gint left, len;
    guint8 *readptr;
    gint readseg;

    /* buffer must be started */
    if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
      gint written;

      left = len;
      do {
        written = writefunc (sink, readptr, left);
        GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d",
            written, left, readseg);
        if (written < 0 || written > left) {
          /* might not be critical, it e.g. happens when aborting playback */
          GST_WARNING_OBJECT (sink,
              "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)",
              GST_DEBUG_FUNCPTR_NAME (writefunc),
              (errno > 1 ? g_strerror (errno) : "unknown"), left, written);
          break;
        }
        left -= written;
        readptr += written;
      } while (left > 0);

      /* clear written samples */
      gst_ring_buffer_clear (buf, readseg);

      /* we wrote one segment */
      gst_ring_buffer_advance (buf, 1);
    } else {
      GST_OBJECT_LOCK (abuf);
      if (!abuf->running)
        goto stop_running;
      GST_DEBUG_OBJECT (sink, "signal wait");
      GST_AUDIORING_BUFFER_SIGNAL (buf);
      GST_DEBUG_OBJECT (sink, "wait for action");
#ifndef GSTREAMER_LITE
      GST_AUDIORING_BUFFER_WAIT (buf);
#else // GSTREAMER_LITE
      // In same cases we may have condition when we waiting here for ring buffer to start,
      // while ring buffer is started and data is available. So, lets use wait with timeout
      // and recheck if we good to go. wait_segment() will start ring buffer when data is available.
      {
          GTimeVal timeout;
          g_get_current_time(&timeout);
          g_time_val_add(&timeout, 100000); // 100 millisecond
          GST_AUDIORING_BUFFER_TIMED_WAIT (buf, &timeout);
      }
#endif // GSTREAMER_LITE
      GST_DEBUG_OBJECT (sink, "got signal");
      if (!abuf->running)
        goto stop_running;
      GST_DEBUG_OBJECT (sink, "continue running");
      GST_OBJECT_UNLOCK (abuf);
    }
  }

  /* Will never be reached */
  g_assert_not_reached ();
  return;

  /* ERROR */
no_function:
  {
    GST_DEBUG_OBJECT (sink, "no write function, exit thread");
    return;
  }
stop_running:
  {
    GST_OBJECT_UNLOCK (abuf);
    GST_DEBUG_OBJECT (sink, "stop running, exit thread");
    message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
        GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink));
    gst_message_set_stream_status_object (message, &val);
    GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
    gst_element_post_message (GST_ELEMENT_CAST (sink), message);
    return;
  }
}
/* this internal thread does nothing else but write samples to the audio device.
 * It will write each segment in the ringbuffer and will update the play
 * pointer.
 * The start/stop methods control the thread.
 */
static void
audioringbuffer_thread_func (GstAudioRingBuffer * buf)
{
    GstAudioSink *sink;
    GstAudioSinkClass *csink;
    GstAudioSinkRingBuffer *abuf = GST_AUDIO_SINK_RING_BUFFER_CAST (buf);
    WriteFunc writefunc;
    GstMessage *message;
    GValue val = { 0 };

    sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
    csink = GST_AUDIO_SINK_GET_CLASS (sink);

    GST_DEBUG_OBJECT (sink, "enter thread");

    GST_OBJECT_LOCK (abuf);
    GST_DEBUG_OBJECT (sink, "signal wait");
    GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
    GST_OBJECT_UNLOCK (abuf);

    writefunc = csink->write;
    if (writefunc == NULL)
        goto no_function;

    message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
              GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink));
    g_value_init (&val, GST_TYPE_G_THREAD);
    g_value_set_boxed (&val, g_thread_self ());
    gst_message_set_stream_status_object (message, &val);
    g_value_unset (&val);
    GST_DEBUG_OBJECT (sink, "posting ENTER stream status");
    gst_element_post_message (GST_ELEMENT_CAST (sink), message);

    while (TRUE) {
        gint left, len;
        guint8 *readptr;
        gint readseg;

        /* buffer must be started */
        if (gst_audio_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) {
            gint written;

            left = len;
            do {
                written = writefunc (sink, readptr, left);
                GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d",
                                written, left, readseg);
                if (written < 0 || written > left) {
                    /* might not be critical, it e.g. happens when aborting playback */
                    GST_WARNING_OBJECT (sink,
                                        "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)",
                                        GST_DEBUG_FUNCPTR_NAME (writefunc),
                                        (errno > 1 ? g_strerror (errno) : "unknown"), left, written);
                    break;
                }
                left -= written;
                readptr += written;
            } while (left > 0);

            /* clear written samples */
            gst_audio_ring_buffer_clear (buf, readseg);

            /* we wrote one segment */
            gst_audio_ring_buffer_advance (buf, 1);
        } else {
            GST_OBJECT_LOCK (abuf);
            if (!abuf->running)
                goto stop_running;
            if (G_UNLIKELY (g_atomic_int_get (&buf->state) ==
                            GST_AUDIO_RING_BUFFER_STATE_STARTED)) {
                GST_OBJECT_UNLOCK (abuf);
                continue;
            }
            GST_DEBUG_OBJECT (sink, "signal wait");
            GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf);
            GST_DEBUG_OBJECT (sink, "wait for action");
            GST_AUDIO_SINK_RING_BUFFER_WAIT (buf);
            GST_DEBUG_OBJECT (sink, "got signal");
            if (!abuf->running)
                goto stop_running;
            GST_DEBUG_OBJECT (sink, "continue running");
            GST_OBJECT_UNLOCK (abuf);
        }
    }

    /* Will never be reached */
    g_assert_not_reached ();
    return;

    /* ERROR */
no_function:
    {
        GST_DEBUG_OBJECT (sink, "no write function, exit thread");
        return;
    }
stop_running:
    {
        GST_OBJECT_UNLOCK (abuf);
        GST_DEBUG_OBJECT (sink, "stop running, exit thread");
        message = gst_message_new_stream_status (GST_OBJECT_CAST (buf),
                  GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink));
        g_value_init (&val, GST_TYPE_G_THREAD);
        g_value_set_boxed (&val, g_thread_self ());
        gst_message_set_stream_status_object (message, &val);
        g_value_unset (&val);
        GST_DEBUG_OBJECT (sink, "posting LEAVE stream status");
        gst_element_post_message (GST_ELEMENT_CAST (sink), message);
        return;
    }
}