[gnome-shell] ShellRecorder: drop frames to approximate the target framerate



commit 60d8683ae750905929f974aa38a83725de02532a
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Mon Jan 30 16:44:32 2012 -0500

    ShellRecorder: drop frames to approximate the target framerate
    
    Instead of adding every rendered frame into the recording, drop frames
    and only buffer and record enough frames to match the target framerate.
    
    Increase the default frame rate from 15 to 30, since now that we're
    actually enforcing framerate, it's noticeable that 15fps is not smooth.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=669066

 data/org.gnome.shell.gschema.xml.in |    2 +-
 src/shell-recorder.c                |   40 +++++++++++++++++++++++++---------
 2 files changed, 30 insertions(+), 12 deletions(-)
---
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
index 325f408..00bba5d 100644
--- a/data/org.gnome.shell.gschema.xml.in
+++ b/data/org.gnome.shell.gschema.xml.in
@@ -108,7 +108,7 @@
   <schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/"
           gettext-domain="@GETTEXT_PACKAGE@">
     <key name="framerate" type="i">
-      <default>15</default>
+      <default>30</default>
       <_summary>Framerate used for recording screencasts.</_summary>
       <_description>
         The framerate of the resulting screencast recordered
diff --git a/src/shell-recorder.c b/src/shell-recorder.c
index 0575856..2e1f3ae 100644
--- a/src/shell-recorder.c
+++ b/src/shell-recorder.c
@@ -77,6 +77,7 @@ struct _ShellRecorder {
   GSList *pipelines; /* all pipelines */
 
   GstClockTime start_time; /* When we started recording (adjusted for pauses) */
+  GstClockTime last_frame_time; /* Timestamp for the last frame */
   GstClockTime pause_time; /* When the pipeline was paused */
 
   /* GSource IDs for different timeouts and idles */
@@ -117,14 +118,12 @@ enum {
 
 G_DEFINE_TYPE(ShellRecorder, shell_recorder, G_TYPE_OBJECT);
 
-/* The number of frames per second we configure for the GStreamer pipeline.
- * (the number of frames we actually write into the GStreamer pipeline is
- * based entirely on how fast clutter is drawing.) Using 60fps seems high
- * but the observed smoothness is a lot better than for 30fps when encoding
- * as theora for a minimal size increase. This may be an artifact of the
- * encoding process.
+/* The default value of the target frame rate; we'll never record more
+ * than this many frames per second, though we may record less if the
+ * screen isn't being redrawn. 30 is a compromise between smoothness
+ * and the size of the recording.
  */
-#define DEFAULT_FRAMES_PER_SECOND 15
+#define DEFAULT_FRAMES_PER_SECOND 30
 
 /* The time (in milliseconds) between querying the server for the cursor
  * position.
@@ -525,6 +524,7 @@ recorder_record_frame (ShellRecorder *recorder)
   GstBuffer *buffer;
   guint8 *data;
   guint size;
+  GstClockTime now;
 
   /* 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
@@ -532,6 +532,17 @@ recorder_record_frame (ShellRecorder *recorder)
   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.
+   */
+  now = get_wall_time();
+  if (now - recorder->last_frame_time < (3 * 1000000000LL / (4 * recorder->framerate)))
+    return;
+
+  recorder->last_frame_time = now;
+
   size = recorder->stage_width * recorder->stage_height * 4;
 
   data = shell_screen_grabber_grab (recorder->grabber,
@@ -541,8 +552,7 @@ recorder_record_frame (ShellRecorder *recorder)
   GST_BUFFER_SIZE(buffer) = size;
   GST_BUFFER_MALLOCDATA(buffer) = GST_BUFFER_DATA(buffer) = data;
 
-  GST_BUFFER_TIMESTAMP(buffer) = get_wall_time() - recorder->start_time;
-
+  GST_BUFFER_TIMESTAMP(buffer) = now - recorder->start_time;
 
   recorder_draw_cursor (recorder, buffer);
 
@@ -1568,9 +1578,15 @@ shell_recorder_new (ClutterStage  *stage)
  * @recorder: the #ShellRecorder
  * @framerate: Framerate used for resulting video in frames-per-second.
  *
- * Sets the number of frames per second we configure for the GStreamer pipeline.
+ * Sets the number of frames per second we try to record. Less frames
+ * will be recorded when the screen doesn't need to be redrawn this
+ * quickly. (This value will also be set as the framerate for the
+ * GStreamer pipeline; whether that has an effect on the resulting
+ * video will depend on the details of the pipeline and the codec. The
+ * default encoding to webm format doesn't pay attention to the pipeline
+ * framerate.)
  *
- * The default value is 15.
+ * The default value is 30.
  */
 void
 shell_recorder_set_framerate (ShellRecorder *recorder,
@@ -1672,6 +1688,7 @@ shell_recorder_record (ShellRecorder *recorder)
        * pause
        */
       recorder->start_time = recorder->start_time + (get_wall_time() - recorder->pause_time);
+      recorder->last_frame_time = 0;
     }
   else
     {
@@ -1679,6 +1696,7 @@ shell_recorder_record (ShellRecorder *recorder)
         return FALSE;
 
       recorder->start_time = get_wall_time();
+      recorder->last_frame_time = 0;
     }
 
   recorder->state = RECORDER_STATE_RECORDING;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]