~ubuntu-branches/ubuntu/feisty/kdetv/feisty

« back to all changes in this revision

Viewing changes to kdetv/plugins/video/v4l2/kdetv_v4l2.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2005-09-17 23:25:16 UTC
  • Revision ID: james.westby@ubuntu.com-20050917232516-9wdsn3ckagbqieh8
Tags: upstream-0.8.8
ImportĀ upstreamĀ versionĀ 0.8.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                           kdetv_v4l2.cpp
 
3
                           --------------
 
4
    begin                : Thu Oct 27 2004
 
5
    copyright            : (C) 2004 by Dirk Ziegelmeier
 
6
    email                : dziegel@gmx.de
 
7
***************************************************************************/
 
8
 
 
9
/*
 
10
 * This library is free software; you can redistribute it and/or
 
11
 * modify it under the terms of the GNU Library General Public
 
12
 * License as published by the Free Software Foundation; either
 
13
 * version 2 of the License, or (at your option) any later version.
 
14
 *
 
15
 * This library is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
18
 * Library General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU Library General Public License
 
21
 * along with this library; see the file COPYING.LIB.  If not, write to
 
22
 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 
23
 * Boston, MA 02110-1301, USA.
 
24
 */
 
25
 
 
26
#ifdef HAVE_CONFIG_H
 
27
#include <config.h>
 
28
#endif
 
29
 
 
30
#include <qwidget.h>
 
31
#include <qradiobutton.h>
 
32
#include <qcheckbox.h>
 
33
#include <qevent.h>
 
34
#include <qdir.h>
 
35
#include <qsize.h>
 
36
#include <qcolor.h>
 
37
#include <qimage.h>
 
38
 
 
39
#include <klocale.h>
 
40
#include <kdebug.h>
 
41
#include <assert.h>
 
42
#include <kconfig.h>
 
43
 
 
44
#include <sys/types.h>
 
45
#include <sys/time.h>
 
46
#include <sys/stat.h>
 
47
#include <unistd.h>
 
48
#include <stdlib.h>
 
49
 
 
50
#include "kdetv_v4l2.h"
 
51
#include "kdetv_grabber.h"
 
52
#include "v4l2dev.h"
 
53
#include "qvideostream.h"
 
54
 
 
55
#include "kdetv.h"
 
56
#include "channel.h"
 
57
#include "v4l2configwidget.h"
 
58
#include "kdetvvideo/kdetvimagefilter.h"
 
59
#include "kdetvvideo/kdetvformatconversionfilter.h"
 
60
#include "filtermanager.h"
 
61
 
 
62
#include "kdetv_v4l2.moc"
 
63
 
 
64
static KdetvImage::ImageFormat qvideoformat2kdetvimageformat(QVideo::ImageFormat fmt);
 
65
static QVideo::ImageFormat kdetvimageformat2qvideoformat(KdetvImage::ImageFormat fmt);
 
66
 
 
67
KdetvV4L2::KdetvV4L2(Kdetv *ktv, QWidget *parent, const char *name)
 
68
    : KdetvSourcePlugin(ktv, "v4l2", parent, name),
 
69
      _w(parent),
 
70
      _dev(0),
 
71
      _probed(false),
 
72
      _qvsFormat(QVideo::FORMAT_YUYV),
 
73
      _capturing(false),
 
74
      _g(0),
 
75
      _fieldTime(20000),
 
76
      _mostRecentField(KdetvImage::TYPE_INTERLACED_ODD)
 
