1
/***************************************************************************
4
begin : Thu Oct 27 2004
5
copyright : (C) 2004 by Dirk Ziegelmeier
7
***************************************************************************/
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.
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.
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.
31
#include <qradiobutton.h>
32
#include <qcheckbox.h>
44
#include <sys/types.h>
50
#include "kdetv_v4l2.h"
51
#include "kdetv_grabber.h"
53
#include "qvideostream.h"
57
#include "v4l2configwidget.h"
58
#include "kdetvvideo/kdetvimagefilter.h"
59
#include "kdetvvideo/kdetvformatconversionfilter.h"
60
#include "filtermanager.h"
62
#include "kdetv_v4l2.moc"
64
static KdetvImage::ImageFormat qvideoformat2kdetvimageformat(QVideo::ImageFormat fmt);
65
static QVideo::ImageFormat kdetvimageformat2qvideoformat(KdetvImage::ImageFormat fmt);
67
KdetvV4L2::KdetvV4L2(Kdetv *ktv, QWidget *parent, const char *name)
68
: KdetvSourcePlugin(ktv, "v4l2", parent, name),
72
_qvsFormat(QVideo::FORMAT_YUYV),
76
_mostRecentField(KdetvImage::TYPE_INTERLACED_ODD)
78
_vs = new QVideoStream(_w);
79
_formatConversionFilter = new KdetvFormatConversionFilter();
81
// figure out best method available
82
QVideo::VideoMethod bestAvailable = QVideo::METHOD_XVSHM;
83
if (!_vs->haveMethod(bestAvailable)) {
84
bestAvailable = QVideo::METHOD_XV;
87
_cfg->setGroup("V4L2 Plugin");
88
_autoConfig = _cfg->readBoolEntry("Autoconfigure", true);
91
_qvsMethod = bestAvailable;
92
_fullFrameRate = false;
94
_qvsMethod = (QVideo::VideoMethod)_cfg->readNumEntry("GD Method", bestAvailable);
96
// saved config may be invalid due to graphics card change
97
if (!_vs->haveMethod(_qvsMethod)) {
98
_qvsMethod = bestAvailable;
100
_fullFrameRate = _cfg->readBoolEntry("Full Frame Rate", false);
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).
112
connect(qApp, SIGNAL( aboutToQuit() ),
113
this, SLOT( stopVideo() ) );
115
connect( parent, SIGNAL( resized(int, int) ),
116
this, SLOT( viewResized() ) );
118
kdDebug() << "Kdetv V4L2 plugin loaded successfully." << endl;
122
KdetvV4L2::~KdetvV4L2()
131
// ---------------------------------------------------- Tuner
133
int KdetvV4L2::setChannelProperties(const Channel::PropertyList& properties)
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());
140
bool wasCapturing = _capturing;
143
setSource(properties["source"].toString());
144
setEncoding(properties["encoding"].toString());
145
setFrequency(properties["frequency"].toULongLong());
154
bool KdetvV4L2::isTuner()
156
return _dev ? _dev->isTuner() : false;
159
int KdetvV4L2::signal()
161
return _dev ? _dev->signal() : -1;
164
int KdetvV4L2::frequency()
166
if ( !_dev || !_dev->isTuner() ) {
170
return (int)(_dev->frequency() / 1000);
173
void KdetvV4L2::setFrequency( int freq )
175
if ( !_dev || !_dev->isTuner() ) {
178
_dev->setFrequency((double)freq * 1000);
181
int KdetvV4L2::setSource( const QString &src )
186
bool wasCapturing = _capturing;
189
bool rc = _dev->setSource(src);
190
_source = _dev->source();
198
int KdetvV4L2::setEncoding( const QString &encoding )
203
bool wasCapturing = _capturing;
206
bool rc = _dev->setEncoding( encoding );
207
_encoding = _dev->encoding();
209
if(_encoding == "ntsc" ||
210
_encoding == "ntsc-jp" ||
211
_encoding == "pal-m" ) {
213
// NTSC and PAL-M transmit ODD fields first
214
_mostRecentField = KdetvImage::TYPE_INTERLACED_EVEN;
217
// all others EVEN fields first
218
_mostRecentField = KdetvImage::TYPE_INTERLACED_ODD;
221
_g->_fieldTime = _fieldTime;
222
_g->_mostRecentField = _mostRecentField;
232
// ---------------------------------------------------- Audio
234
bool KdetvV4L2::muted()
236
return _dev->control("Mute").toBool();
239
void KdetvV4L2::setMuted( bool muted )
241
_dev->setControl("Mute", QVariant(muted, 0));
244
bool KdetvV4L2::setVolume( int left, int right )
246
if(!_dev->hasControl("Volume")) {
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));
255
return _dev->setControl("Volume", val);
258
const QStringList& KdetvV4L2::broadcastedAudioModes()
260
static QStringList empty;
265
return _dev->broadcastedAudioModes();
268
const QString& KdetvV4L2::defaultAudioMode()
270
const QStringList& modes = broadcastedAudioModes();
272
// FIXME: a more intelligent and general algorithm would not hurt...
273
if (modes.contains(i18n("Stereo"))) {
274
return modes[modes.findIndex(i18n("Stereo"))];
277
if (modes.contains(i18n("Language 1"))) {
278
return modes[modes.findIndex(i18n("Language 1"))];
281
return broadcastedAudioModes().first();
284
int KdetvV4L2::setAudioMode( const QString& audioMode )
289
return _dev->setAudioMode(audioMode);
292
// ---------------------------------------------------- Device, Controls
294
QColor KdetvV4L2::colourKey()
299
Control::ControlList& KdetvV4L2::controls()
304
class KdetvV4L2IntegerControl : public IntegerControl
307
KdetvV4L2IntegerControl(const QString& uiname, const QString& internalName, V4L2Dev* dev)
308
: IntegerControl(uiname, internalName),
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);
318
virtual ~KdetvV4L2IntegerControl()
322
virtual bool doSetValue(int value)
324
return _dev->setControl(internalName, value);
327
virtual int value() const
329
return _dev->control(internalName).toInt();
337
class KdetvV4L2BooleanControl : public BooleanControl
340
KdetvV4L2BooleanControl(const QString& uiname, const QString& internalName, V4L2Dev* dev)
341
: BooleanControl(uiname, internalName),
344
advanced = _dev->controlAdvanced(internalName);
345
defaultValue = _dev->controlDefault(internalName);
348
virtual ~KdetvV4L2BooleanControl()
352
virtual bool doSetValue(bool value)
354
return _dev->setControl(internalName, QVariant(value, 0));
357
virtual bool value() const
359
return _dev->control(internalName).toInt();
367
class KdetvV4L2MenuControl : public MenuControl
370
KdetvV4L2MenuControl(const QString& uiname, const QString& internalName, V4L2Dev* dev)
371
: MenuControl(uiname, internalName),
374
advanced = _dev->controlAdvanced(internalName);
375
defaultValue = _dev->controlDefault(internalName);
376
choices = _dev->controlMenuChoices(internalName);
379
virtual ~KdetvV4L2MenuControl()
383
virtual bool doSetValue(const QString& value)
385
return _dev->setControl(internalName, value);
388
virtual const QString value() const
390
return _dev->control(internalName).toString();
398
class KdetvV4L2ButtonControl : public ButtonControl
401
KdetvV4L2ButtonControl(const QString& uiname, const QString& internalName, V4L2Dev* dev)
402
: ButtonControl(uiname, internalName),
405
advanced = _dev->controlAdvanced(internalName);
408
virtual ~KdetvV4L2ButtonControl()
414
return _dev->setControl(internalName, QVariant());
421
int KdetvV4L2::setDevice( const QString &name )
432
_currentDev = _devNames[name];
433
kdDebug() << "V4L2: setDevice [" << name
434
<< "] which maps to " << _currentDev << endl;
436
_dev = V4L2Dev::getDevice( _currentDev );
437
kdDebug() << "V4L2: Success? " << (_dev ? "true" : "false") << endl;
441
_audioModes += _dev->audioModes();
447
_audioModes += _dev->audioModes();
449
const QStringList& controls = _dev->controls();
450
for(QStringList::const_iterator it = controls.constBegin();
451
it != controls.constEnd();
453
if(((*it).lower() == "volume") ||
454
((*it).lower() == "mute") ) {
458
switch(_dev->controlType(*it)) {
459
case V4L2Dev::ControlType_Int:
460
_controls.append(new KdetvV4L2IntegerControl(i18n((*it).ascii()), *it, _dev));
462
case V4L2Dev::ControlType_Boolean:
463
_controls.append(new KdetvV4L2BooleanControl(i18n((*it).ascii()), *it, _dev));
465
case V4L2Dev::ControlType_Button:
466
_controls.append(new KdetvV4L2ButtonControl(i18n((*it).ascii()), *it, _dev));
468
case V4L2Dev::ControlType_Menu:
469
_controls.append(new KdetvV4L2MenuControl(i18n((*it).ascii()), *it, _dev));
477
return _dev ? 0 : -1;
480
int KdetvV4L2::probeDevices()
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;
490
int rc = stat("/dev/v4l", &sb);
491
if (!rc && S_ISDIR(sb.st_mode) && !access("/dev/v4l", R_OK|X_OK)) {
493
dev = "/dev/v4l/video%1";
496
dev = "/dev/video%1";
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");
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();
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);
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;
543
// ---------------------------------------------------- Display
545
void KdetvV4L2::viewResized()
547
V4L2GrabberLocker l(_g);
557
// ---------------------------------------------------- Playback
559
int KdetvV4L2::startVideo()
561
if(!_dev || _capturing) {
565
_vs->setMethod(_qvsMethod);
566
_vs->setFormat(_qvsFormat);
567
_vs->setSize(_w->size());
569
KdetvImageFilterChain* c = driver()->filterManager()->filterChain();
571
calculateGrabFormat(c, _formatConversionFilter);
572
kdDebug() << c->filterChainStatus() << endl;
574
_dev->startStreaming(3);
578
_g = new V4L2Grabber(this, _dev, _vs, qvideoformat2kdetvimageformat(_dev->inputFormat()));
580
_g->_fmtConv = _formatConversionFilter;
581
_g->_fieldTime = _fieldTime;
582
_g->_mostRecentField = _mostRecentField;
583
_g->_fullFrameRate = _fullFrameRate;
591
int KdetvV4L2::stopVideo()
596
_dev->stopStreaming();
606
void KdetvV4L2::calculateGrabFormat(KdetvImageFilterChain* c, KdetvFormatConversionFilter* f)
608
KdetvImage::ImageFormat outputFormat = qvideoformat2kdetvimageformat(_vs->formatsForMethod(_qvsMethod));
610
kdDebug() << "Trying to build output chain without conversion..." << endl;
611
c->setOutputFormat(outputFormat);
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()));
617
f->setInputFormat(outputFormat);
618
f->setOutputFormat(outputFormat);
619
kdDebug() << "... successful." << endl;
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;
629
if(supportedFormats & format) {
630
f->setInputFormat(format);
632
KdetvImage::ImageFormat fmt = (KdetvImage::ImageFormat)1;
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);
645
fmt = (KdetvImage::ImageFormat)(fmt<<1);
646
} while((unsigned)fmt<0x80000000);
648
format = (KdetvImage::ImageFormat)(format<<1);
649
} while((unsigned)format<0x80000000);
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()));
658
bool KdetvV4L2::videoPlaying() const
663
// ---------------------------------------------------- View modes
665
bool KdetvV4L2::canVideoDesktop() const
670
// ---------------------------------------------------- Snapshots
672
bool KdetvV4L2::canGrabStill() const
677
bool KdetvV4L2::grabStill(QImage* img)
680
bool wasCapturing = _capturing;
683
// FIXME: hardcoded image format and endianess
685
im.createBuffer(img->width() * img->height() * 4);
686
im.setFormat(KdetvImage::FORMAT_BGR24);
688
im.setSize(_dev->snapshot(im.buffer(), img->size(), QVideo::FORMAT_BGR24));
690
if(im.size().isValid()) {
702
// ---------------------------------------------------- Configuration
704
QWidget *KdetvV4L2::configWidget(QWidget *parent, const char *name)
706
_cfgWidget = new V4L2ConfigWidget(parent, name);
708
_cfgWidget->_xvideo->setEnabled(_vs->haveMethod(QVideo::METHOD_XV));
709
_cfgWidget->_xvshm->setEnabled (_vs->haveMethod(QVideo::METHOD_XVSHM));
712
case QVideo::METHOD_XV:
713
_cfgWidget->_xvideo->setChecked(true);
715
case QVideo::METHOD_XVSHM:
716
_cfgWidget->_xvshm->setChecked(true);
723
_cfgWidget->_autoConfig->setChecked(_autoConfig);
725
_cfgWidget->_frameRateFull->setChecked(true);
727
_cfgWidget->_frameRateHalf->setChecked(true);
733
void KdetvV4L2::saveConfig()
735
_autoConfig = _cfgWidget->_autoConfig->isChecked();
736
_fullFrameRate = _cfgWidget->_frameRateFull->isChecked();
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;
745
_cfg->writeEntry("GD Method", _qvsMethod);
746
_cfg->writeEntry("Autoconfigure", _autoConfig);
747
_cfg->writeEntry("Full Frame Rate", _fullFrameRate);
751
_vs->setMethod(_qvsMethod);
754
_vs->setMethod(_qvsMethod);
760
// ---------------------------------------------------- Misc
762
static KdetvImage::ImageFormat qvideoformat2kdetvimageformat(QVideo::ImageFormat fmt)
764
if(fmt & QVideo::FORMAT_GREY) {
765
return KdetvImage::FORMAT_GREY;
767
if(fmt & QVideo::FORMAT_HI240) {
768
return KdetvImage::FORMAT_HI240;
770
if(fmt & QVideo::FORMAT_RGB15_LE) {
771
return KdetvImage::FORMAT_RGB15_LE;
773
if(fmt & QVideo::FORMAT_RGB16_LE) {
774
return KdetvImage::FORMAT_RGB16_LE;
776
if(fmt & QVideo::FORMAT_RGB15_BE) {
777
return KdetvImage::FORMAT_RGB15_BE;
779
if(fmt & QVideo::FORMAT_RGB16_BE) {
780
return KdetvImage::FORMAT_RGB16_BE;
782
if(fmt & QVideo::FORMAT_RGB24) {
783
return KdetvImage::FORMAT_RGB24;
785
if(fmt & QVideo::FORMAT_RGB32) {
786
return KdetvImage::FORMAT_RGB32;
788
if(fmt & QVideo::FORMAT_BGR24) {
789
return KdetvImage::FORMAT_BGR24;
791
if(fmt & QVideo::FORMAT_BGR32) {
792
return KdetvImage::FORMAT_BGR32;
794
if(fmt & QVideo::FORMAT_YUYV) {
795
return KdetvImage::FORMAT_YUYV;
797
if(fmt & QVideo::FORMAT_UYVY) {
798
return KdetvImage::FORMAT_UYVY;
800
if(fmt & QVideo::FORMAT_YUV422P) {
801
return KdetvImage::FORMAT_YUV422P;
803
if(fmt & QVideo::FORMAT_YUV420P) {
804
return KdetvImage::FORMAT_YUV420P;
806
return KdetvImage::FORMAT_NONE;
809
static QVideo::ImageFormat kdetvimageformat2qvideoformat(KdetvImage::ImageFormat fmt)
811
if(fmt & KdetvImage::FORMAT_GREY) {
812
return QVideo::FORMAT_GREY;
814
if(fmt & KdetvImage::FORMAT_HI240) {
815
return QVideo::FORMAT_HI240;
817
if(fmt & KdetvImage::FORMAT_RGB15_LE) {
818
return QVideo::FORMAT_RGB15_LE;
820
if(fmt & KdetvImage::FORMAT_RGB16_LE) {
821
return QVideo::FORMAT_RGB16_LE;
823
if(fmt & KdetvImage::FORMAT_RGB15_BE) {
824
return QVideo::FORMAT_RGB15_BE;
826
if(fmt & KdetvImage::FORMAT_RGB16_BE) {
827
return QVideo::FORMAT_RGB16_BE;
829
if(fmt & KdetvImage::FORMAT_RGB24) {
830
return QVideo::FORMAT_RGB24;
832
if(fmt & KdetvImage::FORMAT_RGB32) {
833
return QVideo::FORMAT_RGB32;
835
if(fmt & KdetvImage::FORMAT_BGR24) {
836
return QVideo::FORMAT_BGR24;
838
if(fmt & KdetvImage::FORMAT_BGR32) {
839
return QVideo::FORMAT_BGR32;
841
if(fmt & KdetvImage::FORMAT_YUYV) {
842
return QVideo::FORMAT_YUYV;
844
if(fmt & KdetvImage::FORMAT_UYVY) {
845
return QVideo::FORMAT_UYVY;
847
if(fmt & KdetvImage::FORMAT_YUV422P) {
848
return QVideo::FORMAT_YUV422P;
850
if(fmt & KdetvImage::FORMAT_YUV420P) {
851
return QVideo::FORMAT_YUV420P;
853
return QVideo::FORMAT_NONE;
856
bool KdetvV4L2::event(QEvent* e)
858
if (e->type() == QEvent::User) {
859
emit errorMessage( ((V4L2ErrorEvent*)e)->_msg );
863
return KdetvSourcePlugin::event(e);
867
// ---------------------------------------------------- Factory
870
KdetvV4L2* create_v4l2(Kdetv *ktv, QWidget *w) {
871
return new KdetvV4L2(ktv, w, "v4l2 plugin");