[byzanz] Allow to record sound



commit 60cc168f6cf1294b07ce3b8fea74a2280150abdc
Author: Benjamin Otte <otte redhat com>
Date:   Mon Feb 8 17:19:05 2010 +0100

    Allow to record sound
    
    Only the Theora encoder supports this. Other formats will throw an error
    at people.

 src/byzanzapplet.c           |   15 ++++++++++++++-
 src/byzanzencoder.c          |   26 +++++++++++++++++++++++---
 src/byzanzencoder.h          |    3 +++
 src/byzanzencodergstreamer.c |   18 ++++++++++++++++--
 src/byzanzencodergstreamer.h |    2 ++
 src/byzanzencoderogv.c       |    4 ++++
 src/byzanzsession.c          |   18 +++++++++++++++---
 src/byzanzsession.h          |    4 +++-
 src/playback.c               |    2 +-
 src/record.c                 |    4 +++-
 10 files changed, 84 insertions(+), 12 deletions(-)
---
diff --git a/src/byzanzapplet.c b/src/byzanzapplet.c
index c5742e5..2041a35 100644
--- a/src/byzanzapplet.c
+++ b/src/byzanzapplet.c
@@ -191,7 +191,8 @@ byzanz_applet_select_done (GdkWindow *window, const GdkRectangle *area, gpointer
 
     if (encoder_type == 0)
       encoder_type = byzanz_encoder_get_type_from_file (priv->file);
-    priv->rec = byzanz_session_new (priv->file, encoder_type, window, area, TRUE);
+    priv->rec = byzanz_session_new (priv->file, encoder_type, window, area, FALSE,
+        panel_applet_gconf_get_bool (priv->applet, "record_audio", NULL));
     g_signal_connect_swapped (priv->rec, "notify", G_CALLBACK (byzanz_applet_session_notify), priv);
     byzanz_session_start (priv->rec);
   }
@@ -234,6 +235,10 @@ panel_applet_start_response (GtkWidget *dialog, int response, AppletPrivate *pri
     priv->encoder_type = 0;
   }
 
+  panel_applet_gconf_set_bool (priv->applet, "record_audio",
+      gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
+          gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (priv->dialog)))), NULL);
+
   gtk_widget_destroy (dialog);
   priv->dialog = NULL;
   byzanz_select_method_select (priv->method, byzanz_applet_select_done, priv);
@@ -284,6 +289,14 @@ byzanz_applet_start_recording (AppletPrivate *priv)
         g_object_unref (filter);
       }
     }
+
+    gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (priv->dialog),
+        gtk_check_button_new_with_label (_("Record audio")));
+    if (panel_applet_gconf_get_bool (priv->applet, "record_audio", NULL)) {
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (
+          gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (priv->dialog))), TRUE);
+    }
+
     gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (priv->dialog), FALSE);
     uri = panel_applet_gconf_get_string (priv->applet, "save_filename", NULL);
     if (!uri || uri[0] == '\0' ||
diff --git a/src/byzanzencoder.c b/src/byzanzencoder.c
index 5846d34..f899e7a 100644
--- a/src/byzanzencoder.c
+++ b/src/byzanzencoder.c
@@ -23,6 +23,8 @@
 
 #include "byzanzencoder.h"
 
+#include <glib/gi18n-lib.h>
+
 #include "byzanzserialize.h"
 
 typedef struct _ByzanzEncoderJob ByzanzEncoderJob;
@@ -71,6 +73,7 @@ static gboolean
 byzanz_encoder_run (ByzanzEncoder * encoder,
                     GInputStream *  input,
                     GOutputStream * output,
+                    gboolean        record_audio,
                     GCancellable *  cancellable,
                     GError **	    error)
 {
@@ -81,6 +84,12 @@ byzanz_encoder_run (ByzanzEncoder * encoder,
   guint64 msecs;
   gboolean success;
 
+  if (record_audio) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+        _("This format does not support recording audio."));
+    return FALSE;
+  }
+
   if (!byzanz_deserialize_header (input, &width, &height, cancellable, error) ||
       !klass->setup (encoder, output, width, height, cancellable, error))
     return FALSE;
@@ -112,7 +121,7 @@ byzanz_encoder_thread (gpointer enc)
   GError *error = NULL;
   
   klass->run (encoder, encoder->input_stream, encoder->output_stream,
-      encoder->cancellable, &error);
+      encoder->record_audio, encoder->cancellable, &error);
 
   g_idle_add_full (G_PRIORITY_DEFAULT, byzanz_encoder_finished, enc, NULL);
   return error;