77
{
 
78
    _vs = new QVideoStream(_w);
 
79
    _formatConversionFilter = new KdetvFormatConversionFilter();
 
80
 
 
81
    // figure out best method available
 
82
    QVideo::VideoMethod bestAvailable = QVideo::METHOD_XVSHM;
 
83
    if (!_vs->haveMethod(bestAvailable)) {
 
84
        bestAvailable = QVideo::METHOD_XV;
 
85
    }
 
86
 
 
87
    _cfg->setGroup("V4L2 Plugin");
 
88
    _autoConfig = _cfg->readBoolEntry("Autoconfigure", true);
 
89
 
 
90
    if (_autoConfig) {
 
91
        _qvsMethod     = bestAvailable;
 
92
        _fullFrameRate = false;
 
93
    } else {
 
94
        _qvsMethod = (QVideo::VideoMethod)_cfg->readNumEntry("GD Method", bestAvailable);
 
95
 
 
96
        // saved config may be invalid due to graphics card change
 
97
        if (!_vs->haveMethod(_qvsMethod)) {
 
98
            _qvsMethod = bestAvailable;
 
99
        }
 
100
        _fullFrameRate = _cfg->readBoolEntry("Full Frame Rate", false);
 
101
    }
 
102
 
 
103
    /*
 
104
     * The signal to stop capture must be delivered while qApp is in its event loop
 
105
     * because the shutdown relies on a working Qt Library Mutex handshake.
 
106
     * When qApp is destroyed (at the end of main()), it destroys all QObjects,
 
107
     * but without locking the mutex.
 
108
     * This makes the thread shutdown crash because the _stop flag is set during object deletion,
 
109
     * so the thread can paint to a widget that is being deleted using a buffer that is being
 
110
     * deleted (deletion of tv screen and V4L2Grabber).
 
111
     */
 
112
    connect(qApp, SIGNAL( aboutToQuit() ),
 
113
            this, SLOT( stopVideo() ) );
 
114
 
 
115
    connect( parent, SIGNAL( resized(int, int) ),
 
116
             this, SLOT( viewResized() ) );
 
117
 
 
118
    kdDebug() << "Kdetv V4L2 plugin loaded successfully." << endl;
 
119
}
 
120
 
 
121
 
 
122
KdetvV4L2::~KdetvV4L2()
 
123
{
 
124
    stopVideo();
 
125
    delete _dev;
 
126
    _dev = 0;
 
127
    delete _vs;
 
128
    _vs = 0;
 
129
}
 
130
 
 
131
// ---------------------------------------------------- Tuner
 
132
 
 
133
int KdetvV4L2::setChannelProperties(const Channel::PropertyList& properties)
 
134
{
 
135
    // This is an optimization to enable faster channel switching
 
136
    if((properties["source"].toString() == source())     &&
 
137
       (properties["encoding"].toString() == encoding())    ) {
 
138
        setFrequency(properties["frequency"].toULongLong());
 
139
    } else {
 
140
        bool wasCapturing = _capturing;
 
141
        stopVideo();
 
142
        
 
143
        setSource(properties["source"].toString());
 
144
        setEncoding(properties["encoding"].toString());
 
145
        setFrequency(properties["frequency"].toULongLong());
 
146
        
 
147
        if(wasCapturing) {
 
148
            startVideo();
 
149
        }
 
150
    }
 
151
    return 0;
 
152
}
 
153
 
 
154
bool KdetvV4L2::isTuner()
 
155
{
 
156
    return _dev ? _dev->isTuner() : false;
 
157
}
 
158
 
 
159
int KdetvV4L2::signal()
 
160
{
 
161
    return _dev ? _dev->signal() : -1;
 
162
}
 
163
 
 
164
int KdetvV4L2::frequency()
 
165
{
 
166
    if ( !_dev || !_dev->isTuner() ) {
 
167
        return -1;
 
168
    }
 
169
 
 
170
    return (int)(_dev->frequency() / 1000);
 
171
}
 
172
 
 
173
void KdetvV4L2::setFrequency( int freq )
 
174
{
 
175
    if ( !_dev || !_dev->isTuner() ) {
 
176
        return;
 
177
    }
 
178
    _dev->setFrequency((double)freq * 1000);
 
179
}
 
180
 
 
181
int KdetvV4L2::setSource( const QString &src )
 
182
{
 
183
    if ( !_dev )
 
184
        return -1;
 
185
 
 
186
    bool wasCapturing = _capturing;
 
187
 
 
188
    stopVideo();
 
189
    bool rc = _dev->setSource(src);
 
190
    _source = _dev->source();
 
191
    if(wasCapturing) {
 
192
        startVideo();
 
193
    }
 
194
 
 
195
    return rc? 0 : -1;
 
196
}
 
197
 
 
198
int KdetvV4L2::setEncoding( const QString &encoding )
 
199
{
 
200
    if ( !_dev )
 
201
        return -1;
 
202
 
 
203
    bool wasCapturing = _capturing;
 
204
 
 
205
    stopVideo();
 
206
    bool rc = _dev->setEncoding( encoding );
 
207
    _encoding = _dev->encoding();
 
208
 
 
209
    if(_encoding == "ntsc"     ||
 
210
       _encoding == "ntsc-jp"  ||
 
211
       _encoding == "pal-m"    ) {
 
212
        _fieldTime = 16683;
 
213
        // NTSC and PAL-M transmit ODD fields first
 
214
        _mostRecentField = KdetvImage::TYPE_INTERLACED_EVEN;
 
215
    } else {
 
216
        _fieldTime = 20000;
 
217
        // all others EVEN fields first
 
218
        _mostRecentField = KdetvImage::TYPE_INTERLACED_ODD;
 
219
    }
 
220
    if(_g) {
 
221
        _g->_fieldTime       = _fieldTime;
 
222
        _g->_mostRecentField = _mostRecentField;
 
223
    }
 
224
 
 
225
    if(wasCapturing) {
 
226
        startVideo();
 
227
    }
 
228
 
 
229
    return rc? 0 : -1;
 
230
}
 
