/** * gst_app_src_get_caps: * @appsrc: a #GstAppSrc * * Get the configured caps on @appsrc. * * Returns: the #GstCaps produced by the source. gst_caps_unref() after usage. */ GstCaps * gst_app_src_get_caps (GstAppSrc * appsrc) { g_return_val_if_fail (GST_IS_APP_SRC (appsrc), NULL); return gst_app_src_internal_get_caps (GST_BASE_SRC_CAST (appsrc), NULL); }
/** * gst_app_src_set_caps: * @appsrc: a #GstAppSrc * @caps: caps to set * * Set the capabilities on the appsrc element. This function takes * a copy of the caps structure. After calling this method, the source will * only produce caps that match @caps. @caps must be fixed and the caps on the * buffers must match the caps or left NULL. */ void gst_app_src_set_caps (GstAppSrc * appsrc, const GstCaps * caps) { GstCaps *old; GstAppSrcPrivate *priv; g_return_if_fail (GST_IS_APP_SRC (appsrc)); priv = appsrc->priv; g_mutex_lock (&priv->mutex); GST_OBJECT_LOCK (appsrc); GST_DEBUG_OBJECT (appsrc, "setting caps to %" GST_PTR_FORMAT, caps); if ((old = priv->caps) != caps) { if (caps) priv->caps = gst_caps_copy (caps); else priv->caps = NULL; if (old) gst_caps_unref (old); priv->new_caps = TRUE; } GST_OBJECT_UNLOCK (appsrc); g_mutex_unlock (&priv->mutex); }
/** * gst_app_src_end_of_stream: * @appsrc: a #GstAppSrc * * Indicates to the appsrc element that the last buffer queued in the * element is the last buffer of the stream. * * Returns: #GST_FLOW_OK when the EOS was successfuly queued. * #GST_FLOW_FLUSHING when @appsrc is not PAUSED or PLAYING. */ GstFlowReturn gst_app_src_end_of_stream (GstAppSrc * appsrc) { GstAppSrcPrivate *priv; g_return_val_if_fail (GST_IS_APP_SRC (appsrc), GST_FLOW_ERROR); priv = appsrc->priv; g_mutex_lock (&priv->mutex); /* can't accept buffers when we are flushing. We can accept them when we are * EOS although it will not do anything. */ if (priv->flushing) goto flushing; GST_DEBUG_OBJECT (appsrc, "sending EOS"); priv->is_eos = TRUE; g_cond_broadcast (&priv->cond); g_mutex_unlock (&priv->mutex); return GST_FLOW_OK; /* ERRORS */ flushing: { g_mutex_unlock (&priv->mutex); GST_DEBUG_OBJECT (appsrc, "refuse EOS, we are flushing"); return GST_FLOW_FLUSHING; } }
/** * gst_app_src_set_callbacks: (skip) * @appsrc: a #GstAppSrc * @callbacks: the callbacks * @user_data: a user_data argument for the callbacks * @notify: a destroy notify function * * Set callbacks which will be executed when data is needed, enough data has * been collected or when a seek should be performed. * This is an alternative to using the signals, it has lower overhead and is thus * less expensive, but also less flexible. * * If callbacks are installed, no signals will be emitted for performance * reasons. */ void gst_app_src_set_callbacks (GstAppSrc * appsrc, GstAppSrcCallbacks * callbacks, gpointer user_data, GDestroyNotify notify) { GDestroyNotify old_notify; GstAppSrcPrivate *priv; g_return_if_fail (GST_IS_APP_SRC (appsrc)); g_return_if_fail (callbacks != NULL); priv = appsrc->priv; GST_OBJECT_LOCK (appsrc); old_notify = priv->notify; if (old_notify) { gpointer old_data; old_data = priv->user_data; priv->user_data = NULL; priv->notify = NULL; GST_OBJECT_UNLOCK (appsrc); old_notify (old_data); GST_OBJECT_LOCK (appsrc); } priv->callbacks = *callbacks; priv->user_data = user_data; priv->notify = notify; GST_OBJECT_UNLOCK (appsrc); }
/** * gst_app_src_set_emit_signals: * @appsrc: a #GstAppSrc * @emit: the new state * * Make appsrc emit the "new-preroll" and "new-buffer" signals. This option is * by default disabled because signal emission is expensive and unneeded when * the application prefers to operate in pull mode. * * Since: 0.10.23 */ void gst_app_src_set_emit_signals (GstAppSrc * appsrc, gboolean emit) { g_return_if_fail (GST_IS_APP_SRC (appsrc)); g_mutex_lock (appsrc->priv->mutex); appsrc->priv->emit_signals = emit; g_mutex_unlock (appsrc->priv->mutex); }
/** * gst_app_src_set_stream_type: * @appsrc: a #GstAppSrc * @type: the new state * * Set the stream type on @appsrc. For seekable streams, the "seek" signal must * be connected to. * * A stream_type stream * * Since: 0.10.22 */ void gst_app_src_set_stream_type (GstAppSrc * appsrc, GstAppStreamType type) { g_return_if_fail (appsrc != NULL); g_return_if_fail (GST_IS_APP_SRC (appsrc)); GST_OBJECT_LOCK (appsrc); GST_DEBUG_OBJECT (appsrc, "setting stream_type of %d", type); appsrc->priv->stream_type = type; GST_OBJECT_UNLOCK (appsrc); }
/** * gst_app_src_set_size: * @appsrc: a #GstAppSrc * @size: the size to set * * Set the size of the stream in bytes. A value of -1 means that the size is * not known. * * Since: 0.10.22 */ void gst_app_src_set_size (GstAppSrc * appsrc, gint64 size) { g_return_if_fail (appsrc != NULL); g_return_if_fail (GST_IS_APP_SRC (appsrc)); GST_OBJECT_LOCK (appsrc); GST_DEBUG_OBJECT (appsrc, "setting size of %" G_GINT64_FORMAT, size); appsrc->priv->size = size; GST_OBJECT_UNLOCK (appsrc); }
/** * gst_app_src_get_latency: * @appsrc: a #GstAppSrc * @min: the min latency * @max: the min latency * * Retrieve the min and max latencies in @min and @max respectively. * * Since: 0.10.22 */ void gst_app_src_get_latency (GstAppSrc * appsrc, guint64 * min, guint64 * max) { g_return_if_fail (GST_IS_APP_SRC (appsrc)); g_mutex_lock (appsrc->priv->mutex); if (min) *min = appsrc->priv->min_latency; if (max) *max = appsrc->priv->max_latency; g_mutex_unlock (appsrc->priv->mutex); }
/** * gst_app_src_get_emit_signals: * @appsrc: a #GstAppSrc * * Check if appsrc will emit the "new-preroll" and "new-buffer" signals. * * Returns: %TRUE if @appsrc is emiting the "new-preroll" and "new-buffer" * signals. * * Since: 0.10.23 */ gboolean gst_app_src_get_emit_signals (GstAppSrc * appsrc) { gboolean result; g_return_val_if_fail (GST_IS_APP_SRC (appsrc), FALSE); g_mutex_lock (appsrc->priv->mutex); result = appsrc->priv->emit_signals; g_mutex_unlock (appsrc->priv->mutex); return result; }
/** * gst_app_src_get_max_bytes: * @appsrc: a #GstAppSrc * * Get the maximum amount of bytes that can be queued in @appsrc. * * Returns: The maximum amount of bytes that can be queued. * * Since: 0.10.22 */ guint64 gst_app_src_get_max_bytes (GstAppSrc * appsrc) { guint64 result; g_return_val_if_fail (GST_IS_APP_SRC (appsrc), 0); g_mutex_lock (appsrc->priv->mutex); result = appsrc->priv->max_bytes; GST_DEBUG_OBJECT (appsrc, "getting max-bytes of %" G_GUINT64_FORMAT, result); g_mutex_unlock (appsrc->priv->mutex); return result; }
/** * gst_app_src_set_max_bytes: * @appsrc: a #GstAppSrc * @max: the maximum number of bytes to queue * * Set the maximum amount of bytes that can be queued in @appsrc. * After the maximum amount of bytes are queued, @appsrc will emit the * "enough-data" signal. * * Since: 0.10.22 */ void gst_app_src_set_max_bytes (GstAppSrc * appsrc, guint64 max) { g_return_if_fail (GST_IS_APP_SRC (appsrc)); g_mutex_lock (appsrc->priv->mutex); if (max != appsrc->priv->max_bytes) { GST_DEBUG_OBJECT (appsrc, "setting max-bytes to %" G_GUINT64_FORMAT, max); appsrc->priv->max_bytes = max; /* signal the change */ g_cond_broadcast (appsrc->priv->cond); } g_mutex_unlock (appsrc->priv->mutex); }
/** * gst_app_src_get_size: * @appsrc: a #GstAppSrc * * Get the size of the stream in bytes. A value of -1 means that the size is * not known. * * Returns: the size of the stream previously set with gst_app_src_set_size(); * * Since: 0.10.22 */ gint64 gst_app_src_get_size (GstAppSrc * appsrc) { gint64 size; g_return_val_if_fail (appsrc != NULL, -1); g_return_val_if_fail (GST_IS_APP_SRC (appsrc), -1); GST_OBJECT_LOCK (appsrc); size = appsrc->priv->size; GST_DEBUG_OBJECT (appsrc, "getting size of %" G_GINT64_FORMAT, size); GST_OBJECT_UNLOCK (appsrc); return size; }
/** * gst_app_src_get_stream_type: * @appsrc: a #GstAppSrc * * Get the stream type. Control the stream type of @appsrc * with gst_app_src_set_stream_type(). * * Returns: the stream type. * * Since: 0.10.22 */ GstAppStreamType gst_app_src_get_stream_type (GstAppSrc * appsrc) { gboolean stream_type; g_return_val_if_fail (appsrc != NULL, FALSE); g_return_val_if_fail (GST_IS_APP_SRC (appsrc), FALSE); GST_OBJECT_LOCK (appsrc); stream_type = appsrc->priv->stream_type; GST_DEBUG_OBJECT (appsrc, "getting stream_type of %d", stream_type); GST_OBJECT_UNLOCK (appsrc); return stream_type; }
/** * gst_app_src_get_caps: * @appsrc: a #GstAppSrc * * Get the configured caps on @appsrc. * * Returns: the #GstCaps produced by the source. gst_caps_unref() after usage. * * Since: 0.10.22 */ GstCaps * gst_app_src_get_caps (GstAppSrc * appsrc) { GstCaps *caps; g_return_val_if_fail (appsrc != NULL, NULL); g_return_val_if_fail (GST_IS_APP_SRC (appsrc), NULL); GST_OBJECT_LOCK (appsrc); if ((caps = appsrc->priv->caps)) gst_caps_ref (caps); GST_DEBUG_OBJECT (appsrc, "getting caps of %" GST_PTR_FORMAT, caps); GST_OBJECT_UNLOCK (appsrc); return caps; }
/** * gst_app_src_get_current_level_bytes: * @appsrc: a #GstAppSrc * * Get the number of currently queued bytes inside @appsrc. * * Returns: The number of currently queued bytes. * * Since: 1.2 */ guint64 gst_app_src_get_current_level_bytes (GstAppSrc * appsrc) { gint64 queued; GstAppSrcPrivate *priv; g_return_val_if_fail (GST_IS_APP_SRC (appsrc), -1); priv = appsrc->priv; GST_OBJECT_LOCK (appsrc); queued = priv->queued_bytes; GST_DEBUG_OBJECT (appsrc, "current level bytes is %" G_GUINT64_FORMAT, queued); GST_OBJECT_UNLOCK (appsrc); return queued; }
/** * gst_app_src_set_caps: * @appsrc: a #GstAppSrc * @caps: caps to set * * Set the capabilities on the appsrc element. This function takes * a copy of the caps structure. After calling this method, the source will * only produce caps that match @caps. @caps must be fixed and the caps on the * buffers must match the caps or left NULL. * * Since: 0.10.22 */ void gst_app_src_set_caps (GstAppSrc * appsrc, const GstCaps * caps) { GstCaps *old; g_return_if_fail (GST_IS_APP_SRC (appsrc)); GST_OBJECT_LOCK (appsrc); GST_DEBUG_OBJECT (appsrc, "setting caps to %" GST_PTR_FORMAT, caps); if ((old = appsrc->priv->caps) != caps) { if (caps) appsrc->priv->caps = gst_caps_copy (caps); else appsrc->priv->caps = NULL; if (old) gst_caps_unref (old); } GST_OBJECT_UNLOCK (appsrc); }
/** * gst_app_src_push_buffer: * @appsrc: a #GstAppSrc * @buffer: a #GstBuffer to push * * Adds a buffer to the queue of buffers that the appsrc element will * push to its source pad. This function takes ownership of the buffer. * * Returns: #GST_FLOW_OK when the buffer was successfuly queued. * #GST_FLOW_WRONG_STATE when @appsrc is not PAUSED or PLAYING. * #GST_FLOW_UNEXPECTED when EOS occured. */ GstFlowReturn gst_app_src_push_buffer (GstAppSrc * appsrc, GstBuffer * buffer) { gboolean first = TRUE; g_return_val_if_fail (appsrc, GST_FLOW_ERROR); g_return_val_if_fail (GST_IS_APP_SRC (appsrc), GST_FLOW_ERROR); g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); g_mutex_lock (appsrc->mutex); while (TRUE) { /* can't accept buffers when we are flushing or EOS */ if (appsrc->flushing) goto flushing; if (appsrc->is_eos) goto eos; if (appsrc->queued_bytes >= appsrc->max_bytes) { GST_DEBUG_OBJECT (appsrc, "queue filled (%" G_GUINT64_FORMAT " >= %" G_GUINT64_FORMAT ")", appsrc->queued_bytes, appsrc->max_bytes); if (first) { /* only signal on the first push */ g_mutex_unlock (appsrc->mutex); g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_ENOUGH_DATA], 0, NULL); g_mutex_lock (appsrc->mutex); /* continue to check for flushing/eos after releasing the lock */ first = FALSE; continue; } if (appsrc->block) { GST_DEBUG_OBJECT (appsrc, "waiting for free space"); /* we are filled, wait until a buffer gets popped or when we * flush. */ g_cond_wait (appsrc->cond, appsrc->mutex); } else { /* no need to wait for free space, we just pump data into the queue */ break; } } else break; } GST_DEBUG_OBJECT (appsrc, "queueing buffer %p", buffer); g_queue_push_tail (appsrc->queue, buffer); appsrc->queued_bytes += GST_BUFFER_SIZE (buffer); g_cond_broadcast (appsrc->cond); g_mutex_unlock (appsrc->mutex); return GST_FLOW_OK; /* ERRORS */ flushing: { GST_DEBUG_OBJECT (appsrc, "refuse buffer %p, we are flushing", buffer); gst_buffer_unref (buffer); return GST_FLOW_WRONG_STATE; } eos: { GST_DEBUG_OBJECT (appsrc, "refuse buffer %p, we are EOS", buffer); gst_buffer_unref (buffer); return GST_FLOW_UNEXPECTED; } }
static GstFlowReturn gst_app_src_push_buffer_full (GstAppSrc * appsrc, GstBuffer * buffer, gboolean steal_ref) { gboolean first = TRUE; GstAppSrcPrivate *priv; g_return_val_if_fail (GST_IS_APP_SRC (appsrc), GST_FLOW_ERROR); g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); priv = appsrc->priv; g_mutex_lock (&priv->mutex); while (TRUE) { /* can't accept buffers when we are flushing or EOS */ if (priv->flushing) goto flushing; if (priv->is_eos) goto eos; if (priv->max_bytes && priv->queued_bytes >= priv->max_bytes) { GST_DEBUG_OBJECT (appsrc, "queue filled (%" G_GUINT64_FORMAT " >= %" G_GUINT64_FORMAT ")", priv->queued_bytes, priv->max_bytes); if (first) { gboolean emit; emit = priv->emit_signals; /* only signal on the first push */ g_mutex_unlock (&priv->mutex); if (priv->callbacks.enough_data) priv->callbacks.enough_data (appsrc, priv->user_data); else if (emit) g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_ENOUGH_DATA], 0, NULL); g_mutex_lock (&priv->mutex); /* continue to check for flushing/eos after releasing the lock */ first = FALSE; continue; } if (priv->block) { GST_DEBUG_OBJECT (appsrc, "waiting for free space"); /* we are filled, wait until a buffer gets popped or when we * flush. */ g_cond_wait (&priv->cond, &priv->mutex); } else { /* no need to wait for free space, we just pump more data into the * queue hoping that the caller reacts to the enough-data signal and * stops pushing buffers. */ break; } } else break; } GST_DEBUG_OBJECT (appsrc, "queueing buffer %p", buffer); if (!steal_ref) gst_buffer_ref (buffer); g_queue_push_tail (priv->queue, buffer); priv->queued_bytes += gst_buffer_get_size (buffer); g_cond_broadcast (&priv->cond); g_mutex_unlock (&priv->mutex); return GST_FLOW_OK; /* ERRORS */ flushing: { GST_DEBUG_OBJECT (appsrc, "refuse buffer %p, we are flushing", buffer); if (steal_ref) gst_buffer_unref (buffer); g_mutex_unlock (&priv->mutex); return GST_FLOW_FLUSHING; } eos: { GST_DEBUG_OBJECT (appsrc, "refuse buffer %p, we are EOS", buffer); if (steal_ref) gst_buffer_unref (buffer); g_mutex_unlock (&priv->mutex); return GST_FLOW_EOS; } }
static gboolean byzanz_encoder_gstreamer_run (ByzanzEncoder * encoder, GInputStream * input, GOutputStream * output, gboolean record_audio, GCancellable * cancellable, GError ** error) { ByzanzEncoderGStreamer *gstreamer = BYZANZ_ENCODER_GSTREAMER (encoder); ByzanzEncoderGStreamerClass *klass = BYZANZ_ENCODER_GSTREAMER_GET_CLASS (encoder); GstElement *sink; guint width, height; GstMessage *message; GstBus *bus; if (!byzanz_deserialize_header (input, &width, &height, cancellable, error)) return FALSE; gstreamer->surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); g_assert (klass->pipeline_string); if (record_audio) { if (klass->audio_pipeline_string == NULL) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("This format does not support recording audio.")); return FALSE; } gstreamer->pipeline = gst_parse_launch (klass->audio_pipeline_string, error); gstreamer->audiosrc = gst_bin_get_by_name (GST_BIN (gstreamer->pipeline), "audiosrc"); g_assert (gstreamer->audiosrc); } else { gstreamer->pipeline = gst_parse_launch (klass->pipeline_string, error); } if (gstreamer->pipeline == NULL) return FALSE; g_assert (GST_IS_PIPELINE (gstreamer->pipeline)); gstreamer->src = GST_APP_SRC (gst_bin_get_by_name (GST_BIN (gstreamer->pipeline), "src")); g_assert (GST_IS_APP_SRC (gstreamer->src)); sink = gst_bin_get_by_name (GST_BIN (gstreamer->pipeline), "sink"); g_assert (sink); g_object_set (sink, "stream", output, NULL); g_object_unref (sink); gstreamer->caps = gst_caps_new_simple ("video/x-raw", #if G_BYTE_ORDER == G_LITTLE_ENDIAN "format", G_TYPE_STRING, "BGRx", #elif G_BYTE_ORDER == G_BIG_ENDIAN "format", G_TYPE_STRING, "xRGB", #else #error "Please add the Cairo caps format here" #endif "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, 0, 1, NULL); g_assert (gst_caps_is_fixed (gstreamer->caps)); gst_app_src_set_caps (gstreamer->src, gstreamer->caps); gst_app_src_set_callbacks (gstreamer->src, &callbacks, gstreamer, NULL); gst_app_src_set_stream_type (gstreamer->src, GST_APP_STREAM_TYPE_STREAM); gst_app_src_set_max_bytes (gstreamer->src, 0); g_object_set (gstreamer->src, "format", GST_FORMAT_TIME, NULL); if (!gst_element_set_state (gstreamer->pipeline, GST_STATE_PLAYING)) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to start GStreamer pipeline")); return FALSE; } bus = gst_pipeline_get_bus (GST_PIPELINE (gstreamer->pipeline)); message = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS); g_object_unref (bus); gst_element_set_state (gstreamer->pipeline, GST_STATE_NULL); if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { gst_message_parse_error (message, error, NULL); gst_message_unref (message); return FALSE; } gst_message_unref (message); return TRUE; }