Silence g++/moc warnings
[harmattan/cameraplus] / lib / qtcamdevice.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 "qtcamdevice.h"
22 #include "qtcamviewfinder.h"
23 #include "qtcamconfig.h"
24 #include "qtcamdevice_p.h"
25 #include <QDebug>
26 #include <gst/gst.h>
27 #include "qtcamgstreamermessagelistener.h"
28 #include "qtcammode.h"
29 #include "qtcamimagemode.h"
30 #include "qtcamvideomode.h"
31
32 // TODO: we want the ability to change the image and video gep from the app.
33
34 QtCamDevice::QtCamDevice(QtCamConfig *config, const QString& name,
35                          const QVariant& id, QObject *parent) :
36   QObject(parent), d_ptr(new QtCamDevicePrivate) {
37
38   d_ptr->q_ptr = this;
39   d_ptr->name = name;
40   d_ptr->id = id;
41   d_ptr->conf = config;
42
43   d_ptr->cameraBin = gst_element_factory_make("camerabin2", "QtCameraCameraBin");
44   if (!d_ptr->cameraBin) {
45     qCritical() << "Failed to create camerabin";
46     return;
47   }
48
49   d_ptr->createAndAddElement(d_ptr->conf->audioSource(), "audio-source", "QtCameraAudioSrc");
50   d_ptr->createAndAddVideoSource();
51
52   int flags =
53     0x00000001 /* no-audio-conversion - Do not use audio conversion elements */
54     | 0x00000002 /* no-video-conversion - Do not use video conversion elements */
55     | 0x00000004 /* no-viewfinder-conversion - Do not use viewfinder conversion elements */
56     | 0x00000008; /* no-image-conversion - Do not use image conversion elements */
57
58   g_object_set(d_ptr->cameraBin, "flags", flags, NULL);
59
60   d_ptr->setAudioCaptureCaps();
61
62   // TODO: audio bitrate
63   // TODO: video bitrate
64   // TODO: filters
65   // TODO: capabilities
66   // TODO: custom properties for jifmux, mp4mux, audio encoder, video encoder, sink & video source
67   d_ptr->listener = new QtCamGStreamerMessageListener(gst_element_get_bus(d_ptr->cameraBin),
68                                                       d_ptr, this);
69
70   QObject::connect(d_ptr->listener, SIGNAL(error(const QString&, int, const QString&)),
71                    this, SLOT(_d_error(const QString&, int, const QString&)));
72   QObject::connect(d_ptr->listener, SIGNAL(started()), this, SLOT(_d_started()));
73   QObject::connect(d_ptr->listener, SIGNAL(stopped()), this, SLOT(_d_stopped()));
74   QObject::connect(d_ptr->listener, SIGNAL(stopping()), this, SLOT(_d_stopping()));
75
76   g_signal_connect(d_ptr->cameraBin, "notify::idle",
77                    G_CALLBACK(QtCamDevicePrivate::on_idle_changed), d_ptr);
78
79   g_signal_connect(d_ptr->wrapperVideoSource, "notify::ready-for-capture",
80                    G_CALLBACK(QtCamDevicePrivate::on_ready_for_capture_changed), d_ptr);
81
82   d_ptr->image = new QtCamImageMode(d_ptr, this);
83   d_ptr->video = new QtCamVideoMode(d_ptr, this);
84 }
85
86 QtCamDevice::~QtCamDevice() {
87   stop();
88
89   d_ptr->image->deactivate();
90   d_ptr->video->deactivate();
91
92   delete d_ptr->image; d_ptr->image = 0;
93   delete d_ptr->video; d_ptr->video = 0;
94   delete d_ptr; d_ptr = 0;
95 }
96
97 bool QtCamDevice::setViewfinder(QtCamViewfinder *viewfinder) {
98   if (isRunning()) {
99     qWarning() << "QtCamDevice: pipeline must be stopped before setting a viewfinder";
100     return false;
101   }
102
103   if (d_ptr->viewfinder == viewfinder) {
104     return true;
105   }
106
107   if (!viewfinder) {
108     qWarning() << "QtCamDevice: viewfinder cannot be unset.";
109     return false;
110   }
111
112   if (d_ptr->viewfinder) {
113     qWarning() << "QtCamDevice: viewfinder cannot be replaced.";
114     return false;
115   }
116
117   if (!viewfinder->setDevice(this)) {
118     return false;
119   }
120
121   d_ptr->viewfinder = viewfinder;
122
123   return true;
124 }
125
126 bool QtCamDevice::start() {
127   if (d_ptr->error) {
128     qWarning() << "Pipeline must be stopped first because of an error.";
129     return false;
130   }
131
132   if (!d_ptr->cameraBin) {
133     qWarning() << "Missing camerabin";
134     return false;
135   }
136
137   if (!d_ptr->viewfinder) {
138     qWarning() << "Viewfinder not set";
139     return false;
140   }
141
142   if (isRunning()) {
143     return true;
144   }
145
146   if (!d_ptr->active) {
147     d_ptr->image->activate();
148   }
149   else {
150     d_ptr->active->applySettings();
151   }
152
153   // Set sink.
154   if (!d_ptr->setViewfinderSink()) {
155     return false;
156   }
157
158   GstStateChangeReturn err = gst_element_set_state(d_ptr->cameraBin, GST_STATE_PLAYING);
159   if (err == GST_STATE_CHANGE_FAILURE) {
160     qWarning() << "Failed to start camera pipeline";
161     return false;
162   }
163
164   // We need to wait for startup to complet. There's a race condition somewhere in the pipeline.
165   // If we set the scene mode to night and update the resolution while starting up
166   // then subdevsrc2 barfs:
167   // streaming task paused, reason not-negotiated (-4)
168   GstState state;
169   if (err != GST_STATE_CHANGE_ASYNC) {
170     return true;
171   }
172
173   if (gst_element_get_state(d_ptr->cameraBin, &state, 0, GST_CLOCK_TIME_NONE)
174       != GST_STATE_CHANGE_SUCCESS) {
175     // We are seriously screwed up :(
176     return false;
177   }
178
179   if (state != GST_STATE_PLAYING) {
180     // Huh ? Is this even possible ??
181     return false;
182   }
183
184   return true;
185 }
186
187 bool QtCamDevice::stop() {
188   if (!d_ptr->cameraBin) {
189     return true;
190   }
191
192   if (d_ptr->error) {
193     gst_element_set_state(d_ptr->cameraBin, GST_STATE_NULL);
194     d_ptr->error = false;
195     return true;
196   }
197
198   GstState state;
199   gst_element_get_state(d_ptr->cameraBin, &state, 0, GST_CLOCK_TIME_NONE);
200
201   if (state == GST_STATE_NULL) {
202     // Nothing to do.
203     return true;
204   }
205
206   if (!isIdle()) {
207     return false;
208   }
209
210   d_ptr->viewfinder->stop();
211
212   // First we go to ready:
213   GstStateChangeReturn st = gst_element_set_state(d_ptr->cameraBin, GST_STATE_READY);
214   if (st != GST_STATE_CHANGE_FAILURE) {
215     // Flush the bus:
216     d_ptr->listener->flushMessages();
217   }
218
219   // Now to NULL
220   gst_element_set_state(d_ptr->cameraBin, GST_STATE_NULL);
221
222   return true;
223 }
224
225 bool QtCamDevice::isRunning() {
226   if (!d_ptr->cameraBin) {
227     return false;
228   }
229
230   GstState state;
231   GstStateChangeReturn err = gst_element_get_state(d_ptr->cameraBin,
232                                                    &state, 0, GST_CLOCK_TIME_NONE);
233
234   if (err == GST_STATE_CHANGE_FAILURE || state != GST_STATE_PLAYING) {
235     return false;
236   }
237
238   return true;
239 }
240
241 bool QtCamDevice::isIdle() {
242   if (!d_ptr->cameraBin) {
243     return true;
244   }
245
246   gboolean idle = FALSE;
247   g_object_get(d_ptr->cameraBin, "idle", &idle, NULL);
248
249   return idle == TRUE;
250 }
251
252 QtCamImageMode *QtCamDevice::imageMode() const {
253   return d_ptr->image;
254 }
255
256 QtCamVideoMode *QtCamDevice::videoMode() const {
257   return d_ptr->video;
258 }
259
260 QtCamMode *QtCamDevice::activeMode() const {
261   return d_ptr->active;
262 }
263
264 QString QtCamDevice::name() const {
265   return d_ptr->name;
266 }
267
268 QVariant QtCamDevice::id() const {
269   return d_ptr->id;
270 }
271
272 QtCamConfig *QtCamDevice::config() const {
273   return d_ptr->conf;
274 }
275
276 QtCamGStreamerMessageListener *QtCamDevice::listener() const {
277   return d_ptr->listener;
278 }
279
280 #include "moc_qtcamdevice.cpp"