231
 
 
232
// ---------------------------------------------------- Audio
 
233
 
 
234
bool KdetvV4L2::muted()
 
235
{
 
236
    return _dev->control("Mute").toBool();
 
237
}
 
238
 
 
239
void KdetvV4L2::setMuted( bool muted )
 
240
{
 
241
    _dev->setControl("Mute", QVariant(muted, 0));
 
242
}
 
243
 
 
244
bool KdetvV4L2::setVolume( int left, int right )
 
245
{
 
246
    if(!_dev->hasControl("Volume")) {
 
247
        return false;
 
248
    }
 
249
 
 
250
    // Scale kdetv's internal 0 - 65535 to control range
 
251
    int min = _dev->controlMinimum("Volume");
 
252
    int max = _dev->controlMaximum("Volume");
 
253
    int val = (int)(min + (max-min) * (((double)(left+right)/2) / 65535));
 
254
 
 
255
    return _dev->setControl("Volume", val);
 
256
}
 
257
 
 
258
const QStringList& KdetvV4L2::broadcastedAudioModes()
 
259
{
 
260
    static QStringList empty;
 
261
 
 
262
    if ( !_dev )
 
263
        return empty;
 
264
 
 
265
    return _dev->broadcastedAudioModes();
 
266
}
 
267
 
 
268
const QString& KdetvV4L2::defaultAudioMode()
 
269
{
 
270
    const QStringList& modes = broadcastedAudioModes();
 
271
 
 
272
    // FIXME: a more intelligent and general algorithm would not hurt...
 
273
    if (modes.contains(i18n("Stereo"))) {
 
274
        return modes[modes.findIndex(i18n("Stereo"))];
 
275
    }
 
276
 
 
277
    if (modes.contains(i18n("Language 1"))) {
 
278
        return modes[modes.findIndex(i18n("Language 1"))];
 
279
    }
 
280
 
 
281
    return broadcastedAudioModes().first();
 
282
}
 
283
 
 
284
int KdetvV4L2::setAudioMode( const QString& audioMode )
 
285
{
 
286
    if ( !_dev )
 
287
        return -1;
 
288
 
 
289
    return _dev->setAudioMode(audioMode);
 
290
}
 
291
 
 
292
// ---------------------------------------------------- Device, Controls
 
293
 
 
294
QColor KdetvV4L2::colourKey()
 
295
{
 
296
    return QColor();
 
297
}
 
298
 
 
299
Control::ControlList& KdetvV4L2::controls()
 
300
{
 
301
    return _controls;
 
302
}
 
303
 
 
304
class KdetvV4L2IntegerControl : public IntegerControl
 
305
{
 
306
public:
 
307
    KdetvV4L2IntegerControl(const QString& uiname, const QString& internalName, V4L2Dev* dev)
 
308
        : IntegerControl(uiname, internalName),
 
309
          _dev(dev)
 
310
    {
 
311
        advanced     = _dev->controlAdvanced(internalName);
 
312
        minimumValue = _dev->controlMinimum(internalName);
 
313
        maximumValue = _dev->controlMaximum(internalName);
 
314
        defaultValue = _dev->controlDefault(internalName);
 
315
        step         = _dev->controlStep(internalName);
 
316
    }
 
317
 
 
318
    virtual ~KdetvV4L2IntegerControl()
 
319
    {
 
320
    }
 
321
 
 
322
    virtual bool doSetValue(int value)
 
323
    {
 
324
        return _dev->setControl(internalName, value);
 
325
    }
 
326
 
 
327
    virtual int value() const
 
328
    {
 
329
        return _dev->control(internalName).toInt();
 
330
    }
 
331
 
 
332
 
 
333
private:
 
334
    V4L2Dev* _dev;
 
335
};
 
336
 
 
337
class KdetvV4L2BooleanControl : public BooleanControl
 
