Added a signal idleStateChanged() to QtCamDevice
[harmattan/cameraplus] / lib / qtcamdevice.cpp
1 #include "qtcamdevice.h"
2 #include "qtcamviewfinder.h"
3 #include "qtcamconfig.h"
4 #include "qtcamdevice_p.h"
5 #include <QDebug>
6 #include <gst/gst.h>
7 #include "qtcamgstreamermessagelistener.h"
8 #include "qtcammode.h"
9 #include "qtcamimagemode.h"
10 #include "qtcamvideomode.h"
11
12 QtCamDevice::QtCamDevice(QtCamConfig *config, const QString& name,
13                          const QVariant& id, QObject *parent) :
14   QObject(parent), d_ptr(new QtCamDevicePrivate) {
15
16   d_ptr->q_ptr = this;
17   d_ptr->name = name;
18   d_ptr->id = id;
19   d_ptr->conf = config;
20
21   d_ptr->cameraBin = gst_element_factory_make("camerabin2", "QtCameraCameraBin");
22   if (!d_ptr->cameraBin) {
23     qCritical() << "Failed to create camerabin";
24     return;
25   }
26
27   d_ptr->createAndAddElement(d_ptr->conf->audioSource(), "audio-source", "QtCameraAudioSrc");
28   d_ptr->createAndAddVideoSource();
29
30   int flags =
31     0x00000001 /* no-audio-conversion - Do not use audio conversion elements */
32     | 0x00000002 /* no-video-conversion - Do not use video conversion elements */
33     | 0x00000004 /* no-viewfinder-conversion - Do not use viewfinder conversion elements */
34     | 0x00000008; /* no-image-conversion - Do not use image conversion elements */
35
36   g_object_set(d_ptr->cameraBin, "flags", flags, NULL);
37
38   d_ptr->setAudioCaptureCaps();
39
40   // TODO: audio bitrate
41   // TODO: video bitrate
42   // TODO: filters
43   // TODO: capabilities
44   // TODO: custom properties for jifmux, mp4mux, audio encoder, video encoder, sink & video source
45   // color tune, scene modes
46   d_ptr->listener = new QtCamGStreamerMessageListener(gst_element_get_bus(d_ptr->cameraBin),
47                                                       d_ptr, this);
48
49   QObject::connect(d_ptr->listener, SIGNAL(error(const QString&, int, const QString&)),
50                    this, SLOT(_d_error(const QString&, int, const QString&)));
51   QObject::connect(d_ptr->listener, SIGNAL(started()), this, SIGNAL(started()));
52   QObject::connect(d_ptr->listener, SIGNAL(stopped()), this, SIGNAL(stopped()));
53
54   g_signal_connect(d_ptr->cameraBin, "notify::idle",
55                    G_CALLBACK(QtCamDevicePrivate::on_idle_changed), d_ptr);
56
57   d_ptr->image = new QtCamImageMode(d_ptr, this);
58   d_ptr->video = new QtCamVideoMode(d_ptr, this);
59 }
60
61 QtCamDevice::~QtCamDevice() {
62   stop();
63
64   d_ptr->image->deactivate();
65   d_ptr->video->deactivate();
66
67   delete d_ptr->image; d_ptr->image = 0;
68   delete d_ptr->video; d_ptr->video = 0;
69   delete d_ptr; d_ptr = 0;
70 }
71
72 bool QtCamDevice::setViewfinder(QtCamViewfinder *viewfinder) {
73   if (isRunning()) {
74     qWarning() << "QtCamDevice: pipeline must be stopped before setting a viewfinder";
75     return false;
76   }
77
78   if (d_ptr->viewfinder == viewfinder) {
79     return true;
80   }
81
82   if (!viewfinder) {
83     qWarning() << "QtCamDevice: viewfinder cannot be unset.";
84     return false;
85   }
86
87   if (d_ptr->viewfinder) {
88     qWarning() << "QtCamDevice: viewfinder cannot be replaced.";
89     return false;
90   }
91
92   if (!viewfinder->setDevice(this)) {
93     return false;
94   }
95
96   d_ptr->viewfinder = viewfinder;
97
98   return true;
99 }
100
101 bool QtCamDevice::start() {
102   if (d_ptr->error) {
103     qWarning() << "Pipeline must be stopped first because of an error.";
104     return false;
105   }
106
107   if (!d_ptr->cameraBin) {
108     qWarning() << "Missing camerabin";
109     return false;
110   }
111
112   if (!d_ptr->viewfinder) {
113     qWarning() << "Viewfinder not set";
114     return false;
115   }
116
117   if (isRunning()) {
118     return true;
119   }
120
121   if (!d_ptr->active) {
122     d_ptr->image->activate();
123   }
124   else {
125     d_ptr->active->applySettings();
126   }
127
128   // Set sink.
129   if (!d_ptr->setViewfinderSink()) {
130     return false;
131   }
132
133   GstStateChangeReturn err = gst_element_set_state(d_ptr->cameraBin, GST_STATE_PLAYING);
134   if (err == GST_STATE_CHANGE_FAILURE) {
135     qWarning() << "Failed to start camera pipeline";
136     return false;
137   }
138
139   return true;
140 }
141
142 bool QtCamDevice::stop() {
143   if (!d_ptr->cameraBin) {
144     return true;
145   }
146
147   if (d_ptr->error) {
148     gst_element_set_state(d_ptr->cameraBin, GST_STATE_NULL);
149     d_ptr->error = false;
150     return true;
151   }
152
153   GstState state;
154   gst_element_get_state(d_ptr->cameraBin, &state, 0, GST_CLOCK_TIME_NONE);
155
156   if (state == GST_STATE_NULL) {
157     // Nothing to do.
158     return true;
159   }
160
161   if (!isIdle()) {
162     return false;
163   }
164
165   // First we go to ready:
166   GstStateChangeReturn st = gst_element_set_state(d_ptr->cameraBin, GST_STATE_READY);
167   if (st != GST_STATE_CHANGE_FAILURE) {
168     // Flush the bus:
169     d_ptr->listener->flushMessages();
170   }
171
172   // Now to NULL
173   gst_element_set_state(d_ptr->cameraBin, GST_STATE_NULL);
174
175   return true;
176 }
177
178 bool QtCamDevice::isRunning() {
179   if (!d_ptr->cameraBin) {
180     return false;
181   }
182
183   GstState state;
184   GstStateChangeReturn err = gst_element_get_state(d_ptr->cameraBin,
185                                                    &state, 0, GST_CLOCK_TIME_NONE);
186
187   if (err == GST_STATE_CHANGE_FAILURE || state != GST_STATE_PLAYING) {
188     return false;
189   }
190
191   return true;
192 }
193
194 bool QtCamDevice::isIdle() {
195   if (!d_ptr->cameraBin) {
196     return true;
197   }
198
199   gboolean idle = FALSE;
200   g_object_get(d_ptr->cameraBin, "idle", &idle, NULL);
201
202   return idle == TRUE;
203 }
204
205 QtCamImageMode *QtCamDevice::imageMode() const {
206   return d_ptr->image;
207 }
208
209 QtCamVideoMode *QtCamDevice::videoMode() const {
210   return d_ptr->video;
211 }
212
213 QtCamMode *QtCamDevice::activeMode() const {
214   return d_ptr->active;
215 }
216
217 QString QtCamDevice::name() const {
218   return d_ptr->name;
219 }
220
221 QVariant QtCamDevice::id() const {
222   return d_ptr->id;
223 }
224
225 QtCamConfig *QtCamDevice::config() const {
226   return d_ptr->conf;
227 }
228
229 QtCamGStreamerMessageListener *QtCamDevice::listener() const {
230   return d_ptr->listener;
231 }
232
233 #include "moc_qtcamdevice.cpp"