Disable viewfinder in settings pages
[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 #include <QFile>
31
32 class PreviewImageHandler : public QtCamGStreamerMessageHandler {
33 public:
34   PreviewImageHandler(QtCamMode *m, QObject *parent = 0) :
35     QtCamGStreamerMessageHandler("preview-image", parent) {
36     mode = m;
37   }
38
39   virtual void handleMessage(GstMessage *message) {
40     const GstStructure *s = gst_message_get_structure(message);
41     if (!s) {
42       return;
43     }
44
45     const char *file = gst_structure_get_string(s, "location");
46     if (!file) {
47       return;
48     }
49
50     const GValue *val = gst_structure_get_value(s, "buffer");
51     if (!val) {
52       return;
53     }
54
55     GstBuffer *buffer = gst_value_get_buffer(val);
56     if (!buffer) {
57       return;
58     }
59
60     int width, height;
61     GstVideoFormat fmt;
62     if (!gst_video_format_parse_caps(buffer->caps, &fmt, &width, &height)) {
63       return;
64     }
65
66     if (fmt !=  GST_VIDEO_FORMAT_BGRx || width <= 0 || height <= 0) {
67       return;
68     }
69
70     QImage image(buffer->data, width, height, QImage::Format_RGB32);
71
72     // We need to copy because GStreamer will free the buffer after we return
73     // and since QImage doesn't copythe data by default we will end up with garbage.
74     // There is no way to subclass QImage to prevent copying :|
75     QImage cp = image.copy();
76
77     QString fileName = QString::fromUtf8(file);
78
79     QMetaObject::invokeMethod(mode, "previewAvailable",
80                               Q_ARG(QImage, cp), Q_ARG(QString, fileName));
81   }
82
83   QtCamMode *mode;
84 };
85
86 class DoneHandler : public QtCamGStreamerMessageHandler {
87 public:
88   DoneHandler(QtCamModePrivate *m, const char *done, QObject *parent = 0) :
89     QtCamGStreamerMessageHandler(done, parent) {
90     mode = m;
91   }
92
93   virtual void handleMessage(GstMessage *message) {
94     // If we have a temp file then we rename it:
95     if (!mode->tempFileName.isEmpty() && !mode->fileName.isEmpty()) {
96       if (!QFile::rename(mode->tempFileName, mode->fileName)) {
97         qCritical() << "Failed to rename" << mode->tempFileName << "to" << mode->fileName;
98       }
99     }
100
101     QString fileName;
102     const GstStructure *s = gst_message_get_structure(message);
103     if (gst_structure_has_field(s, "filename")) {
104       const char *str = gst_structure_get_string(s, "filename");
105       if (str) {
106         fileName = QString::fromUtf8(str);
107       }
108     }
109
110     if (fileName.isEmpty()) {
111       fileName = mode->fileName;
112     }
113
114     QMetaObject::invokeMethod(mode->q_ptr, "saved", Q_ARG(QString, fileName));
115   }
116
117   QtCamModePrivate *mode;
118 };
119
120 QtCamMode::QtCamMode(QtCamModePrivate *d, const char *mode, const char *done, QObject *parent) :
121   QObject(parent), d_ptr(d) {
122
123   d_ptr->q_ptr = this;
124   d_ptr->id = d_ptr->modeId(mode);
125   d_ptr->previewImageHandler = new PreviewImageHandler(this, this);
126   d_ptr->doneHandler = new DoneHandler(d_ptr, done, this);
127 }
128
129 QtCamMode::~QtCamMode() {
130   delete d_ptr; d_ptr = 0;
131 }
132
133 void QtCamMode::activate() {
134   if (!d_ptr->dev->cameraBin) {
135     return;
136   }
137
138   if (d_ptr->dev->active == this) {
139     return;
140   }
141
142   if (d_ptr->dev->active) {
143     d_ptr->dev->active->deactivate();
144   }
145
146   d_ptr->dev->active = this;
147
148   // TODO: check that we can actually do it. Perhaps the pipeline is busy.
149   g_object_set(d_ptr->dev->cameraBin, "mode", d_ptr->id, NULL);
150
151   d_ptr->dev->listener->addHandler(d_ptr->previewImageHandler);
152   d_ptr->dev->listener->addHandler(d_ptr->doneHandler);
153
154   start();
155
156   applySettings();
157
158   QMetaObject::invokeMethod(d_ptr->dev->q_ptr, "modeChanged");
159
160   emit activeChanged();
161 }
162
163 void QtCamMode::deactivate() {
164   if (d_ptr->dev->active != this) {
165     return;
166   }
167
168   d_ptr->dev->listener->removeHandler(d_ptr->previewImageHandler);
169   d_ptr->dev->listener->removeHandler(d_ptr->doneHandler);
170
171   d_ptr->previewImageHandler->setParent(this);
172   d_ptr->doneHandler->setParent(this);
173
174   stop();
175
176   d_ptr->dev->active = 0;
177
178   QMetaObject::invokeMethod(d_ptr->dev->q_ptr, "modeChanged");
179
180   emit activeChanged();
181 }
182
183 bool QtCamMode::canCapture() {
184   return d_ptr->dev->cameraBin && isActive() && d_ptr->dev->q_ptr->isRunning() &&
185     !d_ptr->dev->error;
186 }
187
188 bool QtCamMode::isActive() {
189   return d_ptr->dev->active == this;
190 }
191
192 QtCamDevice *QtCamMode::device() const {
193   return d_ptr->dev->q_ptr;
194 }