]> git.sesse.net Git - kdenlive/blob - src/v4l/v4lcapture.cpp
76d9a4a68d66d1638774cfdd215c847fbde89102
[kdenlive] / src / v4l / v4lcapture.cpp
1 /***************************************************************************
2  *   Copyright (C) 2010 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
18  ***************************************************************************/
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <pthread.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26
27 #include <QDebug>
28 #include <QImage>
29 #include <QTimer>
30 #include <QPainter>
31
32 #include <KDebug>
33 #include <KLocale>
34
35 #include "v4lcapture.h"
36 #include "kdenlivesettings.h"
37 #include "dec.h"
38
39 static src_t v4lsrc;
40
41 QImage add_image_png(src_t *src)
42 {
43     QImage im;
44     im.loadFromData((uchar *)src->img, src->length, "PNG");
45     return im;
46 }
47
48 QImage add_image_jpeg(src_t *src)
49 {
50     uint32_t hlength;
51     uint8_t *himg = NULL;
52     QImage im;
53
54     /* MJPEG data may lack the DHT segment required for decoding... */
55     verify_jpeg_dht((uint8_t *) src->img, src->length, &himg, &hlength);
56
57     im.loadFromData(himg, hlength, "JPG");
58     free(himg);
59     return im;
60 }
61
62 class MyDisplay : public QLabel
63 {
64 public:
65     MyDisplay(QWidget *parent = 0);
66     void setImage(QImage img);
67     virtual void paintEvent(QPaintEvent *);
68     virtual void resizeEvent(QResizeEvent *);
69
70 private:
71     QImage m_img;
72     bool m_clear;
73 };
74
75 MyDisplay::MyDisplay(QWidget *parent):
76     QLabel(parent)
77     , m_clear(false)
78 {
79     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
80     setAttribute(Qt::WA_PaintOnScreen);
81     setAttribute(Qt::WA_OpaquePaintEvent);
82 }
83
84 void MyDisplay::resizeEvent(QResizeEvent *)
85 {
86     m_clear = true;
87 }
88
89 void MyDisplay::paintEvent(QPaintEvent *)
90 {
91     QPainter p(this);
92     if (m_clear) {
93         // widget resized, cleanup
94         p.fillRect(0, 0, width(), height(), palette().background());
95         m_clear = false;
96     }
97     if (m_img.isNull()) return;
98     QImage img = m_img.scaled(width(), height(), Qt::KeepAspectRatio);
99     p.drawImage((width() - img.width()) / 2, (height() - img.height()) / 2, img);
100     p.end();
101 }
102
103 void MyDisplay::setImage(QImage img)
104 {
105     m_img = img;
106     update();
107 }
108
109
110
111 V4lCaptureHandler::V4lCaptureHandler(QVBoxLayout *lay, QWidget *parent):
112     CaptureHandler(lay, parent)
113     , m_update(false)
114     , m_device(KdenliveSettings::video4vdevice())
115     , m_width(-1)
116     , m_height(-1)
117 {
118     if (lay == NULL) return;
119     m_display = new MyDisplay;
120     lay->addWidget(m_display);
121 }
122
123 QStringList V4lCaptureHandler::getDeviceName(QString input)
124 {
125     fswebcam_config_t *config;
126     /* Prepare the configuration structure. */
127     config = (fswebcam_config_t *) calloc(sizeof(fswebcam_config_t), 1);
128     if (!config) {
129         /*WARN("Out of memory.");*/
130         fprintf(stderr, "Out of MEM....");
131         return QStringList() << input;
132     }
133
134     /* Set the defaults. */
135     config->loop = 0;
136     config->offset = 0;
137     config->background = 0;
138     config->pidfile = NULL;
139     config->logfile = NULL;
140     config->gmt = 0;
141     config->start = 0;
142     config->device = strdup(input.toUtf8().constData());
143     config->input = NULL;
144     config->tuner = 0;
145     config->frequency = 0;
146     config->delay = 0;
147     config->use_read = 0;
148     config->list = 0;
149     if (m_width > 0) config->width = m_width;
150     else config->width = 384;
151     if (m_height > 0) config->height = m_height;
152     else config->height = 288;
153     config->fps = 0;
154     config->frames = 1;
155     config->skipframes = 0;
156     config->palette = SRC_PAL_ANY;
157     config->option = NULL;
158     config->dumpframe = NULL;
159     config->jobs = 0;
160     config->job = NULL;
161
162     /* Set defaults and parse the command line. */
163     /*if(fswc_getopts(config, argc, argv)) return(-1);*/
164
165
166     /* Record the start time. */
167     config->start = time(NULL);
168     /* Set source options... */
169     memset(&v4lsrc, 0, sizeof(v4lsrc));
170     v4lsrc.input      = config->input;
171     v4lsrc.tuner      = config->tuner;
172     v4lsrc.frequency  = config->frequency;
173     v4lsrc.delay      = config->delay;
174     v4lsrc.timeout    = 10; /* seconds */
175     v4lsrc.use_read   = config->use_read;
176     v4lsrc.list       = config->list;
177     v4lsrc.palette    = config->palette;
178     v4lsrc.width      = config->width;
179     v4lsrc.height     = config->height;
180     v4lsrc.fps        = config->fps;
181     v4lsrc.option     = config->option;
182     char *source = config->device;
183     uint width = 0;
184     uint height = 0;
185     char *pixelformatdescription;
186     QString deviceName(src_query(&v4lsrc, source, &width, &height, &pixelformatdescription));
187     free(config);
188     QStringList result;
189     result << (deviceName.isEmpty() ? input : deviceName) << (width == 0 ? QString() : QString("%1x%2").arg(width).arg(height)) << QString(pixelformatdescription);
190     return result;
191 }
192
193 void V4lCaptureHandler::setDevice(const QString input, QString size)
194 {
195     m_device = input;
196     if (!size.isEmpty()) {
197         m_width = size.section('x', 0, 0).toInt();
198         m_height = size.section('x', -1).toInt();
199
200     }
201 }
202
203 void V4lCaptureHandler::startPreview(int /*deviceId*/, int /*captureMode*/, bool)
204 {
205     m_display->setHidden(false);
206     fswebcam_config_t *config;
207     /* Prepare the configuration structure. */
208     config = (fswebcam_config_t *) calloc(sizeof(fswebcam_config_t), 1);
209     if (!config) {
210         /*WARN("Out of memory.");*/
211         fprintf(stderr, "Out of MEM....");
212         return;
213     }
214
215     /* Set the defaults. */
216     config->loop = 0;
217     config->offset = 0;
218     config->background = 0;
219     config->pidfile = NULL;
220     config->logfile = NULL;
221     config->gmt = 0;
222     config->start = 0;
223     config->device = strdup(m_device.toUtf8().constData());
224     config->input = NULL;
225     config->tuner = 0;
226     config->frequency = 0;
227     config->delay = 0;
228     config->use_read = 0;
229     config->list = 0;
230     if (m_width > 0) config->width = m_width;
231     else config->width = KdenliveSettings::video4size().section("x", 0, 0).toInt();/*384;*/
232     if (m_height > 0) config->height = m_height;
233     else config->height = KdenliveSettings::video4size().section("x", -1).toInt();/*288;*/
234     config->fps = 0;
235     config->frames = 1;
236     config->skipframes = 0;
237     config->palette = SRC_PAL_ANY;
238     config->option = NULL;
239     config->dumpframe = NULL;
240     config->jobs = 0;
241     config->job = NULL;
242
243     /* Set defaults and parse the command line. */
244     /*if(fswc_getopts(config, argc, argv)) return(-1);*/
245
246
247     /* Record the start time. */
248     config->start = time(NULL);
249     /* Set source options... */
250     memset(&v4lsrc, 0, sizeof(v4lsrc));
251     v4lsrc.input      = config->input;
252     v4lsrc.tuner      = config->tuner;
253     v4lsrc.frequency  = config->frequency;
254     v4lsrc.delay      = config->delay;
255     v4lsrc.timeout    = 10; /* seconds */
256     v4lsrc.use_read   = config->use_read;
257     v4lsrc.list       = config->list;
258     v4lsrc.palette    = config->palette;
259     v4lsrc.width      = config->width;
260     v4lsrc.height     = config->height;
261     v4lsrc.fps        = config->fps;
262     v4lsrc.option     = config->option;
263     char *source = config->device;
264
265     if (src_open(&v4lsrc, source) != 0) return;
266     m_update = true;
267     free(config);
268     QTimer::singleShot(200, this, SLOT(slotUpdate()));
269 }
270
271 V4lCaptureHandler::~V4lCaptureHandler()
272 {
273     stopCapture();
274 }
275
276 void V4lCaptureHandler::slotUpdate()
277 {
278     if (!m_update) return;
279     src_grab(&v4lsrc);
280     QImage qimg(v4lsrc.width, v4lsrc.height, QImage::Format_RGB888);
281     switch (v4lsrc.palette) {
282     case SRC_PAL_PNG:
283         qimg = add_image_png(&v4lsrc);
284         break;
285     case SRC_PAL_JPEG:
286     case SRC_PAL_MJPEG:
287         qimg = add_image_jpeg(&v4lsrc);
288         break;
289     case SRC_PAL_S561:
290         fswc_add_image_s561(qimg.bits(), (uchar *)v4lsrc.img, v4lsrc.length, v4lsrc.width, v4lsrc.height, v4lsrc.palette);
291         break;
292     case SRC_PAL_RGB32:
293         fswc_add_image_rgb32(&v4lsrc, qimg.bits());
294         break;
295     case SRC_PAL_BGR32:
296         fswc_add_image_bgr32(&v4lsrc, qimg.bits());
297         break;
298     case SRC_PAL_RGB24:
299         fswc_add_image_rgb24(&v4lsrc, qimg.bits());
300         break;
301     case SRC_PAL_BGR24:
302         fswc_add_image_bgr24(&v4lsrc, qimg.bits());
303         break;
304     case SRC_PAL_BAYER:
305     case SRC_PAL_SGBRG8:
306     case SRC_PAL_SGRBG8:
307         fswc_add_image_bayer(qimg.bits(), (uchar *)v4lsrc.img, v4lsrc.length, v4lsrc.width, v4lsrc.height, v4lsrc.palette);
308         break;
309     case SRC_PAL_YUYV:
310     case SRC_PAL_UYVY:
311         fswc_add_image_yuyv(&v4lsrc, (avgbmp_t *)qimg.bits());
312         break;
313     case SRC_PAL_YUV420P:
314         fswc_add_image_yuv420p(&v4lsrc, qimg.bits());
315         break;
316     case SRC_PAL_NV12MB:
317         fswc_add_image_nv12mb(&v4lsrc, qimg.bits());
318         break;
319     case SRC_PAL_RGB565:
320         fswc_add_image_rgb565(&v4lsrc, qimg.bits());
321         break;
322     case SRC_PAL_RGB555:
323         fswc_add_image_rgb555(&v4lsrc, qimg.bits());
324         break;
325     case SRC_PAL_Y16:
326         fswc_add_image_y16(&v4lsrc, qimg.bits());
327         break;
328     case SRC_PAL_GREY:
329         fswc_add_image_grey(&v4lsrc, qimg.bits());
330         break;
331     }
332     if (m_analyseFrame) {
333         emit gotFrame(qimg);
334     }
335     if (!m_captureFramePath.isEmpty()) {
336         qimg.save(m_captureFramePath);
337         emit frameSaved(m_captureFramePath);
338         m_captureFramePath.clear();
339     }
340     if (!m_overlayImage.isNull()) {
341         // overlay image
342         QPainter p(&qimg);
343         p.setOpacity(0.5);
344         p.drawImage(0, 0, m_overlayImage);
345         p.end();
346     }
347     m_display->setImage(qimg);
348     if (m_update) QTimer::singleShot(50, this, SLOT(slotUpdate()));
349 }
350
351 void V4lCaptureHandler::startCapture(const QString &/*path*/)
352 {
353 }
354
355 void V4lCaptureHandler::stopCapture()
356 {
357 }
358
359 void V4lCaptureHandler::captureFrame(const QString &fname)
360 {
361     m_captureFramePath = fname;
362 }
363
364 void V4lCaptureHandler::showOverlay(QImage img, bool /*transparent*/)
365 {
366     m_overlayImage = img;
367 }
368
369 void V4lCaptureHandler::hideOverlay()
370 {
371     m_overlayImage = QImage();
372 }
373
374 void V4lCaptureHandler::hidePreview(bool hide)
375 {
376     m_display->setHidden(hide);
377 }
378
379 void V4lCaptureHandler::stopPreview()
380 {
381     m_display->setHidden(true);
382     if (!m_update) return;
383     m_update = false;
384     src_close(&v4lsrc);
385 }
386
387