338
{
 
339
public:
 
340
    KdetvV4L2BooleanControl(const QString& uiname, const QString& internalName, V4L2Dev* dev)
 
341
        : BooleanControl(uiname, internalName),
 
342
          _dev(dev)
 
343
    {
 
344
        advanced     = _dev->controlAdvanced(internalName);
 
345
        defaultValue = _dev->controlDefault(internalName);
 
346
    }
 
347
 
 
348
    virtual ~KdetvV4L2BooleanControl()
 
349
    {
 
350
    }
 
351
 
 
352
    virtual bool doSetValue(bool value)
 
353
    {
 
354
        return _dev->setControl(internalName, QVariant(value, 0));
 
355
    }
 
356
 
 
357
    virtual bool value() const
 
358
    {
 
359
        return _dev->control(internalName).toInt();
 
360
    }
 
361
 
 
362
 
 
363
private:
 
364
    V4L2Dev* _dev;
 
365
};
 
366
 
 
367
class KdetvV4L2MenuControl : public MenuControl
 
368
{
 
369
public:
 
370
    KdetvV4L2MenuControl(const QString& uiname, const QString& internalName, V4L2Dev* dev)
 
371
        : MenuControl(uiname, internalName),
 
372
          _dev(dev)
 
373
    {
 
374
        advanced     = _dev->controlAdvanced(internalName);
 
375
        defaultValue = _dev->controlDefault(internalName);
 
376
        choices      = _dev->controlMenuChoices(internalName);
 
377
    }
 
378
 
 
379
    virtual ~KdetvV4L2MenuControl()
 
380
    {
 
381
    }
 
382
 
 
383
    virtual bool doSetValue(const QString& value)
 
384
    {
 
385
        return _dev->setControl(internalName, value);
 
386
    }
 
387
 
 
388
    virtual const QString value() const
 
389
    {
 
390
        return _dev->control(internalName).toString();
 
391
    }
 
392
 
 
393
 
 
394
private:
 
395
    V4L2Dev* _dev;
 
396
};
 
397
 
 
398
class KdetvV4L2ButtonControl : public ButtonControl
 
399
{
 
400
public:
 
401
    KdetvV4L2ButtonControl(const QString& uiname, const QString& internalName, V4L2Dev* dev)
 
402
        : ButtonControl(uiname, internalName),
 
403
          _dev(dev)
 
404
    {
 
405
        advanced = _dev->controlAdvanced(internalName);
 
406
    }
 
407
 
 
408
    virtual ~KdetvV4L2ButtonControl()
 
409
    {
 
410
    }
 
411
 
 
412
    virtual bool click()
 
413
    {
 
414
        return _dev->setControl(internalName, QVariant());
 
415
    }
 
416
 
 
417
private:
 
418
    V4L2Dev* _dev;
 
419
};
 
420
 
 
421
int KdetvV4L2::setDevice( const QString &name )
 
422
{
 
423
    if (!_probed)
 
424
        probeDevices();
 
425
 
 
426
    if (_dev) {
 
427
        stopVideo();
 
428
        delete _dev;
 
429
    }
 
430
 
 
431
    _device = name;
 
432
    _currentDev = _devNames[name];
 
433
    kdDebug() << "V4L2: setDevice [" << name
 
434
              << "] which maps to " << _currentDev << endl;
 
435
 
 
436
    _dev = V4L2Dev::getDevice( _currentDev );
 
437
    kdDebug() << "V4L2: Success? " << (_dev ? "true" : "false") << endl;
 
438
 
 
439
    _audioModes.clear();
 
440
    if (_dev) {
 
441
        _audioModes += _dev->audioModes();
 
442
    }
 
443
 
 
444
    _audioModes.clear();
 
445
    _controls.clear();
 
446
    if(_dev) {
 
447
        _audioModes += _dev->audioModes();
 
448
 
 
449
        const QStringList& controls = _dev->controls();
 
450
        for(QStringList::const_iterator it = controls.constBegin();
 
451
            it != controls.constEnd();
 
452
            ++it) {
 
453
            if(((*it).lower() == "volume") ||
 
454
               ((*it).lower() == "mute")      ) {
 
455
                continue;
 
456
            }
 
457
 
 
458
            switch(_dev->controlType(*it)) {
 
459
            case V4L2Dev::ControlType_Int:
 
460
                _controls.append(new KdetvV4L2IntegerControl(i18n((*it).ascii()), *it, _dev));
 
461
                break;
 
462
            case V4L2Dev::ControlType_Boolean:
 
463
                _controls.append(new KdetvV4L2BooleanControl(i18n((*it).ascii()), *it, _dev));
 
464
                break;
 
465
            case V4L2Dev::ControlType_Button:
 
466
                _controls.append(new KdetvV4L2ButtonControl(i18n((*it).ascii()), *it, _dev));
 
467
                break;
 
468
            case V4L2Dev::ControlType_Menu:
 
469
                _controls.append(new KdetvV4L2MenuControl(i18n((*it).ascii()), *it, _dev));
 
470
                break;
 
471
            default:
 
472
                break;
 
473
            }
 
474
        }
 
475
    }
 
476
 
 
477
    return _dev ? 0 : -1;
 
478
}
 
