/* The create() virtual function is responsible for returning the next buffer. * We just pop buffers off of the queue and block if necessary. */ static GstFlowReturn shell_recorder_src_create (GstPushSrc *push_src, GstBuffer **buffer_out) { ShellRecorderSrc *src = SHELL_RECORDER_SRC (push_src); GstBuffer *buffer; if (src->closed) return GST_FLOW_UNEXPECTED; buffer = g_async_queue_pop (src->queue); if (buffer == RECORDER_QUEUE_END) { /* Returning UNEXPECTED here will cause a EOS message to be sent */ src->closed = TRUE; return GST_FLOW_UNEXPECTED; } shell_recorder_src_update_memory_used (src, - (int)(GST_BUFFER_SIZE(buffer) / 1024)); *buffer_out = buffer; return GST_FLOW_OK; }
static void shell_recorder_src_finalize (GObject *object) { ShellRecorderSrc *src = SHELL_RECORDER_SRC (object); if (src->memory_used_update_idle) g_source_remove (src->memory_used_update_idle); shell_recorder_src_set_caps (src, NULL); g_async_queue_unref (src->queue); g_mutex_clear (src->mutex); G_OBJECT_CLASS (parent_class)->finalize (object); }
static void shell_recorder_src_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ShellRecorderSrc *src = SHELL_RECORDER_SRC (object); switch (prop_id) { case PROP_CAPS: shell_recorder_src_set_caps (src, gst_value_get_caps (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void shell_recorder_src_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ShellRecorderSrc *src = SHELL_RECORDER_SRC (object); switch (prop_id) { case PROP_CAPS: gst_value_set_caps (value, src->caps); break; case PROP_MEMORY_USED: g_mutex_lock (src->mutex); g_value_set_uint (value, src->memory_used); g_mutex_unlock (src->mutex); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
/* Retrieve a frame and feed it into the pipeline */ static void recorder_record_frame (ShellRecorder *recorder, gboolean paint) { GstBuffer *buffer; ClutterCapture *captures; int n_captures; cairo_surface_t *image; guint size; uint8_t *data; GstMemory *memory; int i; GstClock *clock; GstClockTime now, base_time; g_return_if_fail (recorder->current_pipeline != NULL); /* If we get into the red zone, stop buffering new frames; 13/16 is * a bit more than the 3/4 threshold for a red indicator to keep the * indicator from flashing between red and yellow. */ if (recorder->memory_used > (recorder->memory_target * 13) / 16) return; /* Drop frames to get down to something like the target frame rate; since frames * are generated with VBlank sync, we don't have full control anyways, so we just * drop frames if the interval since the last frame is less than 75% of the * desired inter-frame interval. */ clock = gst_element_get_clock (recorder->current_pipeline->src); /* If we have no clock yet, the pipeline is not yet in PLAYING */ if (!clock) return; base_time = gst_element_get_base_time (recorder->current_pipeline->src); now = gst_clock_get_time (clock) - base_time; gst_object_unref (clock); if (GST_CLOCK_TIME_IS_VALID (recorder->last_frame_time) && now - recorder->last_frame_time < gst_util_uint64_scale_int (GST_SECOND, 3, 4 * recorder->framerate)) return; recorder->last_frame_time = now; clutter_stage_capture (recorder->stage, paint, &recorder->area, &captures, &n_captures); if (n_captures == 0) return; if (n_captures == 1) image = cairo_surface_reference (captures[0].image); else image = shell_util_composite_capture_images (captures, n_captures, recorder->area.x, recorder->area.y, recorder->area.width, recorder->area.height); data = cairo_image_surface_get_data (image); size = (cairo_image_surface_get_height (image) * cairo_image_surface_get_stride (image)); for (i = 0; i < n_captures; i++) cairo_surface_destroy (captures[i].image); g_free (captures); buffer = gst_buffer_new(); memory = gst_memory_new_wrapped (0, data, size, 0, size, image, (GDestroyNotify) cairo_surface_destroy); gst_buffer_insert_memory (buffer, -1, memory); GST_BUFFER_PTS(buffer) = now; if (recorder->draw_cursor && !g_settings_get_boolean (recorder->a11y_settings, MAGNIFIER_ACTIVE_KEY)) recorder_draw_cursor (recorder, buffer); shell_recorder_src_add_buffer (SHELL_RECORDER_SRC (recorder->current_pipeline->src), buffer); gst_buffer_unref (buffer); /* Reset the timeout that we used to avoid an overlong pause in the stream */ recorder_remove_redraw_timeout (recorder); recorder_add_redraw_timeout (recorder); }