@@ -124,6 +133,7 @@ enum {
   PROP_0,
   PROP_INPUT,
   PROP_OUTPUT,
+  PROP_SOUND,
   PROP_CANCELLABLE,
   PROP_ERROR,
   PROP_RUNNING
@@ -197,6 +207,9 @@ byzanz_encoder_get_property (GObject *object, guint param_id, GValue *value,
     case PROP_OUTPUT:
       g_value_set_object (value, encoder->output_stream);
       break;
+    case PROP_SOUND:
+      g_value_set_boolean (value, encoder->record_audio);
+      break;
     case PROP_CANCELLABLE:
       g_value_set_object (value, encoder->cancellable);
       break;
@@ -227,6 +240,9 @@ byzanz_encoder_set_property (GObject *object, guint param_id, const GValue *valu
       encoder->output_stream = g_value_dup_object (value);
       g_assert (encoder->output_stream != NULL);
       break;
+    case PROP_SOUND:
+      encoder->record_audio = g_value_get_boolean (value);
+      break;
     case PROP_CANCELLABLE:
       encoder->cancellable = g_value_dup_object (value);
       break;
@@ -285,6 +301,9 @@ byzanz_encoder_class_init (ByzanzEncoderClass *klass)
   g_object_class_install_property (object_class, PROP_OUTPUT,
       g_param_spec_object ("output", "output", "stream to write data to",
 	  G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property (object_class, PROP_SOUND,
+      g_param_spec_boolean ("record-audio", "record audio", "TRUE when recording audio",
+	  FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
   g_object_class_install_property (object_class, PROP_CANCELLABLE,
       g_param_spec_object ("cancellable", "cancellable", "cancellable for stopping the thread",
 	  G_TYPE_CANCELLABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
@@ -310,6 +329,7 @@ ByzanzEncoder *
 byzanz_encoder_new (GType           encoder_type,
                     GInputStream *  input,
                     GOutputStream * output,
+                    gboolean        record_audio,
                     GCancellable *  cancellable)
 {
   ByzanzEncoder *encoder;
@@ -319,8 +339,8 @@ byzanz_encoder_new (GType           encoder_type,
   g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), NULL);
   g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 
-  encoder = g_object_new (encoder_type, "input", input, "output", output,
-      "cancellable", cancellable, NULL);
+  encoder = g_object_new (encoder_type, "input", input, "output", output, 
+      "record-audio", record_audio, "cancellable", cancellable, NULL);
 
   return encoder;
 }
diff --git a/src/byzanzencoder.h b/src/byzanzencoder.h
index 8d711a6..54f816e 100644
--- a/src/byzanzencoder.h
+++ b/src/byzanzencoder.h
@@ -43,6 +43,7 @@ struct _ByzanzEncoder {
   /*<private >*/
   GInputStream *        input_stream;           /* stream to read from in byzanzserialize.h format */
   GOutputStream *       output_stream;          /* stream we write to (passed to the vfuncs) */
+  gboolean              record_audio;           /* TRUE when we're recording audio */
   GCancellable *        cancellable;            /* cancellable to use in thread */
   GError *              error;                  /* NULL or the encoding error */
 
@@ -60,6 +61,7 @@ struct _ByzanzEncoderClass {
   gboolean              (* run)                 (ByzanzEncoder *        encoder,
                                                  GInputStream *         input,
                                                  GOutputStream *        output,
+                                                 gboolean               record_audio,
                                                  GCancellable *         cancellable,
 						 GError **		error);
 
@@ -89,6 +91,7 @@ GType		byzanz_encoder_get_type		(void) G_GNUC_CONST;
 ByzanzEncoder *	byzanz_encoder_new		(GType                  encoder_type,
                                                  GInputStream *         input,
                                                  GOutputStream *        output,
+                                                 gboolean               record_audio,
                                                  GCancellable *         cancellable);
 /*
 void		byzanz_encoder_process		(ByzanzEncoder *	encoder,
diff --git a/src/byzanzencodergstreamer.c b/src/byzanzencodergstreamer.c
index 179dc6f..2d89bab 100644
--- a/src/byzanzencodergstreamer.c
+++ b/src/byzanzencodergstreamer.c
@@ -23,7 +23,7 @@
 
 #include "byzanzencodergstreamer.h"
 
-#include <glib/gi18n.h>
+#include <glib/gi18n-lib.h>
 #include <gst/app/gstappbuffer.h>
 #include <gst/video/video.h>
 
@@ -52,6 +52,8 @@ byzanz_encoder_gstreamer_need_data (GstAppSrc *src, guint length, gpointer data)
 
   if (surface == NULL) {
     gst_app_src_end_of_stream (gst->src);
+    if (gst->audiosrc)
+      gst_element_send_event (gst->audiosrc, gst_event_new_eos ());
     return;
   }
 
@@ -93,6 +95,7 @@ static gboolean
 byzanz_encoder_gstreamer_run (ByzanzEncoder * encoder,
                               GInputStream *  input,
                               GOutputStream * output,
+                              gboolean        record_audio,
                               GCancellable *  cancellable,
                               GError **	      error)
 {
@@ -109,7 +112,18 @@ byzanz_encoder_gstreamer_run (ByzanzEncoder * encoder,
   gstreamer->surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
 
   g_assert (klass->pipeline_string);
-  gstreamer->pipeline = gst_parse_launch (klass->pipeline_string, error);
+  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;
 
diff --git a/src/byzanzencodergstreamer.h b/src/byzanzencodergstreamer.h
index 3dde771..77ea20f 100644
--- a/src/byzanzencodergstreamer.h
+++ b/src/byzanzencodergstreamer.h
@@ -42,6 +42,7 @@ struct _ByzanzEncoderGStreamer {
   GTimeVal              start_time;     /* timestamp of first image */
 
   GstElement *          pipeline;       /* The pipeline */
+  GstElement *          audiosrc;       /* the source we record audio from */
   GstAppSrc *           src;            /* the source we feed with images */
   GstCaps *             caps;           /* caps of video stream */
 };
@@ -50,6 +51,7 @@ struct _ByzanzEncoderGStreamerClass {
   ByzanzEncoderClass    encoder_class;
 
   const char *          pipeline_string;
+  const char *          audio_pipeline_string;
 };
 
 GType		byzanz_encoder_gstreamer_get_type		(void) G_GNUC_CONST;
diff --git a/src/byzanzencoderogv.c b/src/byzanzencoderogv.c
index dd6a379..f834b77 100644
--- a/src/byzanzencoderogv.c
+++ b/src/byzanzencoderogv.c
@@ -43,6 +43,10 @@ byzanz_encoder_ogv_class_init (ByzanzEncoderOgvClass *klass)
   gstreamer_class->pipeline_string = 
     "appsrc name=src ! ffmpegcolorspace ! videorate ! "
     "video/x-raw-yuv,framerate=25/1 ! theoraenc ! oggmux ! giostreamsink name=sink";
+  gstreamer_class->audio_pipeline_string = 
+    "autoaudiosrc name=audiosrc ! audioconvert ! vorbisenc ! queue ! oggmux name=muxer ! giostreamsink name=sink "
+    "appsrc name=src ! ffmpegcolorspace ! videorate ! "
+    "video/x-raw-yuv,framerate=25/1 ! theoraenc ! queue ! muxer.";
 }
 
 static void
diff --git a/src/byzanzsession.c b/src/byzanzsession.c
index d3f0c80..df36c62 100644
--- a/src/byzanzsession.c
+++ b/src/byzanzsession.c
@@ -51,6 +51,7 @@ enum {
   PROP_FILE,
   PROP_AREA,
   PROP_WINDOW,
+  PROP_AUDIO,
   PROP_ENCODER_TYPE
 };
 
@@ -81,6 +82,9 @@ byzanz_session_get_property (GObject *object, guint param_id, GValue *value,
     case PROP_WINDOW:
       g_value_set_object (value, session->window);
       break;
+    case PROP_AUDIO:
+      g_value_set_boolean (value, session->record_audio);
+      break;
     case PROP_ENCODER_TYPE:
       g_value_set_gtype (value, session->encoder_type);
       break;
@@ -106,6 +110,9 @@ byzanz_session_set_property (GObject *object, guint param_id, const GValue *valu
     case PROP_WINDOW:
       session->window = g_value_dup_object (value);
       break;
+    case PROP_AUDIO:
+      session->record_audio = g_value_get_boolean (value);
+      break;
     case PROP_ENCODER_TYPE:
       session->encoder_type = g_value_get_gtype (value);
       break;
@@ -245,7 +252,7 @@ byzanz_session_constructed (GObject *object)
   if (stream != NULL) {
     session->encoder = byzanz_encoder_new (session->encoder_type, 
         byzanz_queue_get_input_stream (session->queue),
-        stream, session->cancellable);
+        stream, session->record_audio, session->cancellable);
     g_signal_connect (session->encoder, "notify", 
         G_CALLBACK (byzanz_session_encoder_notify_cb), session);
     g_object_unref (stream);
@@ -288,6 +295,9 @@ byzanz_session_class_init (ByzanzSessionClass *klass)
   g_object_class_install_property (object_class, PROP_FILE,
       g_param_spec_object ("file", "file", "file to record to",
 	  G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property (object_class, PROP_AUDIO,
+      g_param_spec_boolean ("record-audio", "record audio", "TRUE to record audio",
+	  FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
   g_object_class_install_property (object_class, PROP_ENCODER_TYPE,
       g_param_spec_gtype ("encoder-type", "encoder type", "type for the encoder to use",
 	  BYZANZ_TYPE_ENCODER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
@@ -307,6 +317,7 @@ byzanz_session_init (ByzanzSession *session)
  * @window: window to record
  * @area: area of window that should be recorded
  * @record_cursor: if the cursor image should be recorded
+ * @record_audio: if audio should be recorded
  *
  * Creates a new #ByzanzSession and initializes all basic variables. 
  * gtk_init() and g_thread_init() must have been called before.
@@ -317,7 +328,8 @@ byzanz_session_init (ByzanzSession *session)
  **/
 ByzanzSession *
 byzanz_session_new (GFile *file, GType encoder_type, 
-    GdkWindow *window, const GdkRectangle *area, gboolean record_cursor)
+    GdkWindow *window, const GdkRectangle *area, gboolean record_cursor,
+    gboolean record_audio)
 {
   g_return_val_if_fail (G_IS_FILE (file), NULL);
   g_return_val_if_fail (g_type_is_a (encoder_type, BYZANZ_TYPE_ENCODER), NULL);
@@ -331,7 +343,7 @@ byzanz_session_new (GFile *file, GType encoder_type,
   /* FIXME: handle mouse cursor */
 
   return g_object_new (BYZANZ_TYPE_SESSION, "file", file, "encoder-type", encoder_type,
-      "window", window, "area", area, NULL);
+      "window", window, "area", area, "record-audio", record_audio, NULL);
 }
 
 void
diff --git a/src/byzanzsession.h b/src/byzanzsession.h
index db95825..ed6c32d 100644
--- a/src/byzanzsession.h
+++ b/src/byzanzsession.h
@@ -45,6 +45,7 @@ struct _ByzanzSession {
   GFile *               file;           /* file we're saving to */
   GdkRectangle          area;           /* area of window to record */
   GdkWindow *           window;         /* window to record */
+  gboolean              record_audio;   /* TRUE to record audio */
   GType                 encoder_type;   /* type of encoder to use */
   ByzanzQueue *         queue;          /* queue we use as data cache */
   GTimeVal              start_time;     /* when we started writing to queue */
@@ -67,7 +68,8 @@ ByzanzSession * 	byzanz_session_new		(GFile *                file,
                                                          GType                  encoder_type,
 							 GdkWindow *		window,
 							 const GdkRectangle *	area,
-							 gboolean		record_cursor);
+							 gboolean		record_cursor,
+                                                         gboolean               record_audio);
 void			byzanz_session_start		(ByzanzSession *	session);
 void			byzanz_session_stop		(ByzanzSession *	session);
 void			byzanz_session_abort            (ByzanzSession *	session);
diff --git a/src/playback.c b/src/playback.c
index 813ff65..f5087e1 100644
--- a/src/playback.c
+++ b/src/playback.c
@@ -109,7 +109,7 @@ main (int argc, char **argv)
     return 1;
   }
   encoder = byzanz_encoder_new (byzanz_encoder_get_type_from_file (outfile),
-      instream, outstream, NULL);
+      instream, outstream, FALSE, NULL);
   
   g_signal_connect (encoder, "notify", G_CALLBACK (encoder_notify), loop);
   
diff --git a/src/record.c b/src/record.c
index 6cdff64..fa29397 100644
--- a/src/record.c
+++ b/src/record.c
@@ -28,6 +28,7 @@
 static int duration = 10;
 static int delay = 1;
 static gboolean cursor = FALSE;
+static gboolean audio = FALSE;
 static gboolean verbose = FALSE;
 static GdkRectangle area = { 0, 0, G_MAXINT / 2, G_MAXINT / 2 };
 
@@ -36,6 +37,7 @@ static GOptionEntry entries[] =
   { "duration", 'd', 0, G_OPTION_ARG_INT, &duration, N_("Duration of animation (default: 10 seconds)"), N_("SECS") },
   { "delay", 0, 0, G_OPTION_ARG_INT, &delay, N_("Delay before start (default: 1 second)"), N_("SECS") },
   { "cursor", 'c', 0, G_OPTION_ARG_NONE, &cursor, N_("Record mouse cursor"), NULL },
+  { "audio", 'a', 0, G_OPTION_ARG_NONE, &audio, N_("Record audio"), NULL },
   { "x", 'x', 0, G_OPTION_ARG_INT, &area.x, N_("X coordinate of rectangle to record"), N_("PIXEL") },
   { "y", 'y', 0, G_OPTION_ARG_INT, &area.y, N_("Y coordinate of rectangle to record"), N_("PIXEL") },
   { "width", 'w', 0, G_OPTION_ARG_INT, &area.width, N_("Width of recording rectangle"), N_("PIXEL") },
@@ -149,7 +151,7 @@ main (int argc, char **argv)
   }
   file = g_file_new_for_commandline_arg (argv[1]);
   rec = byzanz_session_new (file, byzanz_encoder_get_type_from_file (file),
-      gdk_get_default_root_window (), &area, cursor);
+      gdk_get_default_root_window (), &area, cursor, audio);
   g_object_unref (file);
   g_signal_connect (rec, "notify", G_CALLBACK (session_notify_cb), NULL);
   delay = MAX (delay, 1);



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