479
 
 
480
int KdetvV4L2::probeDevices()
 
481
{
 
482
    QString dev;
 
483
    struct stat sb;
 
484
 
 
485
 
 
486
    // don't probe multiple times, it's unnecessary and might yield incorrect
 
487
    // results if plugin is currently using the device
 
488
    if (_probed) return 0;
 
489
 
 
490
    int rc = stat("/dev/v4l", &sb);
 
491
    if (!rc && S_ISDIR(sb.st_mode) && !access("/dev/v4l", R_OK|X_OK)) {
 
492
        // DEVFS
 
493
        dev = "/dev/v4l/video%1";
 
494
    } else {
 
495
        // Normal V4L2 case
 
496
        dev = "/dev/video%1";
 
497
    }
 
498
 
 
499
    _devices.clear();
 
500
    _sources.clear();
 
501
    _tuners.clear();
 
502
    _encodings.clear();
 
503
    _devNames.clear();
 
504
 
 
505
    QString mainVideoDev = QString::null;
 
506
    // FIXME: when we test for devices, we must make sure that we can
 
507
    // actually use them too.  This fails for cases where something else
 
508
    // is using the device currently.
 
509
    if (!access("/dev/video", R_OK|W_OK)) {
 
510
        V4L2Dev *vd = V4L2Dev::getDevice("/dev/video");
 
511
        if (vd) {
 
512
            QString name = "Video4Linux2: " + vd->name();
 
513
            _tuners[name] = vd->isTuner();
 
514
            _sources[name] = vd->sources();
 
515
            _encodings[name] = vd->encodings();
 
516
            _devices.append(name);
 
517
            _devNames[name] = "/dev/video";
 
518
            mainVideoDev = QDir("/dev/video").canonicalPath();
 
519
            delete vd;
 
520
        }
 
521
    }
 
522
 
 
523
    for (int i = 0; i <= 9; i++) {
 
524
        QString dn = dev.arg(i);
 
525
        if (dn != mainVideoDev && !access(dn.local8Bit(), R_OK|W_OK)) {
 
526
            V4L2Dev *vd = V4L2Dev::getDevice(dn);
 
527
            if (vd) {
 
528
                QString name = i18n("Video4Linux2: ") + vd->name();
 
529
                _tuners[name] = vd->isTuner();
 
530
                _sources[name] = vd->sources();
 
531
                _encodings[name] = vd->encodings();
 
532
                _devices.append(name);
 
533
                _devNames[name] = dn;
 
534
                delete vd;
 
535
            }
 
536
        }
 
537
    }
 
538
 
 
539
    _probed = true;
 
540
    return 0;
 
541
}
 
542
 
 
543
// ---------------------------------------------------- Display
 
544
 
 
545
void KdetvV4L2::viewResized()
 
546
{
 
547
    V4L2GrabberLocker l(_g);
 
548
    if (!_dev)
 
549
        return;
 
550
 
 
551
    if(_capturing) {
 
552
        stopVideo();
 
553
        startVideo();
 
554
    }
 
555
}
 
556
 
 
557
// ---------------------------------------------------- Playback
 
558
 
 
559
int KdetvV4L2::startVideo()
 
560
{
 
561
    if(!_dev || _capturing) {
 
562
        return -1;
 
563
    }
 
564
 
 
565
    _vs->setMethod(_qvsMethod);
 
566
    _vs->setFormat(_qvsFormat);
 
567
    _vs->setSize(_w->size());
 
568
 
 
569
    KdetvImageFilterChain* c = driver()->filterManager()->filterChain();
 
570
 
 
571
    calculateGrabFormat(c, _formatConversionFilter);
 
572
    kdDebug() << c->filterChainStatus() << endl;
 
573
 
 
574
    _dev->startStreaming(3);
 
575
 
 
576
    setMuted(false);
 
577
 
 
578
    _g = new V4L2Grabber(this, _dev, _vs, qvideoformat2kdetvimageformat(_dev->inputFormat()));
 
579
    _g->_flt             = c;
 
580
    _g->_fmtConv         = _formatConversionFilter;
 
581
    _g->_fieldTime       = _fieldTime;
 
582
    _g->_mostRecentField = _mostRecentField;
 
583
    _g->_fullFrameRate   = _fullFrameRate;
 
584
    _g->start();
 
585
 
 
586
    _capturing = true;
 
587
 
 
588
    return 0;
 
589
}
 
