Added stopping() signal and emit stopping(), stopped() and started()
[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, SLOT(_d_started()));
52   QObject::connect(d_ptr->listener, SIGNAL(stopped()), this, SLOT(_d_stopped()));
53   QObject::connect(d_ptr->listener, SIGNAL(stopping()), this, SLOT(_d_stopping()));
54
55   g_signal_connect(d_ptr->cameraBin, "notify::idle",
56                    G_CALLBACK(QtCamDevicePrivate::on_idle_changed), d_ptr);
57
58   d_ptr->image = new QtCamImageMode(d_ptr, this);
59   d_ptr->video = new QtCamVideoMode(d_ptr, this);
60 }
61
62 QtCamDevice::~QtCamDevice() {
63   stop();
64
65   d_ptr->image->deactivate();
66   d_ptr->video->deactivate();
67
68   delete d_ptr->image; d_ptr->image = 0;
69   delete d_ptr->video; d_ptr->video = 0;
70   delete d_ptr; d_ptr = 0;
71 }
72
73 bool QtCamDevice::setViewfinder(QtCamViewfinder *viewfinder) {
74   if (isRunning()) {
75     qWarning() << "QtCamDevice: pipeline must be stopped before setting a viewfinder";
76     return false;
77   }
78
79   if (d_ptr->viewfinder == viewfinder) {
80     return true;
81   }
82
83   if (!viewfinder) {
84     qWarning() << "QtCamDevice: viewfinder cannot be unset.";
85     return false;
86   }
87
88   if (d_ptr->viewfinder) {
89     qWarning() << "QtCamDevice: viewfinder cannot be replaced.";
90     return false;
91   }
92
93   if (!viewfinder->setDevice(this)) {
94     return false;
95   }
96
97   d_ptr->viewfinder = viewfinder;
98
99   return true;
100 }
101
102 bool QtCamDevice::start() {
103   if (d_ptr->error) {
104     qWarning() << "Pipeline must be stopped first because of an error.";
105     return false;
106   }
107
108   if (!d_ptr->cameraBin) {
109     qWarning() << "Missing camerabin";
110     return false;
111   }
112
113   if (!d_ptr->viewfinder) {
114     qWarning() << "Viewfinder not set";
115     return false;
116   }
117
118   if (isRunning()) {
119     return true;
120   }
121
122   if (!d_ptr->active) {
123     d_ptr->image->activate();
124   }
125   else {
126     d_ptr->active->applySettings();
127   }
128
129   // Set sink.
130   if (!d_ptr->setViewfinderSink()) {
131     return false;
132   }
133
134   GstStateChangeReturn err = gst_element_set_state(d_ptr->cameraBin, GST_STATE_PLAYING);
135   if (err == GST_STATE_CHANGE_FAILURE) {
136     qWarning() << "Failed to start camera pipeline";
137     return false;
138   }
139
140   return true;
141 }
142
143 bool QtCamDevice::stop() {
144   if (!d_ptr->cameraBin) {
145     return true;
146   }
147
148   if (d_ptr->error) {
149     gst_element_set_state(d_ptr->cameraBin, GST_STATE_NULL);
150     d_ptr->error = false;
151     return true;
152   }
153
154   GstState state;
155   gst_element_get_state(d_ptr->cameraBin, &state, 0, GST_CLOCK_TIME_NONE);
156
157   if (state == GST_STATE_NULL) {
158     // Nothing to do.
159     return true;
160   }
161
162   if (!isIdle()) {
163     return false;
164   }
165
166   // First we go to ready:
167   GstStateChangeReturn st = gst_element_set_state(d_ptr->cameraBin, GST_STATE_READY);
168   if (st != GST_STATE_CHANGE_FAILURE) {
169     // Flush the bus:
170     d_ptr->listener->flushMessages();
171   }
172
173   // Now to NULL
174   gst_element_set_state(d_ptr->cameraBin, GST_STATE_NULL);
175
176   return true;
177 }
178
179 bool QtCamDevice::isRunning() {
180   if (!d_ptr->cameraBin) {
181     return false;
182   }
183
184   GstState state;
185   GstStateChangeReturn err = gst_element_get_state(d_ptr->cameraBin,
186                                                    &state, 0, GST_CLOCK_TIME_NONE);
187
188   if (err == GST_STATE_CHANGE_FAILURE || state != GST_STATE_PLAYING) {
189     return false;
190   }
191
192   return true;
193 }
194
195 bool QtCamDevice::isIdle() {
196   if (!d_ptr->cameraBin) {
197     return true;
198   }
199
200   gboolean idle = FALSE;
201   g_object_get(d_ptr->cameraBin, "idle", &idle, NULL);
202
203   return idle == TRUE;
204 }
205
206 QtCamImageMode *QtCamDevice::imageMode() const {
207   return d_ptr->image;
208 }
209
210 QtCamVideoMode *QtCamDevice::videoMode() const {
211   return d_ptr->video;
212 }
213
214 QtCamMode *QtCamDevice::activeMode() const {
215   return d_ptr->active;
216 }
217
218 QString QtCamDevice::name() const {
219   return d_ptr->name;
220 }
221
222 QVariant QtCamDevice::id() const {
223   return d_ptr->id;
224 }
225
226 QtCamConfig *QtCamDevice::config() const {
227   return d_ptr->conf;
228 }
229
230 QtCamGStreamerMessageListener *QtCamDevice::listener() const {
231   return d_ptr->listener;
232 }
233
234 #include "moc_qtcamdevice.cpp"