2 * This file is part of CameraPlus.
4 * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
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.
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.
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
21 #include "qtcamdevice.h"
22 #include "qtcamviewfinder.h"
23 #include "qtcamconfig.h"
24 #include "qtcamdevice_p.h"
27 #include "qtcamgstreamermessagelistener.h"
28 #include "qtcammode.h"
29 #include "qtcamimagemode.h"
30 #include "qtcamvideomode.h"
31 #include "qtcamnotifications.h"
32 #include "gst/gstcopy.h"
33 #include "qtcampropertysetter.h"
34 #include "qtcamanalysisbin.h"
36 QtCamDevice::QtCamDevice(QtCamConfig *config, const QString& name,
37 const QVariant& id, QObject *parent) :
38 QObject(parent), d_ptr(new QtCamDevicePrivate) {
40 static gboolean register_copy = TRUE;
42 qt_cam_copy_register();
43 register_copy = FALSE;
51 d_ptr->cameraBin = gst_element_factory_make("camerabin2", "QtCameraCameraBin");
52 if (!d_ptr->cameraBin) {
53 qCritical() << "Failed to create camerabin";
57 d_ptr->propertySetter = new QtCamPropertySetter(d_ptr);
59 d_ptr->createAndAddElement(d_ptr->conf->audioSource(), "audio-source", "QtCameraAudioSrc");
60 if (!d_ptr->conf->wrapperVideoSource().isEmpty() &&
61 !d_ptr->conf->wrapperVideoSourceProperty().isEmpty()) {
62 d_ptr->createAndAddVideoSourceAndWrapper();
65 d_ptr->createAndAddVideoSource();
68 d_ptr->setDevicePoperty();
71 0x00000001 /* no-audio-conversion - Do not use audio conversion elements */
72 | 0x00000002 /* no-video-conversion - Do not use video conversion elements */
73 | 0x00000004 /* no-viewfinder-conversion - Do not use viewfinder conversion elements */
74 | 0x00000008; /* no-image-conversion - Do not use image conversion elements */
76 g_object_set(d_ptr->cameraBin, "flags", flags, NULL);
78 d_ptr->setAudioCaptureCaps();
80 QStringList viewfinderFilters = d_ptr->conf->viewfinderFilters();
81 if (!viewfinderFilters.isEmpty()) {
82 d_ptr->viewfinderFilters =
83 QtCamAnalysisBin::create(viewfinderFilters, "QtCamViewfinderFilters");
85 if (!d_ptr->viewfinderFilters) {
86 qWarning() << "Failed to create viewfinder filters";
89 g_object_set(d_ptr->cameraBin, "viewfinder-filter", d_ptr->viewfinderFilters->bin(), NULL);
93 d_ptr->listener = new QtCamGStreamerMessageListener(gst_element_get_bus(d_ptr->cameraBin),
96 QObject::connect(d_ptr->listener, SIGNAL(error(const QString&, int, const QString&)),
97 this, SLOT(_d_error(const QString&, int, const QString&)));
98 QObject::connect(d_ptr->listener, SIGNAL(started()), this, SLOT(_d_started()));
99 QObject::connect(d_ptr->listener, SIGNAL(stopped()), this, SLOT(_d_stopped()));
100 QObject::connect(d_ptr->listener, SIGNAL(stopping()), this, SLOT(_d_stopping()));
102 g_signal_connect(d_ptr->cameraBin, "notify::idle",
103 G_CALLBACK(QtCamDevicePrivate::on_idle_changed), d_ptr);
105 if (d_ptr->wrapperVideoSource) {
106 g_signal_connect(d_ptr->wrapperVideoSource, "notify::ready-for-capture",
107 G_CALLBACK(QtCamDevicePrivate::on_ready_for_capture_changed), d_ptr);
110 g_signal_connect(d_ptr->videoSource, "notify::ready-for-capture",
111 G_CALLBACK(QtCamDevicePrivate::on_ready_for_capture_changed), d_ptr);
114 d_ptr->image = new QtCamImageMode(d_ptr, this);
115 d_ptr->video = new QtCamVideoMode(d_ptr, this);
117 d_ptr->notifications = new QtCamNotifications(this, this);
120 QtCamDevice::~QtCamDevice() {
123 d_ptr->image->deactivate();
124 d_ptr->video->deactivate();
126 delete d_ptr->image; d_ptr->image = 0;
127 delete d_ptr->video; d_ptr->video = 0;
129 delete d_ptr->propertySetter;
131 delete d_ptr->viewfinderFilters;
133 if (d_ptr->cameraBin) {
134 gst_object_unref(d_ptr->cameraBin);
137 delete d_ptr; d_ptr = 0;
140 bool QtCamDevice::setViewfinder(QtCamViewfinder *viewfinder) {
142 qWarning() << "QtCamDevice: pipeline must be stopped before setting a viewfinder";
146 if (d_ptr->viewfinder == viewfinder) {
151 qWarning() << "QtCamDevice: viewfinder cannot be unset.";
155 if (d_ptr->viewfinder) {
156 qWarning() << "QtCamDevice: viewfinder cannot be replaced.";
160 if (!viewfinder->setDevice(this)) {
164 d_ptr->viewfinder = viewfinder;
169 QtCamViewfinder *QtCamDevice::viewfinder() const {
170 return d_ptr->viewfinder;
173 bool QtCamDevice::start() {
175 qWarning() << "Pipeline must be stopped first because of an error.";
179 if (!d_ptr->cameraBin) {
180 qWarning() << "Missing camerabin";
184 if (!d_ptr->viewfinder) {
185 qWarning() << "Viewfinder not set";
193 if (!d_ptr->active) {
194 d_ptr->image->activate();
197 d_ptr->active->applySettings();
201 if (!d_ptr->setViewfinderSink()) {
205 GstStateChangeReturn err = gst_element_set_state(d_ptr->cameraBin, GST_STATE_PLAYING);
206 if (err == GST_STATE_CHANGE_FAILURE) {
207 qWarning() << "Failed to start camera pipeline";
211 // We need to wait for startup to complet. There's a race condition somewhere in the pipeline.
212 // If we set the scene mode to night and update the resolution while starting up
213 // then subdevsrc2 barfs:
214 // streaming task paused, reason not-negotiated (-4)
216 if (err != GST_STATE_CHANGE_ASYNC) {
220 if (gst_element_get_state(d_ptr->cameraBin, &state, 0, GST_CLOCK_TIME_NONE)
221 != GST_STATE_CHANGE_SUCCESS) {
222 // We are seriously screwed up :(
226 if (state != GST_STATE_PLAYING) {
227 // Huh ? Is this even possible ??
234 bool QtCamDevice::stop(bool force) {
235 if (!d_ptr->cameraBin) {
240 gst_element_set_state(d_ptr->cameraBin, GST_STATE_NULL);
241 d_ptr->error = false;
243 d_ptr->viewfinder->stop();
249 gst_element_get_state(d_ptr->cameraBin, &state, 0, GST_CLOCK_TIME_NONE);
251 if (state == GST_STATE_NULL) {
262 // First we go to ready:
263 GstStateChangeReturn st = gst_element_set_state(d_ptr->cameraBin, GST_STATE_READY);
264 if (st != GST_STATE_CHANGE_FAILURE) {
266 d_ptr->listener->flushMessages();
270 gst_element_set_state(d_ptr->cameraBin, GST_STATE_NULL);
272 d_ptr->viewfinder->stop();
277 bool QtCamDevice::isRunning() {
278 if (!d_ptr->cameraBin) {
283 GstStateChangeReturn err = gst_element_get_state(d_ptr->cameraBin,
284 &state, 0, GST_CLOCK_TIME_NONE);
286 if (err == GST_STATE_CHANGE_FAILURE || state != GST_STATE_PLAYING) {
293 bool QtCamDevice::isIdle() {
294 if (!d_ptr->cameraBin) {
298 gboolean idle = FALSE;
299 g_object_get(d_ptr->cameraBin, "idle", &idle, NULL);
304 QtCamImageMode *QtCamDevice::imageMode() const {
308 QtCamVideoMode *QtCamDevice::videoMode() const {
312 QtCamMode *QtCamDevice::activeMode() const {
313 return d_ptr->active;
316 QString QtCamDevice::name() const {
320 QVariant QtCamDevice::id() const {
324 QtCamConfig *QtCamDevice::config() const {
328 QtCamGStreamerMessageListener *QtCamDevice::listener() const {
329 return d_ptr->listener;
332 QtCamNotifications *QtCamDevice::notifications() const {
333 return d_ptr->notifications;
336 #include "moc_qtcamdevice.cpp"