590
 
 
591
int KdetvV4L2::stopVideo()
 
592
{
 
593
    if (!_capturing)
 
594
        return -1;
 
595
 
 
596
    _dev->stopStreaming();
 
597
    _g->stop();
 
598
    _g = 0;
 
599
 
 
600
    setMuted(true);
 
601
 
 
602
    _capturing = false;
 
603
    return 0;
 
604
}
 
605
 
 
606
void KdetvV4L2::calculateGrabFormat(KdetvImageFilterChain* c, KdetvFormatConversionFilter* f)
 
607
{
 
608
    KdetvImage::ImageFormat outputFormat = qvideoformat2kdetvimageformat(_vs->formatsForMethod(_qvsMethod));
 
609
 
 
610
    kdDebug() << "Trying to build output chain without conversion..." << endl;
 
611
    c->setOutputFormat(outputFormat);
 
612
 
 
613
    // Try grabbing the format the display needs (-> hopefully no conversion necessary)
 
614
    if(_dev->setInputProperties(_vs->formatsForMethod(_qvsMethod), _w->size()).isValid()) {
 
615
        c->setInputFormat(qvideoformat2kdetvimageformat(_dev->inputFormat()));
 
616
        if(c->isValid()) {
 
617
            f->setInputFormat(outputFormat);
 
618
            f->setOutputFormat(outputFormat);
 
619
            kdDebug() << "... successful." << endl;
 
620
            return;
 
621
        }
 
622
    }
 
623
 
 
624
    // No success, try using a use format conversion filter
 
625
    kdDebug() << "... failed. Trying to use format converter..." << endl;
 
626
    KdetvImage::ImageFormat supportedFormats = f->inputFormats();
 
627
    KdetvImage::ImageFormat format = (KdetvImage::ImageFormat)1;
 
628
    do {
 
629
        if(supportedFormats & format) {
 
630
            f->setInputFormat(format);
 
631
 
 
632
            KdetvImage::ImageFormat fmt = (KdetvImage::ImageFormat)1;
 
633
            do {
 
634
                if(f->outputFormats() & c->inputFormats() & fmt) {
 
635
                    if(_dev->setInputProperties(kdetvimageformat2qvideoformat(format), _w->size()).isValid()) {
 
636
                        kdDebug() << "Trying to grab " << KdetvImage::toString(format)
 
637
                                  << " and convert it to " << KdetvImage::toString(fmt) << endl;
 
638
                        f->setOutputFormat(fmt);
 
639
                        c->setInputFormat(fmt);
 
640
                        if(c->isValid()) {
 
641
                            return;
 
642
                        }
 
643
                    }
 
644
                }
 
645
                fmt = (KdetvImage::ImageFormat)(fmt<<1);
 
646
            } while((unsigned)fmt<0x80000000);
 
647
        }
 
648
        format = (KdetvImage::ImageFormat)(format<<1);
 
649
    } while((unsigned)format<0x80000000);
 
650
 
 
651
    // No success. Use display format for grabbing and pray it works.
 
652
    kdWarning() << "... failed. kdetv likely does not to work with your device and/or your current filter config." << endl;
 
653
    _dev->setInputProperties(_vs->formatsForMethod(_qvsMethod), _w->size());
 
654
    c->setInputFormat(qvideoformat2kdetvimageformat(_dev->inputFormat()));
 
655
    return;
 
656
}
 
657
 
 
658
bool KdetvV4L2::videoPlaying() const
 
659
{
 
660
    return _capturing;
 
661
}
 
662
 
 
663
// ---------------------------------------------------- View modes
 
664
 
 
665
bool KdetvV4L2::canVideoDesktop() const
 
666
{
 
667
    return false;
 
668
}
 
669
 
 
670
// ---------------------------------------------------- Snapshots
 
671
 
 
672
bool KdetvV4L2::canGrabStill() const
 
673
{
 
674
    return true;
 
675
}
 
676
 
 
677
bool KdetvV4L2::grabStill(QImage* img)
 
