Re: kdetv fail at startup (and xawtv succed) : pvrusb2 v4l2
Dirk Ziegelmeier <[email protected]> Mon, 7 Mar 2005 18:02:04 +0100
| Newsgroups | gmane.comp.kde.kwintv |
|---|---|
| Message-ID | <[email protected]> |
On Sunday 06 March 2005 14:50, [email protected] wrote: > Hi, > > I'm usign a Hauppauge WinTV-PVR-usb2 with the > http://justiceforall.free.fr/pvrusb2.html driver and it works without > problem with xawtv4 CVS. > > kdetv failed at startup looping on : > kdetv: WARNING: V4L2Dev: VIDIOC_QUERYMENU failed: Invalid argument > kdetv: WARNING: V4L2Dev: VIDIOC_QUERYMENU failed: Invalid argument > kdetv: WARNING: V4L2Dev: VIDIOC_QUERYMENU failed: Invalid argument > kdetv: WARNING: V4L2Dev: VIDIOC_QUERYMENU failed: Invalid argument > (inifite loop on this warning). > > I have read the sources : kdetv vl42 plugin and xawtv4 seems to init the > card almost the way. I'm was not able to wolve the problem. > Any ideas to get kdetv working? Cool, the first user with a "menu" control ;-) Now you get my debugger. Please try recompiling the attached file (kvideoio/v4l2dev.cpp) Dirk _______________________________________________ kwintv mailing list [email protected] https://mail.kde.org/mailman/listinfo/kwintv
v4l2dev.cpp
(text/x-c++src, 33.3 KB)
/***************************************************************************
v4l2dev.cpp
-----------
begin : Sat Oct 24 2004
copyright : (C) 2004 by Dirk Ziegelmeier
email : [email protected]
***************************************************************************/
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef __STRICT_ANSI__
#define FOO__STRICT_ANSI__
#undef __STRICT_ANSI__
#endif
#include <asm/types.h>
#ifdef FOO__STRICT_ANSI__
#define __STRICT_ANSI__
#undef FOO__STRICT_ANSI__
#endif
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <strings.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <kdebug.h>
#include <klocale.h>
#include "kv4lsetup/videodev2.h"
#include "v4l2dev.h"
#define _DEBUG
//#define DEBUG kdDebug()
#define DEBUG kndDebug()
// static void printBuffer(struct v4l2_buffer& desc);
V4L2Dev* V4L2Dev::getDevice( const QString &dev )
{
int fd = ::open(dev.local8Bit(), O_RDWR);
if(fd < 0) {
return NULL;
}
// ----------- Query capabilities
kdDebug() << "V4L2Dev: device \"" << dev << "\" capabilities: " << endl;
struct v4l2_capability desc;
memset(&desc, 0, sizeof(desc));
int rc = ::ioctl(fd, VIDIOC_QUERYCAP, &desc);
if(rc >= 0) {
kdDebug() << " Driver: " << (const char*)desc.driver << " "
<< ((desc.version>>16) & 0xFF) << "."
<< ((desc.version>> 8) & 0xFF) << "."
<< ((desc.version ) & 0xFF) << endl;
kdDebug() << " Card: " << (const char*)desc.card << endl;
kdDebug() << " Bus info: " << (const char*)desc.card << endl;
kdDebug() << " Capabilities:" << endl;
if(desc.capabilities & V4L2_CAP_VIDEO_CAPTURE)
kdDebug() << " Video capture" << endl;
if(desc.capabilities & V4L2_CAP_VIDEO_OUTPUT)
kdDebug() << " Video output" << endl;
if(desc.capabilities & V4L2_CAP_VIDEO_OVERLAY)
kdDebug() << " Video overlay" << endl;
if(desc.capabilities & V4L2_CAP_VBI_CAPTURE)
kdDebug() << " VBI capture" << endl;
if(desc.capabilities & V4L2_CAP_VBI_OUTPUT)
kdDebug() << " VBI output" << endl;
if(desc.capabilities & V4L2_CAP_RDS_CAPTURE)
kdDebug() << " RDS capture" << endl;
if(desc.capabilities & V4L2_CAP_TUNER)
kdDebug() << " Tuner IO" << endl;
if(desc.capabilities & V4L2_CAP_AUDIO)
kdDebug() << " Audio IO" << endl;
if(desc.capabilities & V4L2_CAP_READWRITE)
kdDebug() << " Read/Write interface" << endl;
if(desc.capabilities & V4L2_CAP_ASYNCIO)
kdDebug() << " Async IO interface" << endl;
if(desc.capabilities & V4L2_CAP_STREAMING)
kdDebug() << " Streaming interface" << endl;
if(desc.capabilities & V4L2_CAP_STREAMING) {
return new V4L2Dev(fd,
(const char*)desc.card,
(desc.capabilities & V4L2_CAP_READWRITE) != 0);
}
}
::close(fd);
kdWarning() << "Device does not support streaming interface or is not a V4L2 device." << endl;
return NULL;
}
V4L2Dev::V4L2Dev(int fd, const QString& name, bool supportsReadWrite)
: _fd(fd),
_streamingBufferCount(0),
_streaming(false),
_name(name),
_isTuner(false),
_supportsReadWrite(supportsReadWrite)
{
bool ok;
// Set priority
v4l2_priority pdesc = V4L2_PRIORITY_DEFAULT;
xioctl(VIDIOC_S_PRIORITY, &pdesc, EINVAL);
// ----------- Enumerate grab formats
DEBUG << "Enumerating grab formats: " << endl;
ok = true;
for(int i=0; ok; i++) {
struct v4l2_fmtdesc desc;
memset(&desc, 0, sizeof(desc));
desc.index = i;
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ok = xioctl(VIDIOC_ENUM_FMT, &desc, EINVAL);
if(ok) {
DEBUG << " " << (const char*)desc.description << endl;
ImageFormat f = v4l2format2qvideoformat(desc.pixelformat);
if(f != FORMAT_NONE) {
_grabFormats = (ImageFormat)(_grabFormats | f);
}
}
}
// ----------- Enumerate video inputs
DEBUG << "Enumerating video inputs: " << endl;
ok = true;
for(int i=0; ok; i++) {
struct v4l2_input desc;
memset(&desc, 0, sizeof(desc));
desc.index = i;
ok = xioctl(VIDIOC_ENUMINPUT, &desc, EINVAL);
if(ok) {
QString name = QString((const char*)desc.name).lower();
DEBUG << " " << name << " (tuner: " << ((desc.type & V4L2_INPUT_TYPE_TUNER) != 0) << ")" << endl;
if((desc.type & V4L2_INPUT_TYPE_TUNER) != 0) {
_tunerForInput[name] = desc.tuner;
_isTuner = true;
} else {
_tunerForInput[name] = -1;
}
_videoInputs[name] = i;
}
}
// ----------- Enumerate video standarts
DEBUG << "Enumerating video standarts: " << endl;
ok = true;
for(int i=0; ok; i++) {
struct v4l2_standard desc;
memset(&desc, 0, sizeof(desc));
desc.index = i;
ok = xioctl(VIDIOC_ENUMSTD, &desc, EINVAL);
if(ok) {
QString name = QString((const char*)desc.name).lower();
DEBUG << " " << name << endl;
_videoStandarts[name] = desc.id;
}
}
// ----------- Enumerate controls
DEBUG << "Enumerating public controls: " << endl;
ok = true;
for(int i=V4L2_CID_BASE;
ok && (i < V4L2_CID_LASTP1);
i++) {
struct v4l2_queryctrl desc;
memset(&desc, 0, sizeof(desc));
desc.id = i;
ok = xioctl(VIDIOC_QUERYCTRL, &desc, EINVAL);
if( ok && !(desc.flags & V4L2_CTRL_FLAG_DISABLED)) {
_controls[(const char*)desc.name] = parseControl(desc);
_controls[(const char*)desc.name]->advanced = false;
}
}
DEBUG << "Enumerating private controls: " << endl;
ok = true;
for(int i=V4L2_CID_PRIVATE_BASE; ok; i++) {
struct v4l2_queryctrl desc;
memset(&desc, 0, sizeof(desc));
desc.id = i;
ok = xioctl(VIDIOC_QUERYCTRL, &desc, EINVAL);
if( ok && !(desc.flags & V4L2_CTRL_FLAG_DISABLED)) {
_controls[(const char*)desc.name] = parseControl(desc);
_controls[(const char*)desc.name]->advanced = true;
}
}
// Init input dependent attributes
setSource(source());
_audioMap[i18n("Mono")] = V4L2_TUNER_SUB_MONO;
_audioMap[i18n("Stereo")] = V4L2_TUNER_SUB_STEREO;
_audioMap[i18n("Language 1")] = V4L2_TUNER_SUB_LANG1;
_audioMap[i18n("Language 2")] = V4L2_TUNER_SUB_LANG2;
_audioModes += _audioMap.keys();
}
V4L2Dev::~V4L2Dev()
{
cleanup();
::close(_fd);
}
const QString& V4L2Dev::name()
{
return _name;
}
// -----------------------------------------------------------------------
V4L2Dev::controlDescriptor* V4L2Dev::parseControl(const v4l2_queryctrl& desc)
{
controlDescriptor* d = new controlDescriptor();
d->id = desc.id;
d->type = translateV4L2ControlType(desc.type);
d->name = QString((const char*)desc.name);
d->minVal = desc.minimum;
d->maxVal = desc.maximum;
d->step = desc.step;
d->defaultVal = desc.default_value;
switch(d->type) {
case ControlType_Int:
DEBUG << " " << (const char*)desc.name
<< " - type: Integer; range: [" << d->minVal << ".." << d->maxVal << "]; step: " << d->step
<< "; default: " << d->defaultVal << "." << endl;
break;
case ControlType_Boolean:
DEBUG << " " << (const char*)desc.name
<< " - type: Boolean; default: " << d->defaultVal << "." << endl;
break;
case ControlType_Menu:
// Options are enumerated below
break;
case ControlType_Button:
DEBUG << " " << (const char*)desc.name << " - type: Button." << endl;
break;
default:
DEBUG << " " << (const char*)desc.name << " - type: Unknown." << endl;
break;
}
if(desc.type == V4L2_CTRL_TYPE_MENU) {
DEBUG << " " << (const char*)desc.name << " - type: Menu. Getting options:" << endl;
bool ok = true;
for(int i=0; ok; i++) {
struct v4l2_querymenu mdesc;
memset(&mdesc, 0, sizeof(mdesc));
mdesc.id = desc.id;
mdesc.index = i;
ok = xioctl(VIDIOC_QUERYMENU, &mdesc);
if(ok) {
DEBUG << " " << (const char*)mdesc.name << endl;
d->choices.append((const char*)mdesc.name);
}
}
}
return d;
}
QVariant V4L2Dev::control(const QString& name) const
{
const controlDescriptor* d;
if(_controls.contains(name)) {
d = _controls[name];
} else {
kdDebug() << "V4L2Dev::control(): " << name << ": no such control." << endl;
return QVariant();
}
struct v4l2_control desc;
desc.id = d->id;
desc.value = 0;
if(xioctl(VIDIOC_G_CTRL, &desc)) {
switch(_controls[name]->type) {
case ControlType_Int:
DEBUG << "V4L2Dev::control(): " << name << ": " << (int)desc.value << endl;
return QVariant((int)desc.value);
break;
case ControlType_Boolean:
DEBUG << "V4L2Dev::control(): " << name << ": " << (bool)desc.value << endl;
return QVariant((bool)desc.value, 0);
break;
case ControlType_Menu:
DEBUG << "V4L2Dev::control(): " << name << ": " << d->choices[desc.value] << endl;
return QVariant(d->choices[desc.value]);
break;
default:
break;
}
}
kdDebug() << "V4L2Dev::control(): IOCTL failed or unknown control type." << endl;
return QVariant();
}
bool V4L2Dev::setControl(const QString& name, const QVariant& value) const
{
const controlDescriptor* d;
if(_controls.contains(name)) {
d = _controls[name];
} else {
kdDebug() << "V4L2Dev::setControl(): " << name << ": no such control." << endl;
return false;
}
DEBUG << "V4L2Dev::setControl(): " << name << ": " << value.toString() << endl;
struct v4l2_control desc;
desc.id = d->id;
switch(_controls[name]->type) {
case ControlType_Int:
if(value.type() != QVariant::Int) {
return false;
}
desc.value = value.toInt();
break;
case ControlType_Boolean:
if(value.type() != QVariant::Bool) {
return false;
}
desc.value = value.toBool();
break;
case ControlType_Menu:
{
if(value.type() != QVariant::String) {
return false;
}
int index = d->choices.findIndex(value.toString());
if(index == -1) {
return false;
}
desc.value = index;
break;
}
case ControlType_Button:
desc.value = 0;
break;
default:
return false;
}
return xioctl(VIDIOC_S_CTRL, &desc);
}
// -----------------------------------------------------------------------
bool V4L2Dev::setSource(const QString& name)
{
DEBUG << "V4L2Dev::setSource(): " << name << endl;
if(_videoInputs.contains(name)) {
int id = _videoInputs[name];
if(xioctl(VIDIOC_S_INPUT, &id)) {
_currentTuner = _tunerForInput[name];
if(_currentTuner != -1) {
struct v4l2_tuner desc;
memset(&desc, 0, sizeof(desc));
desc.index = _currentTuner;
if(xioctl(VIDIOC_G_TUNER, &desc)) {
_currentTunerType = desc.type;
if(desc.capability & V4L2_TUNER_CAP_LOW) {
_frequencyScale = 62.5;
} else {
_frequencyScale = 62500;
}
}
}
return true;
}
}
_currentTuner = -1;
return false;
}
const QString& V4L2Dev::source() const
{
int id;
if(xioctl(VIDIOC_G_INPUT, &id)) {
for(QMap<QString, int>::const_iterator it = _videoInputs.constBegin();
it != _videoInputs.constEnd();
++it) {
if(it.data() == id) {
DEBUG << "V4L2Dev::source(): " << it.key() << endl;
return it.key();
}
}
}
return QString::null;
}
// -----------------------------------------------------------------------
bool V4L2Dev::setEncoding(const QString& name)
{
DEBUG << "V4L2Dev::setEncoding(): " << name << endl;
if(!_videoStandarts.contains(name)) {
return false;
}
v4l2_std_id id = _videoStandarts[name];
return xioctl(VIDIOC_S_STD, &id);
}
const QString& V4L2Dev::encoding() const
{
v4l2_std_id id;
if(xioctl(VIDIOC_G_STD, &id)) {
for(QMap<QString, Q_ULLONG>::const_iterator it = _videoStandarts.constBegin();
it != _videoStandarts.constEnd();
++it) {
if(it.data() == id) {
DEBUG << "V4L2Dev::encoding(): " << it.key() << endl;
return it.key();
}
}
}
return QString::null;
}
// -----------------------------------------------------------------------
bool V4L2Dev::setAudioMode(const QString& mode)
{
DEBUG << "V4L2Dev::setAudioMode(): " << mode << endl;
if(_currentTuner == -1) {
return false;
}
struct v4l2_tuner desc;
memset(&desc, 0, sizeof(desc));
desc.index = _currentTuner;
if(mode == i18n("Mono")) {
desc.audmode = V4L2_TUNER_MODE_MONO;
} else if (mode == i18n("Stereo")) {
desc.audmode = V4L2_TUNER_MODE_STEREO;
} else if (mode == i18n("Language 1")) {
desc.audmode = V4L2_TUNER_MODE_LANG1;
} else if (mode == i18n("Language 2")) {
desc.audmode = V4L2_TUNER_MODE_LANG2;
} else {
return false;
}
return xioctl(VIDIOC_S_TUNER, &desc);
}
const QStringList& V4L2Dev::broadcastedAudioModes()
{
_broadcastedAudioModes.clear();
if(_currentTuner != -1) {
struct v4l2_tuner desc;
memset(&desc, 0, sizeof(desc));
desc.index = _currentTuner;
if (xioctl(VIDIOC_G_TUNER, &desc)) {
for (QMapConstIterator<QString, int> it(_audioMap.constBegin());
it != _audioMap.constEnd();
++it) {
if (it.data() & desc.rxsubchans) {
_broadcastedAudioModes.append(it.key());
}
}
}
}
return _broadcastedAudioModes;
}
// -----------------------------------------------------------------------
QSize V4L2Dev::setInputProperties(ImageFormat fmt, const QSize& sz)
{
DEBUG << "V4L2Dev::setInputProperties(): qvideo format: " << fmt << ", size: " << sz << endl;
if(_streaming) {
stopStreaming();
}
// Fixup size - YUV formats only support multiples of 2
QSize size = QSize(sz.width() & 0xFFFFFFFE, sz.height());
struct v4l2_format desc;
memset(&desc, 0, sizeof(desc));
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
desc.fmt.pix.width = size.width();
desc.fmt.pix.height = size.height();
desc.fmt.pix.pixelformat = qvideoformat2v4l2format(fmt);
desc.fmt.pix.field = V4L2_FIELD_INTERLACED;
desc.fmt.pix.bytesperline = bytesppForFormat(fmt) * size.width();
if(xioctl(VIDIOC_S_FMT, &desc) && (desc.fmt.pix.pixelformat == qvideoformat2v4l2format(fmt))) {
DEBUG << "V4L2Dev::setInputProperties(): ok (got v4l2 format: " << qvideoformat2v4l2format(fmt)
<< ", size: " << QSize(desc.fmt.pix.width, desc.fmt.pix.height) << ")" << endl;
return QSize(desc.fmt.pix.width, desc.fmt.pix.height);
} else {
kdWarning() << "V4L2Dev::setInputProperties(): failed" << endl;
return QSize();
}
}
QVideo::ImageFormat V4L2Dev::inputFormat() const
{
struct v4l2_format desc;
memset(&desc, 0, sizeof(desc));
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(xioctl(VIDIOC_G_FMT, &desc)) {
DEBUG << "V4L2Dev::inputFormat(): " << v4l2format2qvideoformat(desc.fmt.pix.pixelformat) << endl;
return v4l2format2qvideoformat(desc.fmt.pix.pixelformat);
} else {
return FORMAT_NONE;
}
}
QSize V4L2Dev::inputSize() const
{
struct v4l2_format desc;
memset(&desc, 0, sizeof(desc));
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(xioctl(VIDIOC_G_FMT, &desc)) {
// DEBUG << "V4L2Dev::inputSize(): " << QSize(desc.fmt.pix.width, desc.fmt.pix.height) << endl;
return QSize(desc.fmt.pix.width, desc.fmt.pix.height);
} else {
return QSize();
}
}
// -----------------------------------------------------------------------
double V4L2Dev::frequency() const
{
if(_currentTuner == -1) {
return false;
}
struct v4l2_frequency desc;
memset(&desc, 0, sizeof(desc));
desc.tuner = _currentTuner;
if(xioctl(VIDIOC_G_FREQUENCY, &desc)) {
DEBUG << "V4L2Dev::frequency(): " << (((double)desc.frequency) * _frequencyScale) << endl;
return ((double)desc.frequency) * _frequencyScale;
}
return 0;
}
double V4L2Dev::setFrequency(double freq)
{
DEBUG << "V4L2Dev::setFrequency(): " << freq << "Hz" << endl;
if(_currentTuner == -1) {
return false;
}
struct v4l2_frequency desc;
memset(&desc, 0, sizeof(desc));
desc.tuner = _currentTuner;
desc.type = (v4l2_tuner_type)_currentTunerType;
desc.frequency = (__u32)(freq / _frequencyScale);
if(xioctl(VIDIOC_S_FREQUENCY, &desc)) {
return frequency();
} else {
return 0;
}
}
int V4L2Dev::signal() const
{
if(_currentTuner == -1) {
return -1;
}
struct v4l2_tuner desc;
memset(&desc, 0, sizeof(desc));
desc.index = _currentTuner;
if(xioctl(VIDIOC_G_TUNER, &desc)) {
DEBUG << "V4L2Dev::signal(): " << desc.signal << endl;
return desc.signal;
} else {
return -1;
}
}
// -----------------------------------------------------------------------
bool V4L2Dev::startStreaming(unsigned int numBuffers)
{
DEBUG << "V4L2Dev::startStreaming()" << endl;
if(_streaming) {
return true;
}
if((0 == _streamingBufferCount) && (0 == setupStreaming(numBuffers))) {
return false;
}
for(unsigned int i=0; i<_streamingBufferCount; i++) {
enqueueBuffer(i);
}
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
_streaming = xioctl(VIDIOC_STREAMON, &type);
return _streaming;
}
bool V4L2Dev::stopStreaming()
{
DEBUG << "V4L2Dev::stopStreaming()" << endl;
if(!_streaming) {
return true;
}
_streaming = false;
for(unsigned int i=0; i<_streamingBufferCount; i++) {
_streamingBuffers[i].queued = false;
}
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(VIDIOC_STREAMOFF, &type);
cleanup();
return true;
}
void V4L2Dev::cleanup()
{
DEBUG << "V4L2Dev::cleanup()" << endl;
if(_streaming) {
stopStreaming();
}
for(unsigned int i=0; i<_streamingBufferCount; i++) {
if(_streamingBuffers[i].mmapped) {
munmap(_streamingBuffers[i].start, _streamingBuffers[i].length);
} else {
free(_streamingBuffers[i].start);
}
}
_streamingBufferCount = 0;
}
int V4L2Dev::setupStreaming(unsigned int numBuffers)
{
DEBUG << "V4L2Dev::setupStreaming(): " << numBuffers << endl;
if(numBuffers > V4L2_MAX_STREAMING_BUFFERS) {
numBuffers = V4L2_MAX_STREAMING_BUFFERS;
}
if(_streamingBufferCount != 0) {
cleanup();
}
_streamingBufferCount = setupStreamingMMAP(numBuffers);
if(_streamingBufferCount == 0) {
_streamingBufferCount = setupStreamingUser(numBuffers);
}
return _streamingBufferCount;
}
int V4L2Dev::setupStreamingMMAP(unsigned int numBuffers)
{
struct v4l2_requestbuffers desc;
memset(&desc, 0, sizeof(desc));
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
desc.memory = V4L2_MEMORY_MMAP;
desc.count = numBuffers;
if(xioctl(VIDIOC_REQBUFS, &desc)) {
if (desc.count == 0) {
kdWarning() << "V4L2Dev::setupStreamingMMAP(): driver failed to allocate buffers." << endl;
return 0;
}
kdDebug() << "V4L2Dev::setupStreamingMMAP(): driver allocated " << desc.count << " mmapped buffers." << endl;
for(_streamingBufferCount=0; _streamingBufferCount<desc.count; _streamingBufferCount++) {
struct v4l2_buffer bdesc;
memset(&bdesc, 0, sizeof(bdesc));
bdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bdesc.index = _streamingBufferCount;
if(xioctl(VIDIOC_QUERYBUF, &bdesc)) {
_streamingBuffers[_streamingBufferCount].queued = false;
_streamingBuffers[_streamingBufferCount].mmapped = true;
_streamingBuffers[_streamingBufferCount].length = bdesc.length;
_streamingBuffers[_streamingBufferCount].start = mmap(NULL, bdesc.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
_fd, bdesc.m.offset);
if (_streamingBuffers[_streamingBufferCount].start == MAP_FAILED) {
cleanup();
return 0;
}
} else {
cleanup();
return 0;
}
}
_streamtype = V4L2_MEMORY_MMAP;
return _streamingBufferCount;
}
kdWarning() << "V4L2Dev::setupStreamingMMAP(): driver cannot handle mmap buffers." << endl;
return 0;
}
int V4L2Dev::setupStreamingUser(unsigned int numBuffers)
{
DEBUG << "V4L2Dev::setupStreamingUser(): " << numBuffers << endl;
struct v4l2_requestbuffers desc;
memset(&desc, 0, sizeof(desc));
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
desc.memory = V4L2_MEMORY_USERPTR;
desc.count = numBuffers;
QSize sz = inputSize();
int bufSize = sz.width() * sz.height() * bytesppForFormat(inputFormat());
if(xioctl(VIDIOC_REQBUFS, &desc) && (desc.count != 0)) {
kdDebug() << "V4L2Dev::setupStreamingUser(): driver supports " << desc.count << " user buffers." << endl;
for(_streamingBufferCount=0; _streamingBufferCount<numBuffers; _streamingBufferCount++) {
_streamingBuffers[_streamingBufferCount].queued = false;
_streamingBuffers[_streamingBufferCount].mmapped = false;
_streamingBuffers[_streamingBufferCount].start = malloc(bufSize);
_streamingBuffers[_streamingBufferCount].length = bufSize;
}
_streamtype = V4L2_MEMORY_USERPTR;
return numBuffers;
}
kdWarning() << "V4L2Dev::setupStreamingUser(): driver cannot handle user buffers." << endl;
return 0;
}
const unsigned char* V4L2Dev::getStreamingBuffer(unsigned int id) const
{
return (const unsigned char*)_streamingBuffers[id].start;
}
bool V4L2Dev::enqueueBuffer(unsigned int id)
{
if(id > _streamingBufferCount) {
kdWarning() << "V4L2Dev::enqueueBuffer(): broken id: " << id << endl;
return false;
}
if(_streamingBuffers[id].queued) {
kdWarning() << "V4L2Dev::enqueueBuffer(): buffer already queued: " << id << endl;
return false;
}
struct v4l2_buffer desc;
memset(&desc, 0, sizeof(desc));
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
desc.index = id;
if(_streamingBuffers[id].mmapped) {
desc.memory = V4L2_MEMORY_MMAP;
} else {
desc.memory = V4L2_MEMORY_USERPTR;
desc.m.userptr = (unsigned long)_streamingBuffers[id].start;
desc.length = _streamingBuffers[id].length;
}
if(xioctl(VIDIOC_QBUF, &desc)) {
_streamingBuffers[id].queued = true;
return true;
} else {
_streamingBuffers[id].queued = false;
return false;
}
}
bool V4L2Dev::waitBuffer(unsigned int* id)
{
struct v4l2_buffer desc;
memset(&desc, 0, sizeof(desc));
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
desc.memory = (v4l2_memory)_streamtype;
if(xioctl(VIDIOC_DQBUF, &desc)) {
if(desc.index > _streamingBufferCount) {
kdWarning() << "V4L2Dev::dequeueBuffer(): dequeued broken index: " << id << endl;
return false;
}
*id = desc.index;
_streamingBuffers[desc.index].queued = false;
// printBuffer(desc);
return true;
} else {
if(errno == EIO) {
kdWarning() << "IO error - requeuing buffer" << endl;
*id = desc.index;
_streamingBuffers[desc.index].queued = false;
enqueueBuffer(*id);
}
return false;
}
}
// -----------------------------------------------------------------------
QSize V4L2Dev::snapshot(unsigned char* buf, const QSize& desiredSize, QVideo::ImageFormat format)
{
stopStreaming();
if(_supportsReadWrite) {
QSize sz = setInputProperties(format, desiredSize);
if(sz.isValid()) {
ssize_t count = ::read(_fd, buf,
sz.width() * sz.height() * QVideo::bytesppForFormat(format));
kdDebug() << "V4LDev2::snapshot(): Grab returned " << count << " bytes." << endl;
if(count > 0) {
return sz;
} else {
kdWarning() << "V4L2Dev::snapshot(): error: read() returned: " << strerror(errno) << endl;
}
}
} else {
kdWarning() << "V4L2Dev::snapshot(): error: device does not support read()" << endl;
}
return QSize();
}
// -----------------------------------------------------------------------
bool V4L2Dev::xioctl(int cmd, void* buf, int mayFail) const
{
static const char* v4l2ioctls[] = {
"VIDIOC_QUERYCAP",
"VIDIOC_RESERVED",
"VIDIOC_ENUM_FMT", "", "VIDIOC_G_FMT", "VIDIOC_S_FMT",
"VIDIOC_G_COMP", "VIDIOC_S_COMP",
"VIDIOC_REQBUFS", "VIDIOC_QUERYBUF", "VIDIOC_G_FBUF", "VIDIOC_S_FBUF",
"", "",
"VIDIOC_OVERLAY",
"VIDIOC_QBUF", "", "VIDIOC_DQBUF", "VIDIOC_STREAMON", "VIDIOC_STREAMOFF",
"",
"VIDIOC_G_PARM", "VIDIOC_S_PARM",
"VIDIOC_G_STD", "VIDIOC_S_STD", "VIDIOC_ENUMSTD",
"VIDIOC_ENUMINPUT",
"VIDIOC_G_CTRL", "VIDIOC_S_CTRL",
"VIDIOC_G_TUNER", "VIDIOC_S_TUNER",
"", "",
"VIDIOC_G_AUDIO", "VIDIOC_S_AUDIO", "",
"VIDIOC_QUERYCTRL", "VIDIOC_QUERYMENU",
"VIDIOC_G_INPUT", "VIDIOC_S_INPUT",
"", "", "", "", "", "",
"VIDIOC_G_OUTPUT", "VIDIOC_S_OUTPUT", "VIDIOC_ENUMOUTPUT",
"VIDIOC_G_AUDOUT", "VIDIOC_S_AUDOUT",
"", "", "",
"VIDIOC_G_MODULATOR", "VIDIOC_S_MODULATOR",
"VIDIOC_G_FREQUENCY", "VIDIOC_S_FREQUENCY",
"VIDIOC_CROPCAP", "VIDIOC_G_CROP", "VIDIOC_S_CROP",
"VIDIOC_G_JPEGCOMP", "VIDIOC_S_JPEGCOMP",
"VIDIOC_QUERYSTD",
"VIDIOC_TRY_FMT",
"VIDIOC_ENUMAUDIO", "VIDIOC_ENUMAUDOUT",
"VIDIOC_G_PRIORITY", "VIDIOC_S_PRIORITY"
};
int rc = ::ioctl(_fd, cmd, buf);
if( (rc < 0) && (errno != mayFail)) {
kdWarning() << "V4L2Dev: " << v4l2ioctls[_IOC_NR(cmd)] << " failed: " << strerror(errno) << endl;
} else {
// DEBUG << "V4L2Dev: " << v4l2ioctls[_IOC_NR(cmd)] << " ok. (" << rc << ")" << endl;
}
return (rc >= 0);
}
#if 0
static void printBuffer(struct v4l2_buffer& desc)
{
switch(desc.type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
DEBUG << " type: capture buffer" << endl;
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
DEBUG << " type: overlay buffer" << endl;
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
DEBUG << " type: output buffer" << endl;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
DEBUG << " type: vbi capture buffer" << endl;
break;
case V4L2_BUF_TYPE_VBI_OUTPUT:
DEBUG << " type: vbi output buffer" << endl;
break;
default:
DEBUG << " type: unknown" << endl;
break;
}
switch(desc.field) {
case V4L2_FIELD_ANY:
DEBUG << " field: any" << endl;
break;
case V4L2_FIELD_NONE:
DEBUG << " field: none" << endl;
break;
case V4L2_FIELD_TOP:
DEBUG << " field: top" << endl;
break;
case V4L2_FIELD_BOTTOM:
DEBUG << " field: bottom" << endl;
break;
case V4L2_FIELD_INTERLACED:
DEBUG << " field: interlaced" << endl;
break;
case V4L2_FIELD_SEQ_TB:
DEBUG << " field: seq tb" << endl;
break;
case V4L2_FIELD_SEQ_BT:
DEBUG << " field: seq bt" << endl;
break;
case V4L2_FIELD_ALTERNATE:
DEBUG << " field: alternate" << endl;
break;
default:
DEBUG << " field: unknown" << endl;
break;
}
DEBUG << " bytes: " << desc.bytesused << endl;
DEBUG << " sequence: " << desc.sequence << endl;
DEBUG << " mapped: " << (desc.flags & V4L2_BUF_FLAG_MAPPED) << endl;
DEBUG << " queued: " << (desc.flags & V4L2_BUF_FLAG_QUEUED) << endl;
DEBUG << " done: " << (desc.flags & V4L2_BUF_FLAG_DONE) << endl;
DEBUG << " keyframe: " << (desc.flags & V4L2_BUF_FLAG_KEYFRAME) << endl;
DEBUG << " pframe: " << (desc.flags & V4L2_BUF_FLAG_PFRAME) << endl;
DEBUG << " bframe: " << (desc.flags & V4L2_BUF_FLAG_BFRAME) << endl;
DEBUG << " timecode: " << (desc.flags & V4L2_BUF_FLAG_TIMECODE) << endl;
}
#endif
// -----------------------------------------------------------------------
V4L2Dev::ControlType V4L2Dev::translateV4L2ControlType(int t)
{
switch(t) {
case V4L2_CTRL_TYPE_INTEGER:
return ControlType_Int;
case V4L2_CTRL_TYPE_BOOLEAN:
return ControlType_Boolean;
case V4L2_CTRL_TYPE_MENU:
return ControlType_Menu;
case V4L2_CTRL_TYPE_BUTTON:
return ControlType_Button;
default:
kdWarning() << "V4LDev::translateV4L2ControlType(): unknown control type: " << t << endl;
return ControlType_Int;
}
}
// -----------------------------------------------------------------------
unsigned int V4L2Dev::qvideoformat2v4l2format(ImageFormat f)
{
if(f & FORMAT_GREY) {
return V4L2_PIX_FMT_GREY;
}
if(f & FORMAT_HI240) {
return V4L2_PIX_FMT_HI240;
}
if(f & FORMAT_RGB15_LE) {
return V4L2_PIX_FMT_RGB555;
}
if(f & FORMAT_RGB15_BE) {
return V4L2_PIX_FMT_RGB555X;
}
if(f & FORMAT_RGB16_LE) {
return V4L2_PIX_FMT_RGB565;
}
if(f & FORMAT_RGB16_BE) {
return V4L2_PIX_FMT_RGB565X;
}
if(f & FORMAT_RGB24) {
return V4L2_PIX_FMT_RGB24;
}
if(f & FORMAT_RGB32) {
return V4L2_PIX_FMT_RGB32;
}
if(f & FORMAT_BGR24) {
return V4L2_PIX_FMT_BGR24;
}
if(f & FORMAT_BGR32) {
return V4L2_PIX_FMT_BGR32;
}
if(f & FORMAT_YUYV) {
return V4L2_PIX_FMT_YUYV;
}
if(f & FORMAT_UYVY) {
return V4L2_PIX_FMT_UYVY;
}
if(f & FORMAT_YUV422P) {
return V4L2_PIX_FMT_YUV422P;
}
if(f & FORMAT_YUV420P) {
return V4L2_PIX_FMT_YUV420;
}
kdWarning() << "V4LDev: Unable to figure out a grab format for the desired QImageFormat: " << f << endl;
return V4L2_PIX_FMT_YUYV;
}
QVideo::ImageFormat V4L2Dev::v4l2format2qvideoformat(unsigned int f)
{
if(f == V4L2_PIX_FMT_GREY) {
return FORMAT_GREY;
}
if(f == V4L2_PIX_FMT_HI240) {
return FORMAT_HI240;
}
if(f == V4L2_PIX_FMT_YUYV) {
return FORMAT_YUYV;
}
if(f == V4L2_PIX_FMT_UYVY) {
return FORMAT_UYVY;
}
if(f == V4L2_PIX_FMT_YUV420) {
return FORMAT_YUV420P;
}
if(f == V4L2_PIX_FMT_YUV422P) {
return FORMAT_YUV422P;
}
if(f == V4L2_PIX_FMT_RGB32) {
return FORMAT_RGB32;
}
if(f == V4L2_PIX_FMT_BGR32) {
return FORMAT_BGR32;
}
if(f == V4L2_PIX_FMT_RGB24) {
return FORMAT_RGB24;
}
if(f == V4L2_PIX_FMT_BGR24) {
return FORMAT_BGR24;
}
if(f == V4L2_PIX_FMT_RGB555) {
return FORMAT_RGB15_LE;
}
if(f == V4L2_PIX_FMT_RGB555X) {
return FORMAT_RGB15_BE;
}
if(f == V4L2_PIX_FMT_RGB565) {
return FORMAT_RGB16_LE;
}
if(f == V4L2_PIX_FMT_RGB565X) {
return FORMAT_RGB16_BE;
}
return FORMAT_NONE;
}