[gnome-devel-docs] webcam demo: add tutorial
- From: Daniel G. Siegel <dgsiegel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-devel-docs] webcam demo: add tutorial
- Date: Fri, 3 Dec 2010 22:57:36 +0000 (UTC)
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 && 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 && 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]