Пример #1
0
/* 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;
}
Пример #2
0
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);
}
Пример #3
0
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;
    }
}
Пример #4
0
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;
    }
}
Пример #5
0
/* 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);
}