Convert TextSwitch to a platform specific component and rename it to CameraTextSwitch
[harmattan/cameraplus] / lib / qtcammode.cpp
1 /*!
2  * This file is part of CameraPlus.
3  *
4  * Copyright (C) 2012-2013 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 "qtcamgstreamermessagelistener.h"
27 #include <gst/video/video.h>
28 #include <QImage>
29 #include <QFile>
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 QtCamMode::QtCamMode(QtCamModePrivate *d, const char *mode, QObject *parent) :
86   QObject(parent), d_ptr(d) {
87
88   d_ptr->q_ptr = this;
89   d_ptr->id = d_ptr->modeId(mode);
90   d_ptr->previewImageHandler = new PreviewImageHandler(this, this);
91   d_ptr->doneHandler = 0;
92 }
93
94 QtCamMode::~QtCamMode() {
95   delete d_ptr; d_ptr = 0;
96 }
97
98 void QtCamMode::activate() {
99   if (!d_ptr->dev->cameraBin) {
100     return;
101   }
102
103   if (d_ptr->dev->active == this) {
104     return;
105   }
106
107   if (d_ptr->dev->active) {
108     d_ptr->dev->active->deactivate();
109   }
110
111   d_ptr->dev->active = this;
112
113   g_object_set(d_ptr->dev->cameraBin, "mode", d_ptr->id, NULL);
114
115   d_ptr->dev->listener->addHandler(d_ptr->previewImageHandler);
116
117   // This has to be sync. VideoDoneHandler will lock a mutex that is already
118   // locked from the main thread.
119   d_ptr->dev->listener->addSyncHandler(d_ptr->doneHandler);
120
121   start();
122
123   applySettings();
124
125   QMetaObject::invokeMethod(d_ptr->dev->q_ptr, "modeChanged");
126
127   emit activeChanged();
128 }
129
130 void QtCamMode::deactivate() {
131   if (d_ptr->dev->active != this) {
132     return;
133   }
134
135   d_ptr->dev->listener->removeHandler(d_ptr->previewImageHandler);
136   d_ptr->dev->listener->removeSyncHandler(d_ptr->doneHandler);
137
138   d_ptr->previewImageHandler->setParent(this);
139   d_ptr->doneHandler->setParent(this);
140
141   stop();
142
143   d_ptr->dev->active = 0;
144
145   QMetaObject::invokeMethod(d_ptr->dev->q_ptr, "modeChanged");
146
147   emit activeChanged();
148 }
149
150 bool QtCamMode::canCapture() {
151   return d_ptr->dev->cameraBin && isActive() && d_ptr->dev->q_ptr->isRunning() &&
152     !d_ptr->dev->error;
153 }
154
155 bool QtCamMode::isActive() {
156   return d_ptr->dev->active == this;
157 }
158
159 QtCamDevice *QtCamMode::device() const {
160   return d_ptr->dev->q_ptr;
161 }