678
{
 
679
    bool rc = false;
 
680
    bool wasCapturing = _capturing;
 
681
    stopVideo();
 
682
 
 
683
    // FIXME: hardcoded image format and endianess
 
684
    KdetvImage im;
 
685
    im.createBuffer(img->width() * img->height() * 4);
 
686
    im.setFormat(KdetvImage::FORMAT_BGR24);
 
687
 
 
688
    im.setSize(_dev->snapshot(im.buffer(), img->size(), QVideo::FORMAT_BGR24));
 
689
 
 
690
    if(im.size().isValid()) {
 
691
        im.toQImage(*img);
 
692
        rc = true;
 
693
    }
 
694
 
 
695
    if(wasCapturing) {
 
696
        startVideo();
 
697
    }
 
698
 
 
699
    return rc;
 
700
}
 
701
 
 
702
// ---------------------------------------------------- Configuration
 
703
 
 
704
QWidget *KdetvV4L2::configWidget(QWidget *parent, const char *name)
 
705
{
 
706
    _cfgWidget = new V4L2ConfigWidget(parent, name);
 
707
 
 
708
    _cfgWidget->_xvideo->setEnabled(_vs->haveMethod(QVideo::METHOD_XV));
 
709
    _cfgWidget->_xvshm->setEnabled (_vs->haveMethod(QVideo::METHOD_XVSHM));
 
710
 
 
711
    switch(_qvsMethod) {
 
712
    case QVideo::METHOD_XV:
 
713
        _cfgWidget->_xvideo->setChecked(true);
 
714
        break;
 
715
    case QVideo::METHOD_XVSHM:
 
716
        _cfgWidget->_xvshm->setChecked(true);
 
717
        break;
 
718
    default:
 
719
        assert(0);
 
720
        break;
 
721
    }
 
722
 
 
723
    _cfgWidget->_autoConfig->setChecked(_autoConfig);
 
724
    if(_fullFrameRate) {
 
725
        _cfgWidget->_frameRateFull->setChecked(true);
 
726
    } else {
 
727
        _cfgWidget->_frameRateHalf->setChecked(true);
 
728
    }
 
729
 
 
730
    return _cfgWidget;
 
731
}
 
732
 
 
733
void KdetvV4L2::saveConfig()
 
734
{
 
735
    _autoConfig    = _cfgWidget->_autoConfig->isChecked();
 
736
    _fullFrameRate = _cfgWidget->_frameRateFull->isChecked();
 
737
 
 
738
    _qvsMethod = QVideo::METHOD_NONE;
 
739
    if (_cfgWidget->_xvideo->isChecked()) {
 
740
        _qvsMethod = QVideo::METHOD_XV;
 
741
    } else if (_cfgWidget->_xvshm->isChecked()) {
 
742
        _qvsMethod = QVideo::METHOD_XVSHM;
 
743
    }
 
744
 
 
745
    _cfg->writeEntry("GD Method", _qvsMethod);
 
746
    _cfg->writeEntry("Autoconfigure", _autoConfig);
 
747
    _cfg->writeEntry("Full Frame Rate", _fullFrameRate);
 
748
 
 
749
    if (_capturing) {
 
750
        stopVideo();
 
751
        _vs->setMethod(_qvsMethod);
 
752
        startVideo();
 
753
    } else {
 
754
        _vs->setMethod(_qvsMethod);
 
755
    }
 
756
 
 
757
    _cfg->sync();
 
758
}
 
759
 
 
760
// ---------------------------------------------------- Misc
 
761
 
 
762
static KdetvImage::ImageFormat qvideoformat2kdetvimageformat(QVideo::ImageFormat fmt)
 
