A camera using GDigicam and Qt

You may (or not 😉 ) know that GDigicam is an open source library used in Maemo 5 as a middleware betweeen the camera application and the GStreamer stuff. The goal of the library is to ease the development of camera style applications by hiding the low level stuff to the UI developers, and it allows different GStreamer pipelines to be used in the lower layers to achieve the camera funcionality. Currently the camerabin plugin is the fully supported one, and it’s also the one being used for the N900 camera.

I had the chance to collaborate in the development of the GDigicam library time ago, and it’s currently maintained by some of my colleagues at Igalia. One of them asked me some days ago about the possibility of using GDigicam together with Qt to develop a camera application. You know how this works… that seed was enough to awake my curiosity, so I started working on it 🙂

Some tests later, I’ve developed an experiment integrating both things. A Qt application that uses GDigicam to display a viewfinder in a Qt window, and to get pictures and show a preview of them. I must confess that I got really surprised because it was a really simple task. You can clone my personal repository (http://git.igalia.com/user/magomez/qtcamera.git) if you want to check the code. These are the steps I followed and the tricky parts of the code 🙂

First, extend the QWidget to create a CamWindow widget. In the CamWindow constructor, create the GDigicamManager, the GStreamer camerabin plugin, the GDigicamDescriptor and fill the bin capabilities (this is done in the setupCamerabin method). Connect the callbacks to the GDigicam desired signals and set the initial configuration. In the example, I used CamWindow’s static methods as callbacks of the GDigicam signals. This is fine as long as you don’t need the CamWindow instance. If you need it, then you’ll have to set it as the callback user_data parameter when connecting the signal (as in the preview signal case).

void CamWindow::setupGDigicam()
{
    GstElement *bin;
    GDigicamDescriptor *descriptor = NULL;

    /* create the GDigicamManager */
    manager = g_digicam_manager_new();
    colorkey = 0;

    /* create the bin */
    bin = g_digicam_camerabin_element_new ("v4l2camsrc",
                                           "dspmp4venc",
                                           "hantromp4mux",
                                           "pulsesrc",
                                           "nokiaaacenc",
                                           "jpegenc",
                                           NULL,
                                           "xvimagesink",
                                           &colorkey);

    /* create and fill the descriptor*/
    descriptor = g_digicam_camerabin_descriptor_new (bin);
    descriptor->max_zoom_macro_enabled = 6;
    descriptor->max_zoom_macro_disabled = 6;
    descriptor->max_digital_zoom = 6;


..... more descriptor capabilities stuff....


    /* set the bin and the descriptor to the manager */
    g_digicam_manager_set_gstreamer_bin (manager,
                                         bin,
                                         descriptor,
                                         NULL);

    /* connect to the manager's signals */
    g_signal_connect (manager, "pict-done",
                     (GCallback) captureDone,
                      NULL);
    g_signal_connect (manager, "capture-start",
                     (GCallback) captureStart,
                      NULL);
    g_signal_connect (manager, "capture-end",
                     (GCallback) captureEnd,
                      NULL);
    g_signal_connect (manager, "image-preview",
                     (GCallback) imagePreview,
                      this);

    /* set initial configuration */
    setOperationMode(G_DIGICAM_MODE_STILL);
    setResolution(G_DIGICAM_RESOLUTION_HIGH,
                  G_DIGICAM_ASPECTRATIO_16X9);
    setFlashMode(G_DIGICAM_FLASHMODE_AUTO);
    enablePreview(true);
}

I’ve created some private members in CamWindow to encapsulate the GDigicam function calls. They are used for initialization and also called through the options in the window menu (change resolution, play/stop bin) and when clicking the capture button. This is the one to set the resolution for example:

void CamWindow::setResolution(GDigicamResolution res,
                              GDigicamAspectratio ar)
{
    GDigicamCamerabinAspectRatioResolutionHelper *helper = NULL;

    helper = g_slice_new (GDigicamCamerabinAspectRatioResolutionHelper);
    helper->resolution = res;
    helper->aspect_ratio = ar;

    g_digicam_manager_set_aspect_ratio_resolution (manager,
                                                   helper->aspect_ratio,
                                                   helper->resolution,
                                                   NULL,
                                                   helper);

    g_slice_free (GDigicamCamerabinAspectRatioResolutionHelper, helper);
}

One of the capabilities of the camerabin is that through the use of a colorkey, it allows blending UI components over the video stream. To make this work, the background of the window where the video is put must be filled wit the colorley color (this color is provided when creating the camerabin element). This is why this is done in the paintEvent method of the window:

void CamWindow::paintEvent (QPaintEvent *)
{
    QPainter painter(this);
    QBrush brush;

    QColor color((colorkey & 0x00ff0000) >> 16,
                 (colorkey & 0x0000ff00) >> 8,
                  colorkey & 0x000000ff);

    painter.save();
    painter.fillRect(0, 0, width(), height(), color);
    painter.restore ();
}

This done, by calling g_digicam_manager_play_bin() and g_digicam_manager_stop_bin(), you can control the viewfinder running on the window. The g_digicam_manager_play_bin() function received the XWindow id of the widget, which is obtained through the winId() member of QWidget.

Finally, when the pipeline is running, by calling g_digicam_camerabin_get_still_picture(), you can capture a picture. When doing so, besides the picture being stored in the provided path, the manager will emit (if preview is active) a signal containing a preview of the captured picture. In order to show this preview, I connected the imagePreview member of CamWindow to the preview signal. Inside this method, the GdkPixbuf received is turned into a QImage and then a QPixmap that is shown in a new window:

void CamWindow::imagePreview(GDigicamManager *manager,
                             GdkPixbuf *preview,
                             gpointer data)
{
    QLabel *label = new QLabel();
    label->setAttribute(Qt::WA_DeleteOnClose);
    label->setWindowFlags(label->windowFlags() | Qt::Window);

    QImage image(gdk_pixbuf_get_pixels(preview),
                 gdk_pixbuf_get_width(preview),
                 gdk_pixbuf_get_height(preview),
                 gdk_pixbuf_get_rowstride(preview),
                 QImage::Format_RGB888);

   QPixmap pixmap(QPixmap::fromImage(image));
                  label->setPixmap(pixmap);
                  label->show();
}

If you get the code and run the example in an N900, you will see a window with a capture button. Go to the menu, select play and the viewfinder will show up (and capture button will be over it!). You can change the resolution of the picture through the menu, and press the capture button to get a picture, and see the preview of the capture in a new window. For the moment, those are the features I’ve implemented in the example.

It’s quite simple, isn’t it? 🙂

2 thoughts on “A camera using GDigicam and Qt”

  1. Quite QT 🙂

    But would it be possible to increase the video recording resolution on the N900 by taking advantage of the DSP?

Comments are closed.