[gnome-devel-docs] webcam demo: add tutorial



commit 22fbe9de80bb21f83f23f1b29674a75ea0450030
Author: daniel g. siegel <dgsiegel gnome org>
Date:   Fri Dec 3 23:56:58 2010 +0100

    webcam demo: add tutorial

 demos/webcam/webcam.vala.page |  410 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 410 insertions(+), 0 deletions(-)
---
diff --git a/demos/webcam/webcam.vala.page b/demos/webcam/webcam.vala.page
new file mode 100644
index 0000000..e451172
--- /dev/null
+++ b/demos/webcam/webcam.vala.page
@@ -0,0 +1,410 @@
+<page xmlns="http://projectmallard.org/1.0/";
+      type="topic"
+      id="webcam.vala">
+
+  <info>
+
+    <link type="guide" xref="index"/>
+
+    <link type="seealso" xref="index"/>
+
+    <desc>XXX</desc>
+
+    <revision pkgversion="0.1" version="0.1" date="2010-12-02" status="stub"/>
+    <credit type="author">
+      <name>GNOME Documentation Project</name>
+      <email>gnome-doc-list gnome org</email>
+    </credit>
+
+  </info>
+
+<title>Write a webcam application in 15 minutes</title>
+
+<synopsis>
+  <p>In this tutorial, you will learn:</p>
+  <list>
+    <item><p>How to create a GTK+ Application</p></item>
+    <item><p>How to access your webcam using GStreamer and embedding the result into your application</p></item>
+    <item><p>How to grap photos off your webcam</p></item>
+    <item><p>We need these tools/libraries</p>
+      <list>
+        <item><p>GTK+</p></item>
+        <item><p>GStreamer</p></item>
+        <item><p>Vala</p></item>
+      </list>
+    </item>
+  </list>
+</synopsis>
+
+<media type="image" mime="image/png" src="example.png"/>
+
+<section>
+  <title>The story...</title>
+  <p>Who doesn't know it: your mirror just fell off the wall and broke in
+  thousand pieces and you need a mirror to shave your beard of or add some make
+  up. You only have 15 minutes left, before catching the bus to work. But
+  breaking a thing, mend your luck. And you are very lucky, because I am going
+  to show you how to write a webcam application in 15 minutes.</p>
+
+  <p>This tutorial is split up in 4 easy steps:</p>
+  <list>
+    <item><p>Create an empty window with GTK+</p></item>
+    <item><p>Access the camera and have a look at yourself</p></item>
+    <item><p>Embed the video into the GTK+ window</p></item>
+    <item><p>Add buttons to control the application</p></item>
+  </list>
+</section>
+
+<section>
+  <title>Create an empty window with GTK+</title>
+  <p>
+  Let's start with creating an empty file named <file>webcam.vala</file>.
+  </p>
+  <code mime="text/x-vala" style="numbered">
+using Gtk;
+
+public class Webcam : Gtk.Window
+{
+
+  public Webcam ()
+  {
+    this.set_title ("Press play to start");
+    this.destroy.connect (Gtk.main_quit);
+  }
+
+  public static int main (string[] args)
+  {
+    Gtk.init (ref args);
+
+    var webcam = new Webcam ();
+    webcam.show_all ();
+
+    Gtk.main ();
+
+    return 0;
+  }
+}
+  </code>
+
+  <p>
+  That code above will give us an empty window with a title. Awesome work! Now
+  let's have a closer look on it: <code>using Gtk;</code> will tell the Vala
+  compiler to include the needed files and libraries from the GTK+ package. We
+  then create a class named <code>Webcam</code>, which inherits from 
+  <code>Gtk.Window</code>. And that creates already the window for us. By using
+  <code>this</code>, we can access the window. And we are doing that right away
+  by setting a window title and connect the close button to the <code>Gtk.main_quit</code>
+  method. The <code>main</code> method now just initializes GTK+ and creates a
+  new <code>Webcam</code> object. <code>webcam.show_all ()</code> is
+  responsible to show the window and all widgets we put into it later.
+  </p>
+
+  <p>
+  In order to run this demo just save the code into a file (for instance
+  webcam.vala) and run the following command:
+  </p>
+
+  <screen>
+  valac --pkg gtk+-2.0 --pkg gdk-x11-2.0 --pkg gstreamer-0.10 \
+        --pkg gstreamer-interfaces-0.10 webcam.vala
+  </screen>
+
+  <p>
+  You will end up with an executable <file>webcam</file>, which you can run.
+  </p>
+</section>
+
+
+<section>
+  <title>Access the camera and have a look at yourself</title>
+  <p>Let's add GStreamer to our application and have a look at our beautiful
+  faces</p>
+
+  <code mime="text/x-vala" style="numbered">
+using Gtk;
+using Gst;
+
+public class Webcam : Gtk.Window
+{
+  private Gtk.DrawingArea drawing_area;
+  private Gst.Element camerabin;
+
+  public Webcam ()
+  {
+    this.set_title ("Press play to start");
+    this.destroy.connect (Gtk.main_quit);
+
+    var vbox = new Gtk.VBox (false, 0);
+    this.drawing_area = new Gtk.DrawingArea ();
+    this.drawing_area.set_size_request (640, 480);
+    vbox.pack_start (this.drawing_area, true, true, 0);
+
+    this.add (vbox);
+
+    this.camerabin = Gst.ElementFactory.make ("camerabin", "camera");
+    this.camerabin.set_state (Gst.State.PLAYING);
+  }
+
+  public static int main (string[] args)
+  {
+    Gst.init (ref args);
+    Gtk.init (ref args);
+
+    var webcam = new Webcam ();
+    webcam.show_all ();
+
+    Gtk.main ();
+
+    return 0;
+  }
+}
+  </code>
+
+  <p>
+  First we need <code>using Gst;</code> to also include the GStreamer
+  libraries. We declare a <code>Gtk.DrawingArea</code>, which will be the
+  element which holds our video feed afterwards. As we want to add buttons too
+  later, it is a good idea to add a vertical box, where we can put widgets
+  into. This is done by <code>vbox.pack_start</code>. Of course, we need to add
+  the box to the window, which is done by writing <code>this.add (vbox)</code>.
+  </p>
+
+  <p>
+  Now we are creating a GStreamer element, which accesses our webcam. We are
+  using the Camerabin element, which is an all-in-one camera element and is
+  capable of taking photos, videos, applying effects and much more. Perfect for
+  our use case! With <code>this.camerabin.set_state (Gst.State.PLAYING)</code>
+  we tell the GStreamer pipeline we just created to start playing. Easy, not?
+  </p>
+
+  <p>
+  Compile and run it again. You will end up with two windows. In the next step
+  we will integrate the video into the GTK+ window.
+  </p>
+</section>
+
+<section>
+  <title>Embed the video into the GTK+ window</title>
+  <p>
+  After this step you will have a full featured webcam viewer, that are
+  awesome news, aren't they?
+  </p>
+
+  <code mime="text/x-vala" style="numbered">
+using Gtk;
+using Gst;
+
+public class Webcam : Gtk.Window
+{
+  private Gtk.DrawingArea drawing_area;
+  private Gst.Element camerabin;
+  private static X.ID xid;
+
+  public Webcam ()
+  {
+    this.set_title ("Press play to start");
+    this.destroy.connect (Gtk.main_quit);
+
+    var vbox = new Gtk.VBox (false, 0);
+    this.drawing_area = new Gtk.DrawingArea ();
+    this.drawing_area.set_size_request (640, 480);
+    this.drawing_area.realize.connect (on_realize);
+    vbox.pack_start (this.drawing_area, true, true, 0);
+
+    this.add (vbox);
+
+    this.camerabin = Gst.ElementFactory.make ("camerabin", "camera");
+    var bus = this.camerabin.get_bus ();
+    bus.set_sync_handler (on_bus_callback);
+  }
+
+  private Gst.BusSyncReply on_bus_callback (Gst.Bus bus, Gst.Message message)
+  {
+    if (message.get_structure () != null &amp;&amp; message.get_structure().has_name("prepare-xwindow-id")) {
+      var xoverlay = message.src as Gst.XOverlay;
+      xoverlay.set_xwindow_id (this.xid);
+      return Gst.BusSyncReply.DROP;
+    }
+
+    return Gst.BusSyncReply.PASS;
+  }
+
+  private void on_realize ()
+  {
+    this.xid = Gdk.x11_drawable_get_xid (this.drawing_area.window);
+    this.camerabin.set_state (Gst.State.PLAYING);
+  }
+
+  public static int main (string[] args)
+  {
+    Gst.init (ref args);
+    Gtk.init (ref args);
+
+    var webcam = new Webcam ();
+    webcam.show_all ();
+
+    Gtk.main ();
+
+    return 0;
+  }
+}
+  </code>
+
+  <p>
+  Now we are making our hands dirty. Did you ever hear about X window id? No?
+  Doesn't matter, just remember this: Every window has a unique id, which
+  identifies that specific window. What we want to do now is to get the X
+  window id of our GTK+ window and then set the X window id of the GStreamer
+  overlay to that specific id. We could now run into two problems:
+  </p>
+
+  <list>
+    <item><p>The X window id of any window is only available after you can see it
+    on your screen</p></item>
+    <item><p>We only can set the X window id of the GStreamer overlay before it
+    has started to get data from the webcam.</p></item>
+  </list>
+
+  <p>
+  As you probably can imagine, many things can go wrong with the above points.
+  So we need to make sure to first get the X window id from the GTK+ window and
+  after that is done, set it on the GStreamer overlay before it has started.
+  With <code>this.drawing_area.realize.connect (on_realize);</code> we hook on
+  the <code>realize</code> signal GTK+ will send after it is drawn on the screen
+  and call our method <code>on_realize</code>. There we just get the X window
+  id and store it in the static variable <code>this.xid</code>. This variable
+  has to be static, as we have to make sure that it stays the same througout
+  the context and threads of the application. After that is done, we can just
+  start our GStreamer pipeline.
+  </p>
+
+  <p>
+  To intercept the GStreamer overlay, just before it is drawn and put it into
+  the GTK+ window we need to listen to the signals GStreamer is sending around.
+  First we need to get the bus, over which the messages flow using
+  <code>this.camerabin.get_bus ();</code> and then, like before with the
+  realize signal we are hooking into the messages of that pipeline using our
+  own function <code>on_bus_callback</code>.
+  </p>
+
+  <p>
+  There are a lot of messages coming in, so first we need to make sure that it
+  is a message, we can process using <code>message.get_structure () != null</code> and then 
+  we just want to get the one message with the name <code>prepare-xwindow-id</code>. This 
+  signal is sent when the pipeline is ready and waiting for an X window id. We
+  get the source of the signal, which actually is our pipeline and set the X
+  window id we got before <code>xoverlay.set_xwindow_id (this.xid);</code>. The
+  return values just pass on the message or drop the message from the message
+  flow. We want to drop that single message of course, otherways somebody else
+  could steal it.
+  </p>
+
+</section>
+
+<section>
+  <title>Add buttons to control the application</title>
+  <p>So if you just need a webcam viewer you can stop reading now and run to
+  your bus. If you however want to impress your friends, let's just add a
+  button and make your application fully functional</p>
+
+  <code mime="text/x-vala" style="numbered">
+using Gtk;
+using Gst;
+
+public class Webcam : Gtk.Window
+{
+  private Gtk.DrawingArea drawing_area;
+  private X.ID xid;
+  private Gst.Element camerabin;
+  private int counter = 1;
+
+  public Webcam ()
+  {
+    this.set_title ("Press play to start");
+    this.destroy.connect (Gtk.main_quit);
+
+    var vbox = new Gtk.VBox (false, 0);
+    this.drawing_area = new Gtk.DrawingArea ();
+    this.drawing_area.set_size_request (640, 480);
+    this.drawing_area.realize.connect (on_realize);
+    vbox.pack_start (this.drawing_area, true, true, 0);
+
+    var photo_button = new Button.with_label ("Take a picture");
+    photo_button.clicked.connect (on_take_picture);
+
+    vbox.pack_start (photo_button, false, false, 5);
+
+    this.add (vbox);
+
+    this.camerabin = Gst.ElementFactory.make ("camerabin", "camera");
+    var bus = this.camerabin.get_bus ();
+    bus.set_sync_handler (on_bus_callback);
+  }
+
+  private Gst.BusSyncReply on_bus_callback (Gst.Bus bus, Gst.Message message)
+  {
+    if (message.get_structure () != null &amp;&amp; message.get_structure().has_name("prepare-xwindow-id")) {
+      var xoverlay = message.src as Gst.XOverlay;
+      xoverlay.set_xwindow_id (this.xid);
+      return Gst.BusSyncReply.DROP;
+    }
+
+    return Gst.BusSyncReply.PASS;
+  }
+
+  private void on_realize ()
+  {
+    this.xid = Gdk.x11_drawable_get_xid (this.drawing_area.window);
+    this.camerabin.set_state (Gst.State.PLAYING);
+  }
+
+  private void on_take_picture ()
+  {
+    var filename = "photo" + "%d".printf (this.counter) + ".jpg";
+    this.set_title ("%d".printf (this.counter) + " photos taken");
+    this.counter++;
+    this.camerabin.set ("filename", filename);
+    GLib.Signal.emit_by_name (this.camerabin, "capture-start");
+  }
+
+  public static int main (string[] args)
+  {
+    Gst.init (ref args);
+    Gtk.init (ref args);
+
+    var webcam = new Webcam ();
+    webcam.show_all ();
+
+    Gtk.main ();
+
+    return 0;
+  }
+}
+  </code>
+
+  <p>
+  We create the take a photo button using
+  <code>new Button.with_label ("Take a picture");</code>. Then we connect the
+  <code>clicked</code> event with our method <code>on_take_picture</code>. This
+  signal happens when you click on the button and it automatically calls that
+  one method. In there we set the filename we want to use for the photo, update
+  the window title and take a photo. The title we set using
+  <code>this.set_title ("%d".printf (this.counter) + " photos taken");</code>,
+  the filename by setting a property of our GStreamer camerabin element
+  <code>this.camerabin.set ("filename", filename);</code> and finally we take a
+  photo by sending a signal to the camerabin element
+  <code>GLib.Signal.emit_by_name (this.camerabin, "capture-start");</code>
+  </p>
+
+  <p>
+  That's it, you have managed to create a full featured webcam photo
+  application in 15 minutes. Now you can shave your beard off or add some make
+  up to your beautiful face, right before having a beautiful day at your work,
+  where you can impress your friends and colleagues with an awesome application
+  you just make in 15 minutes.
+  </p>
+</section>
+
+</page>
+
+



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