Code cleanup
[harmattan/cameraplus] / lib / qtcammode.cpp
1 /*!
2  * This file is part of CameraPlus.
3  *
4  * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "qtcammode.h"
22 #include "qtcammode_p.h"
23 #include "qtcamdevice_p.h"
24 #include "qtcamdevice.h"
25 #include <QDebug>
26 #include "qtcamgstreamermessagehandler.h"
27 #include "qtcamgstreamermessagelistener.h"
28 #include <gst/video/video.h>
29 #include <QImage>
30
31 class PreviewImageHandler : public QtCamGStreamerMessageHandler {
32 public:
33   PreviewImageHandler(QtCamMode *m, QObject *parent = 0) :
34     QtCamGStreamerMessageHandler("preview-image", parent) {
35     mode = m;
36   }
37
38   virtual void handleMessage(GstMessage *message) {
39     const GstStructure *s = gst_message_get_structure(message);
40     if (!s) {
41       return;
42     }
43
44     const char *file = gst_structure_get_string(s, "location");
45     if (!file) {
46       return;
47     }
48
49     const GValue *val = gst_structure_get_value(s, "buffer");
50     if (!val) {
51       return;
52     }
53
54     GstBuffer *buffer = gst_value_get_buffer(val);
55     if (!buffer) {
56       return;
57     }
58
59     int width, height;
60     GstVideoFormat fmt;
61     if (!gst_video_format_parse_caps(buffer->caps, &fmt, &width, &height)) {
62       return;
63     }
64
65     if (fmt !=  GST_VIDEO_FORMAT_BGRx || width <= 0 || height <= 0) {
66       return;
67     }
68
69     QImage image(buffer->data, width, height, QImage::Format_RGB32);
70
71     // We need to copy because GStreamer will free the buffer after we return
72     // and since QImage doesn't copythe data by default we will end up with garbage.
73     // There is no way to subclass QImage to prevent copying :|
74     QImage cp = image.copy();
75
76     QString fileName = QString::fromUtf8(file);
77
78     QMetaObject::invokeMethod(mode, "previewAvailable",
79                               Q_ARG(QImage, cp), Q_ARG(QString, fileName));
80   }
81
82   QtCamMode *mode;
83 };
84
85 class DoneHandler : public QtCamGStreamerMessageHandler {
86 public:
87   DoneHandler(QtCamModePrivate *m, const char *done, QObject *parent = 0) :
88     QtCamGStreamerMessageHandler(done, parent) {
89     mode = m;
90   }
91
92   virtual void handleMessage(GstMessage *message) {
93     const GstStructure *s = gst_message_get_structure(message);
94     if (gst_structure_has_field(s, "filename")) {
95       const char *str = gst_structure_get_string(s, "filename");
96       if (str) {
97         mode->fileName = QString::fromUtf8(str);
98       }
99     }
100
101     QMetaObject::invokeMethod(mode->q_ptr, "saved", Q_ARG(QString, mode->fileName));
102   }
103
104   QtCamModePrivate *mode;
105 };
106
107 QtCamMode::QtCamMode(QtCamModePrivate *d, const char *mode, const char *done, QObject *parent) :
108   QObject(parent), d_ptr(d) {
109
110   d_ptr->q_ptr = this;
111   d_ptr->id = d_ptr->modeId(mode);
112   d_ptr->previewImageHandler = new PreviewImageHandler(this, this);
113   d_ptr->doneHandler = new DoneHandler(d_ptr, done, this);
114 }
115
116 QtCamMode::~QtCamMode() {
117   delete d_ptr; d_ptr = 0;
118 }
119
120 void QtCamMode::activate() {
121   if (!d_ptr->dev->cameraBin) {
122     return;
123   }
124
125   if (d_ptr->dev->active == this) {
126     return;
127   }
128
129   if (d_ptr->dev->active) {
130     d_ptr->dev->active->deactivate();
131   }
132
133   d_ptr->dev->active = this;
134
135   // TODO: check that we can actually do it. Perhaps the pipeline is busy.
136   g_object_set(d_ptr->dev->cameraBin, "mode", d_ptr->id, NULL);
137
138   d_ptr->dev->listener->addHandler(d_ptr->previewImageHandler);
139   d_ptr->dev->listener->addHandler(d_ptr->doneHandler);
140
141   start();
142
143   applySettings();
144
145   QMetaObject::invokeMethod(d_ptr->dev->q_ptr, "modeChanged");
146
147   emit activeChanged();
148 }
149
150 void QtCamMode::deactivate() {
151   if (d_ptr->dev->active != this) {
152     return;
153   }
154
155   d_ptr->dev->listener->removeHandler(d_ptr->previewImageHandler);
156   d_ptr->dev->listener->removeHandler(d_ptr->doneHandler);
157
158   d_ptr->previewImageHandler->setParent(this);
159   d_ptr->doneHandler->setParent(this);
160
161   stop();
162
163   d_ptr->dev->active = 0;
164
165   QMetaObject::invokeMethod(d_ptr->dev->q_ptr, "modeChanged");
166
167   emit activeChanged();
168 }
169
170 bool QtCamMode::canCapture() {
171   return d_ptr->dev->cameraBin && isActive() && d_ptr->dev->q_ptr->isRunning() &&
172     !d_ptr->dev->error;
173 }
174
175 bool QtCamMode::isActive() {
176   return d_ptr->dev->active == this;
177 }
178
179 QtCamDevice *QtCamMode::device() const {
180   return d_ptr->dev->q_ptr;
181 }