Added a new property (nightMode) to QtCamMode to use the night framerate
[harmattan/cameraplus] / lib / qtcammode.cpp
1 #include "qtcammode.h"
2 #include "qtcammode_p.h"
3 #include "qtcamdevice_p.h"
4 #include "qtcamdevice.h"
5 #include <QDebug>
6 #include "qtcamgstreamermessagehandler.h"
7 #include "qtcamgstreamermessagelistener.h"
8 #include <gst/video/video.h>
9 #include <QImage>
10
11 #define PREVIEW_CAPS "video/x-raw-rgb, width = (int) %1, height = (int) %2, bpp = (int) 32, depth = (int) 24, red_mask = (int) 65280, green_mask = (int) 16711680, blue_mask = (int) -16777216"
12
13 class PreviewImageHandler : public QtCamGStreamerMessageHandler {
14 public:
15   PreviewImageHandler(QtCamMode *m, QObject *parent = 0) :
16     QtCamGStreamerMessageHandler("preview-image", parent) {
17     mode = m;
18   }
19
20   virtual void handleMessage(GstMessage *message) {
21     const GstStructure *s = gst_message_get_structure(message);
22     if (!s) {
23       return;
24     }
25
26     const char *file = gst_structure_get_string(s, "location");
27     if (!file) {
28       return;
29     }
30
31     const GValue *val = gst_structure_get_value(s, "buffer");
32     if (!val) {
33       return;
34     }
35
36     GstBuffer *buffer = gst_value_get_buffer(val);
37     if (!buffer) {
38       return;
39     }
40
41     int width, height;
42     GstVideoFormat fmt;
43     if (!gst_video_format_parse_caps(buffer->caps, &fmt, &width, &height)) {
44       return;
45     }
46
47     if (fmt !=  GST_VIDEO_FORMAT_BGRx || width <= 0 || height <= 0) {
48       return;
49     }
50
51     QImage image(buffer->data, width, height, QImage::Format_RGB32);
52
53     // We need to copy because GStreamer will free the buffer after we return
54     // and since QImage doesn't copythe data by default we will end up with garbage.
55     // TODO: consider a QImage subclass that takes a GstBuffer reference
56     QImage cp = image.copy();
57
58     QString fileName = QString::fromUtf8(file);
59
60     QMetaObject::invokeMethod(mode, "previewAvailable",
61                               Q_ARG(QImage, cp), Q_ARG(QString, fileName));
62   }
63
64   QtCamMode *mode;
65 };
66
67 class DoneHandler : public QtCamGStreamerMessageHandler {
68 public:
69   DoneHandler(QtCamMode *m, const char *done, QObject *parent = 0) :
70     QtCamGStreamerMessageHandler(done, parent) {
71     mode = m;
72   }
73
74   virtual void handleMessage(GstMessage *message) {
75     const GstStructure *s = gst_message_get_structure(message);
76     if (gst_structure_has_field(s, "filename")) {
77       const char *str = gst_structure_get_string(s, "filename");
78       if (str) {
79         fileName = QString::fromUtf8(str);
80       }
81     }
82
83     QMetaObject::invokeMethod(mode, "saved", Q_ARG(QString, fileName));
84   }
85
86   QString fileName;
87   QtCamMode *mode;
88 };
89
90 QtCamMode::QtCamMode(QtCamModePrivate *d, const char *mode, const char *done, QObject *parent) :
91   QObject(parent), d_ptr(d) {
92
93   d_ptr->id = d_ptr->modeId(mode);
94   d_ptr->previewImageHandler = new PreviewImageHandler(this, this);
95   d_ptr->doneHandler = new DoneHandler(this, done, this);
96 }
97
98 QtCamMode::~QtCamMode() {
99   delete d_ptr; d_ptr = 0;
100 }
101
102 void QtCamMode::activate() {
103   if (!d_ptr->dev->cameraBin) {
104     return;
105   }
106
107   if (d_ptr->dev->active == this) {
108     return;
109   }
110
111   if (d_ptr->dev->active) {
112     d_ptr->dev->active->deactivate();
113   }
114
115   d_ptr->dev->active = this;
116
117   // TODO: check that we can actually do it. Perhaps the pipeline is busy.
118   g_object_set(d_ptr->dev->cameraBin, "mode", d_ptr->id, NULL);
119
120   d_ptr->dev->resetCapabilities();
121
122   d_ptr->dev->listener->addHandler(d_ptr->previewImageHandler);
123   d_ptr->dev->listener->addHandler(d_ptr->doneHandler);
124
125   start();
126
127   applySettings();
128
129   QMetaObject::invokeMethod(d_ptr->dev->q_ptr, "modeChanged");
130
131   emit activeChanged();
132 }
133
134 void QtCamMode::deactivate() {
135   if (d_ptr->dev->active != this) {
136     return;
137   }
138
139   d_ptr->dev->listener->removeHandler(d_ptr->previewImageHandler);
140   d_ptr->dev->listener->removeHandler(d_ptr->doneHandler);
141
142   d_ptr->previewImageHandler->setParent(this);
143   d_ptr->doneHandler->setParent(this);
144
145   stop();
146
147   d_ptr->dev->active = 0;
148
149   QMetaObject::invokeMethod(d_ptr->dev->q_ptr, "modeChanged");
150
151   emit activeChanged();
152 }
153
154 bool QtCamMode::canCapture() {
155   return d_ptr->dev->cameraBin && isActive() && d_ptr->dev->q_ptr->isRunning();
156 }
157
158 bool QtCamMode::isActive() {
159   return d_ptr->dev->active == this;
160 }
161
162 void QtCamMode::setPreviewSize(const QSize& size) {
163   if (!d_ptr->dev->cameraBin) {
164     return;
165   }
166
167   if (size.width() <= 0 && size.height() <= 0) {
168     g_object_set(d_ptr->dev->cameraBin, "preview-caps", NULL, "post-previews", FALSE, NULL);
169   }
170   else {
171     QString preview = QString(PREVIEW_CAPS).arg(size.width()).arg(size.height());
172
173     GstCaps *caps = gst_caps_from_string(preview.toAscii());
174
175     g_object_set(d_ptr->dev->cameraBin, "preview-caps", caps, "post-previews", TRUE, NULL);
176
177     gst_caps_unref(caps);
178   }
179 }
180
181 void QtCamMode::setFileName(const QString& fileName) {
182   d_ptr->doneHandler->fileName = fileName;
183 }
184
185 void QtCamMode::setNightMode(bool night) {
186   if (d_ptr->night != night) {
187     d_ptr->night = night;
188     applySettings();
189
190     emit nightModeChanged();
191   }
192 }
193
194 bool QtCamMode::inNightMode() const {
195   return d_ptr->night;
196 }