9c8d40aa05eb2a62ee15395a875281dc72c992ce
[harmattan/cameraplus] / lib / qtcamviewfinderrenderergeneric.cpp
1 /*!
2  * This file is part of CameraPlus.
3  *
4  * Copyright (C) 2012-2013 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 "qtcamviewfinderrenderergeneric.h"
22 #include <QDebug>
23 #include <gst/video/video.h>
24 #include <QPainter>
25 #include "qtcamconfig.h"
26
27 QT_CAM_VIEWFINDER_RENDERER(RENDERER_TYPE_GENERIC, QtCamViewfinderRendererGeneric);
28
29 #define CAPS "video/x-raw-rgb, bpp = (int) 32, depth = (int) 24, red_mask = (int) 65280, green_mask = (int) 16711680, blue_mask = (int) -16777216"
30
31 // TODO: this needs to be debugged or rewritten. There are race conditions.
32 QtCamViewfinderRendererGeneric::QtCamViewfinderRendererGeneric(QtCamConfig *config,
33                                                                QObject *parent) :
34   QtCamViewfinderRenderer(config, parent), m_elem(0), m_sink(0), m_id(0) {
35
36 }
37
38 QtCamViewfinderRendererGeneric::~QtCamViewfinderRendererGeneric() {
39   m_mutex.lock();
40
41   if (m_elem) {
42     g_object_remove_toggle_ref(G_OBJECT(m_elem), (GToggleNotify)sink_notify, this);
43     m_elem = 0;
44
45     g_signal_handler_disconnect(m_sink, m_id);
46   }
47
48   m_mutex.unlock();
49 }
50
51 void QtCamViewfinderRendererGeneric::paint(QPainter *painter) {
52   // TODO: scale and keep aspect ratio.
53   m_mutex.lock();
54
55   if (!m_image.isNull()) {
56     painter->drawImage(QRectF(QPointF(0, 0), m_size), m_image);
57   }
58
59   m_mutex.unlock();
60 }
61
62 void QtCamViewfinderRendererGeneric::resize(const QSizeF& size) {
63   m_size = size;
64 }
65
66 void QtCamViewfinderRendererGeneric::reset() {
67   m_image = QImage();
68 }
69
70 GstElement *QtCamViewfinderRendererGeneric::sinkElement() {
71   if (!m_elem) {
72     m_elem = gst_bin_new("QtCamViewfinderRendererGenericBin");
73     if (!m_elem) {
74       qCritical() << "Failed to create sink bin";
75       return 0;
76     }
77
78     GstElement *sink = gst_element_factory_make("fakesink", "QtCamViewfinderRendererGenericSink");
79     if (!sink) {
80       qCritical() << "Failed to create fakesink";
81       gst_object_unref(m_elem);
82       m_elem = 0;
83       return 0;
84     }
85
86     g_object_set(G_OBJECT(sink), "signal-handoffs", TRUE, "sync", TRUE, NULL);
87     m_id = g_signal_connect(sink, "handoff", G_CALLBACK(on_gst_buffer), this);
88
89     GstElement *csp = gst_element_factory_make("ffmpegcolorspace",
90                                                "QtCamViewfinderRendererGenericCsp");
91     if (!csp) {
92       qCritical() << "Failed to create ffmpegcolorspace";
93       gst_object_unref(sink);
94       gst_object_unref(m_elem);
95       m_elem = 0;
96       return 0;
97     }
98
99     GstElement *filter = gst_element_factory_make("capsfilter",
100                                                   "QtCamViewfinderRendererGenericCapsFilter");
101     if (!filter) {
102       qCritical() << "Failed to create capsfilter";
103       gst_object_unref(sink);
104       gst_object_unref(csp);
105       gst_object_unref(m_elem);
106       m_elem = 0;
107       return 0;
108     }
109
110     GstCaps *caps = gst_caps_from_string(CAPS);
111     g_object_set(filter, "caps", caps, NULL);
112     gst_caps_unref(caps);
113
114     gst_bin_add_many(GST_BIN(m_elem), csp, filter, sink, NULL);
115     gst_element_link_many(csp, filter, sink, NULL);
116
117     GstPad *pad = gst_element_get_static_pad(csp, "sink");
118     gst_element_add_pad(m_elem, gst_ghost_pad_new("sink", pad));
119     gst_object_unref(pad);
120
121     g_object_add_toggle_ref(G_OBJECT(m_elem), (GToggleNotify)sink_notify, this);
122
123     m_sink = sink;
124   }
125
126   return m_elem;
127 }
128
129 QRectF QtCamViewfinderRendererGeneric::renderArea() {
130   // TODO: calculate this and emit renderAreaChanged() signal when needed
131   return QRectF();
132 }
133
134 QSizeF QtCamViewfinderRendererGeneric::videoResolution() {
135   // TODO:
136
137   return QSizeF();
138 }
139
140 void QtCamViewfinderRendererGeneric::on_gst_buffer(GstElement *element,
141                                                    GstBuffer *buf, GstPad *pad,
142                                                    QtCamViewfinderRendererGeneric *q) {
143
144   Q_UNUSED(element);
145
146   q->m_mutex.lock();
147
148   if (!q->m_elem) {
149     q->m_mutex.unlock();
150     return;
151   }
152
153   int width, height;
154
155   if (!gst_video_get_size(pad, &width, &height)) {
156     return;
157   }
158
159   QImage image(buf->data, width, height, QImage::Format_RGB32);
160
161   q->m_image = image.copy();
162
163   QMetaObject::invokeMethod(q, "updateRequested", Qt::QueuedConnection);
164
165   q->m_mutex.unlock();
166 }
167
168 void QtCamViewfinderRendererGeneric::sink_notify(QtCamViewfinderRendererGeneric *q,
169                                                  GObject *object,
170                                                  gboolean is_last_ref) {
171
172   Q_UNUSED(object);
173
174   if (is_last_ref) {
175     g_object_remove_toggle_ref(G_OBJECT(q->m_elem), (GToggleNotify)sink_notify, q);
176     q->m_elem = 0;
177     q->m_sink = 0;
178   }
179 }