763
{
 
764
    if(fmt & QVideo::FORMAT_GREY) {
 
765
        return KdetvImage::FORMAT_GREY;
 
766
    }
 
767
    if(fmt & QVideo::FORMAT_HI240) {
 
768
        return KdetvImage::FORMAT_HI240;
 
769
    }
 
770
    if(fmt & QVideo::FORMAT_RGB15_LE) {
 
771
        return KdetvImage::FORMAT_RGB15_LE;
 
772
    }
 
773
    if(fmt & QVideo::FORMAT_RGB16_LE) {
 
774
        return KdetvImage::FORMAT_RGB16_LE;
 
775
    }
 
776
    if(fmt & QVideo::FORMAT_RGB15_BE) {
 
777
        return KdetvImage::FORMAT_RGB15_BE;
 
778
    }
 
779
    if(fmt & QVideo::FORMAT_RGB16_BE) {
 
780
        return KdetvImage::FORMAT_RGB16_BE;
 
781
    }
 
782
    if(fmt & QVideo::FORMAT_RGB24) {
 
783
        return KdetvImage::FORMAT_RGB24;
 
784
    }
 
785
    if(fmt & QVideo::FORMAT_RGB32) {
 
786
        return KdetvImage::FORMAT_RGB32;
 
787
    }
 
788
    if(fmt & QVideo::FORMAT_BGR24) {
 
789
        return KdetvImage::FORMAT_BGR24;
 
790
    }
 
791
    if(fmt & QVideo::FORMAT_BGR32) {
 
792
        return KdetvImage::FORMAT_BGR32;
 
793
    }
 
794
    if(fmt & QVideo::FORMAT_YUYV) {
 
795
        return KdetvImage::FORMAT_YUYV;
 
796
    }
 
797
    if(fmt & QVideo::FORMAT_UYVY) {
 
798
        return KdetvImage::FORMAT_UYVY;
 
799
    }
 
800
    if(fmt & QVideo::FORMAT_YUV422P) {
 
801
        return KdetvImage::FORMAT_YUV422P;
 
802
    }
 
803
    if(fmt & QVideo::FORMAT_YUV420P) {
 
804
        return KdetvImage::FORMAT_YUV420P;
 
805
    }
 
806
    return KdetvImage::FORMAT_NONE;
 
807
}
 
808
 
 
809
static QVideo::ImageFormat kdetvimageformat2qvideoformat(KdetvImage::ImageFormat fmt)
 
810
{
 
811
    if(fmt & KdetvImage::FORMAT_GREY) {
 
812
        return QVideo::FORMAT_GREY;
 
813
    }
 
814
    if(fmt & KdetvImage::FORMAT_HI240) {
 
815
        return QVideo::FORMAT_HI240;
 
816
    }
 
817
    if(fmt & KdetvImage::FORMAT_RGB15_LE) {
 
818
        return QVideo::FORMAT_RGB15_LE;
 
819
    }
 
820
    if(fmt & KdetvImage::FORMAT_RGB16_LE) {
 
821
        return QVideo::FORMAT_RGB16_LE;
 
822
    }
 
823
    if(fmt & KdetvImage::FORMAT_RGB15_BE) {
 
824
        return QVideo::FORMAT_RGB15_BE;
 
825
    }
 
826
    if(fmt & KdetvImage::FORMAT_RGB16_BE) {
 
827
        return QVideo::FORMAT_RGB16_BE;
 
828
    }
 
829
    if(fmt & KdetvImage::FORMAT_RGB24) {
 
830
        return QVideo::FORMAT_RGB24;
 
831
    }
 
832
    if(fmt & KdetvImage::FORMAT_RGB32) {
 
833
        return QVideo::FORMAT_RGB32;
 
834
    }
 
835
    if(fmt & KdetvImage::FORMAT_BGR24) {
 
836
        return QVideo::FORMAT_BGR24;
 
837
    }
 
838
    if(fmt & KdetvImage::FORMAT_BGR32) {
 
839
        return QVideo::FORMAT_BGR32;
 
840
    }
 
841
    if(fmt & KdetvImage::FORMAT_YUYV) {
 
842
        return QVideo::FORMAT_YUYV;
 
843
    }
 
844
    if(fmt & KdetvImage::FORMAT_UYVY) {
 
845
        return QVideo::FORMAT_UYVY;
 
846
    }
 
847
    if(fmt & KdetvImage::FORMAT_YUV422P) {
 
848
        return QVideo::FORMAT_YUV422P;
 
849
    }
 
850
    if(fmt & KdetvImage::FORMAT_YUV420P) {
 
851
        return QVideo::FORMAT_YUV420P;
 
852
    }
 
853
    return QVideo::FORMAT_NONE;
 
854
}
 
855
 
 
856
bool KdetvV4L2::event(QEvent* e)
 
857
{
 
858
    if (e->type() == QEvent::User) {
 
859
        emit errorMessage( ((V4L2ErrorEvent*)e)->_msg );
 
860
        stopVideo();
 
861
        return true;
 
862
    } else {
 
863
        return KdetvSourcePlugin::event(e);
 
864
    }
 
865
}
 
866
 
 
867
// ---------------------------------------------------- Factory
 
868
 
 
869
extern "C" {
 
870
    KdetvV4L2* create_v4l2(Kdetv *ktv, QWidget *w) {
 
871
        return new KdetvV4L2(ktv, w, "v4l2 plugin");
 
872
    }
 
873
}