Re: Problems with cx88xx

Dirk Ziegelmeier <[email protected]>
Newsgroups gmane.comp.kde.kwintv
Message-ID <[email protected]>
On Wednesday 15 September 2004 23:26, Christoph Brill wrote:
> Find attached the complete strace in bzip2ed textfile. It was generated
> with the command "strace kdetv 2> strace-kdetv-2004-09-15". When kdetv
> hang, I pressed CTRL+C
OK, please try it with the attached file (kvideoio/v4ldev.cpp) and tell me if 
it works. If not, send me a "strace" again.

Dirk

_______________________________________________
kwintv mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/kwintv
v4ldev.cpp (text/x-c++src, 24.1 KB)
/*
 * Copyright (C) 2002-2003 George Staikos <[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.
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <endian.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/mman.h>
#include <assert.h>
#include <signal.h>

#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
#define _LINUX_TIME_H
#define _DEVICE_H_
#include <linux/videodev.h>

#include <qimage.h>
#include <kdebug.h>
#include <kprocess.h>

#include "v4ldev.h"
#include "v4ldevtuner.h"
#include "v4ldevcamera.h"

#include <sys/time.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>

/* FIXME:
 *     - Colourspaces are not done.
 */

///////////////////////////////////////////////////////////////////////////////////////
// SIGALM signal handler
///////////////////////////////////////////////////////////////////////////////////////

static int _sigs = 0;

static void sigalarm(int)
{
    _sigs++;
    fprintf(stderr, "v4ldev: V4L timeout %d\n");
}

class V4LSigInit
{
public:
    V4LSigInit()
    {
        kdDebug() << "V4LDev: Installing SIGALARM handler." << endl;
        _old = signal(SIGALRM, sigalarm);
    }

    ~V4LSigInit()
    {
        kdDebug() << "V4LDev: Uninstalling SIGALARM handler." << endl;
        signal(SIGALRM, _old);
    }

    void (*_old)(int);
};

static V4LSigInit _initSignals;

///////////////////////////////////////////////////////////////////////////////////////
// Device factory
///////////////////////////////////////////////////////////////////////////////////////

V4LDev* V4LDev::getDevice( const QString &dev )
{
    int rc;
    int fd = ::open(dev.local8Bit(), O_RDWR);
    if (fd < 0)
        return NULL;

    /* get the capture properties */
    struct video_capability vcap;
    memset(&vcap, 0, sizeof(vcap));
    rc = ioctl(fd, VIDIOCGCAP, &vcap);
    if (rc < 0) {
        ::close(fd);
        return NULL;
    }

    kdDebug() << "v4ldev: Grabber Name: " << vcap.name << endl;
    kdDebug() << "Type: " << vcap.type << endl;
    kdDebug() << "Input Channels: " << vcap.channels << endl;
    kdDebug() << "minw=" << vcap.minwidth << ", minh=" << vcap.minheight
              << ", maxw=" << vcap.maxwidth << ", maxh=" << vcap.maxheight << endl;

    if (vcap.type&VID_TYPE_CAPTURE) {
        kdDebug() << "  Supports: capture to memory" << endl;
    }
    if (vcap.type&VID_TYPE_OVERLAY) {
        kdDebug() << "  Supports: video overlay" << endl;
    }
    if (vcap.type&VID_TYPE_CLIPPING) {
        kdDebug() << "  Supports: clipping" << endl;
    }
    if (vcap.type&VID_TYPE_CHROMAKEY) {
        kdDebug() << "  Requires: chromakey" << endl;
    }
    if (vcap.type&VID_TYPE_SCALES) {
        kdDebug() << "  Supports: scaling" << endl;
    }
    if (vcap.type&VID_TYPE_FRAMERAM) {
        kdDebug() << "  Requires: overwriting frame buffer" << endl;
    }
    if (vcap.type&VID_TYPE_SUBCAPTURE) {
        kdDebug() << "  Supports: capture of parts to memory" << endl;
    }

    if (vcap.type&VID_TYPE_OVERLAY) {
        // v4l1 does not support multiple fd opening
        ::close(fd);

        kdDebug() << "v4ldev: The device supports overlay. Running kv4lsetup." << endl;

        KProcess p;
        p.setUseShell(true);
        p << "kv4lsetup" << "-c" << dev;
        // p << "-l" << "-b" << QString::number(QPaintDevice::x11AppDepth());
        // FIXME: configure shift
        // p << "-s" << QString::number(shift);
        p.start(KProcess::Block);

        if (p.exitStatus() != 0) {
            kdWarning() << "v4ldev: kv4lsetup had some trouble. Trying to continue anyway." << endl;
        }

        // reopen device
        fd = ::open(dev.local8Bit(), O_RDWR);
        if (fd < 0)
            return NULL;
    }

    V4LDev *nd = NULL;
    if (vcap.type & VID_TYPE_TUNER) {   /* it must be a TV tuner */
    nd = new V4LTuner(fd, vcap.name, vcap.channels, vcap.type,
                      vcap.minwidth, vcap.minheight,
                      vcap.maxwidth, vcap.maxheight);
    /* see if it's a camera */
    } else if (vcap.channels == 1) {  // hack for now   FIXME
        nd =  new V4LCamera(fd, vcap.name, vcap.channels,
                            vcap.type, vcap.minwidth, vcap.minheight,
                            vcap.maxwidth, vcap.maxheight);
    } else {
        ::close(fd);
    }

    return nd;
}

///////////////////////////////////////////////////////////////////////////////////////
// Constructor / destructor
///////////////////////////////////////////////////////////////////////////////////////

V4LDev::V4LDev(int fd, const QString &name, int channels, int type, int minw, int minh, int maxw, int maxh)
    : _fd(fd),
      _name(name),
      _minWidth(minw),
      _minHeight(minh),
      _maxWidth(maxw),
      _maxHeight(maxh),
      _type(type)
{
    int rc;

    _source = 0;
    _sources.clear();
    _encoding = QString::null;
    _encodings.clear();

    _isTuner = false;
    _isCamera = false;

    _aspectRatio = (float)maxw/(float)maxh;
    _overlaid = false;

    int displayrc, bitspp, depth;
    displayrc = findDisplayProperties(_qvideofmt, depth, bitspp, _bpp);
    _v4lfmt = qvideoformat2v4lformat(_qvideofmt);

    _mmapBuf = 0;
    _readBuf = 0;
    _mmapCurrentFrame = 0;
    _grabNeedsInit = true;
    _mmapData = 0;
    _grabW = maxw;
    _grabH = maxh;
    _mbuf = new struct video_mbuf;
    _cliprecs = new struct video_clip[MAX_CLIP_RECTS];

    setImageSize(maxw, maxh);

    /* Get the channels */
    _channels = new video_channel[channels];
    memset(_channels, 0, sizeof(_channels));

    for (int i = 0; i < channels; i++) {
        _channels[i].channel = i;
        rc = ioctl(_fd, VIDIOCGCHAN, &_channels[i]);
        if (rc >= 0) {
            _sources << QString(_channels[i].name).lower();

            /**** DEBUG ****/
            kdDebug() << "v4ldev: Channel " << i+1 << ": " << _channels[i].name << endl;

            QString type;
            if ( _channels[i].type & VIDEO_TYPE_TV )
                type = "TV";
            else if ( _channels[i].type & VIDEO_TYPE_CAMERA )
                type = "Camera";
            else
                type ="Unknown Type";

            QString msg( "%1" );
            if  ( _channels[i].flags & VIDEO_VC_TUNER )
                msg = msg + QString(" - tuner(%1) ").arg(_channels[i].tuners);
            if ( _channels[i].flags & VIDEO_VC_AUDIO )
                msg = msg + " - audio ";

            kdDebug() << msg.arg(type) << endl;
            /**** END DEBUG ****/
        }
    }

    // Overlay stuff
    _disableOverlay = true;
    if (_type&VID_TYPE_OVERLAY) {
        struct video_buffer vb;
        memset(&vb, 0, sizeof(vb));
        rc = ioctl(_fd, VIDIOCGFBUF, &vb);
        if (rc < 0) {
            kdDebug() << "v4ldev: Unable to get frame buffer info from v4l. Overlay disabled." << endl;
            return;
        }

        if (!displayrc) {
            kdDebug() << "v4ldev: Unable to figure out display properties. Overlay disabled." << endl;
            return;
        }

        /* bttv confuses color depth and bits/pixel */
        if (depth == 15) {
            bitspp = 15;
        }

        if (vb.depth != bitspp) {
            kdDebug() << "v4ldev: V4L and KVIDEOIO disagree about the depth of the "
                      << "display. Is kv4lsetup installed suid root? Overlay disabled." << endl;
            kdDebug() << "(I think it should be " << bitspp << ", v4l says: " << vb.depth << ")" << endl;
            return;
        }

        struct video_picture vp;
        memset(&vp, 0, sizeof(vp));
        rc = ioctl(_fd, VIDIOCGPICT, &vp);
        if (rc >= 0) {
            vp.palette = _v4lfmt;
            vp.depth   = bitspp;
            rc = ioctl(_fd, VIDIOCSPICT, &vp);
            if (rc < 0) {
                kdDebug() << "v4ldev: VIDIOCSPICT failed: " << rc << ". Overlay disabled." << endl;
                return;
            }
        }

        _disableOverlay = false;
        kdDebug() << "v4ldev: Overlay video display is possible." << endl;
    }
}

V4LDev::~V4LDev()
{
    delete[] _channels;
    int zero = 0;

    if (_mmapBuf)
        munmap(_mmapBuf, _mbuf->size);

    delete[] _readBuf;
    delete[] _mmapData;
    delete[] _mbuf;
    delete[] _cliprecs;

    ioctl(_fd, VIDIOCCAPTURE, &zero);
    ::close(_fd);
}

///////////////////////////////////////////////////////////////////////////////////////
// Video Source
///////////////////////////////////////////////////////////////////////////////////////

int V4LDev::setSource(const QString &source)
{
    kdDebug() << "V4LDev::setSource(..) Source is " << source << endl;

//    syncCurrentFrame();

    // Empty source means don't touch
    if (source.isEmpty()) return 0;

    int idx = _sources.findIndex(source);

    if (idx < 0) return -1;

    struct video_channel vc;

    memset(&vc, 0, sizeof(vc));
    vc.channel = idx;

    int rc = ioctl(_fd, VIDIOCGCHAN, &vc);
    if (rc < 0)
        return -1;

    rc = ioctl(_fd, VIDIOCSCHAN, &vc);
    if (rc < 0) {
        kdDebug() << "v4ldev: Error setting source to " << idx << endl;
    }

    _source = idx;
    return 0;
}

///////////////////////////////////////////////////////////////////////////////////////
// Grabbing
///////////////////////////////////////////////////////////////////////////////////////

bool V4LDev::canGrab() const
{
    if (_type&VID_TYPE_CAPTURE)
        return true;
    return false;
}

int V4LDev::initGrabbing()
{
    if (_mmapBuf) {
        munmap(_mmapBuf, _mbuf->size);
        _mmapBuf = 0;
    }

    if (_mmapData) {
        delete[] _mmapData;
        _mmapData = 0;
    }

    _mmapCurrentFrame = 0;

    if (_type & VID_TYPE_CAPTURE) {
        int rc = ioctl(_fd, VIDIOCGMBUF, _mbuf);
        if (rc == 0) {
            void *rc2 = mmap(0, _mbuf->size, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, 0);
            if ((long)rc2 != -1 && rc2 != 0) {
                _mmapBuf = static_cast<uchar*>(rc2);
            } else {
                kdDebug() << "v4ldev: MMAP error." << endl;
                return -1;
            }
        } else {
            return -1;
        }

        _mmapData = new struct video_mmap[_mbuf->frames];
        memset(_mmapData, 0, _mbuf->frames*sizeof(struct video_mmap));
        for (int i = 0; i < _mbuf->frames; i++) {
            _mmapData[i].width  = _grabW;
            _mmapData[i].height = _grabH;
            _mmapData[i].frame  = i;
            _mmapData[i].format = _v4lfmt;
        }

        rc = ioctl(_fd, VIDIOCMCAPTURE, _mmapData);
        if (rc != 0) {
            fprintf(stderr, "v4ldev: VIDIOCMCAPTURE failed. Format may not be supported by grabber.\n");
            return -1;
        }
    }
    _grabNeedsInit = false;

    return 0;
}

bool V4LDev::setInputFormat(ImageFormat fmt)
{
//    syncCurrentFrame();

    int ig = bytesppForFormat(fmt);
    if (ig < 0) {
        _qvideofmt = FORMAT_NONE;
        _v4lfmt = VIDEO_PALETTE_YUV422;
        return FORMAT_NONE;
    }

    _bpp = ig;
    _qvideofmt = fmt;
    _v4lfmt = qvideoformat2v4lformat(fmt);
    return (initGrabbing() == 0);
}

QVideo::ImageFormat V4LDev::inputFormat() const
{
    return _qvideofmt;
}

void V4LDev::syncCurrentFrame() const
{
    if (_mmapBuf) {
        while (ioctl(_fd, VIDIOCSYNC, &_mmapCurrentFrame) == -1
               && errno == EINTR)
            ;
    }
}

QSize V4LDev::grab(unsigned char* img)
{
    if (_grabNeedsInit) {
        initGrabbing();
    }

    if (_mmapBuf) {  ////////////////////////////////////   mmap() method
        int rc;
        int nextFrame = (_mmapCurrentFrame+1) % _mbuf->frames;

        rc = ioctl(_fd, VIDIOCMCAPTURE, &(_mmapData[nextFrame]));
        if (rc != 0) {
            fprintf(stderr, "v4ldev: VIDIOCMCAPTURE failed.\n");
            if (errno == EBUSY) {
                // on EBUSY, somehow the frame is busy.  This should never
                // happen as far as I know.  Hack: try to release the frame.
                rc = ioctl(_fd, VIDIOCSYNC, &nextFrame);
                if (rc != 0) {
                    fprintf(stderr, "v4ldev: VIDIOCSYNC failed too.\n");
                }
            }
            return QSize();
        }

//        syncCurrentFrame();

        if (img) {
            memcpy(img, _mmapBuf + _mbuf->offsets[_mmapCurrentFrame], _grabW*_grabH*_bpp);
        }

        _mmapCurrentFrame = nextFrame;
        if (rc != 0) {
            fprintf(stderr, "v4ldev::grab(): VIDIOCSYNC failed.\n");
        }
    } else {  /////////////////////////////////////////   read() method
        if (!img) {
            int sz = _grabW*_grabH*_bpp;
            if (!_readBuf)
                _readBuf = new uchar[sz];
            int rc = read(_fd, _readBuf, sz);
            if (rc != sz) {
                fprintf(stderr, "v4ldev::grab() [mmap]: error: wanted %d, got rc = %d\n", sz, rc);

                return QSize();
            }
        } else {
            int sz = _grabW*_grabH*_bpp;

            int rc = read(_fd, img, sz);
            if (rc != sz) {
                fprintf(stderr, "v4ldev::grab() [read]: error: wanted %d, got rc = %d\n", sz, rc);
                return QSize();
            }
        }
    }

    return QSize(_grabW, _grabH);
}

int V4LDev::setImageSize(int w, int h)
{
//    syncCurrentFrame();

    if (w < _minWidth)
        w = _minWidth;

    if (h >= 0 && h < _minHeight)
        h = _minHeight;

    if (w > _maxWidth)
        w = _maxWidth;

    if (h > _maxHeight)
        h = _maxHeight;

    if (h == -1) {
        h = int(w/_aspectRatio);
    }

    while (w%4 != 0 && w > _minWidth)
        w--;

    while (h%4 != 0 && h > _minHeight)
        h--;

    struct video_window vw;
    memset(&vw, 0, sizeof(vw));
    int rc = ioctl(_fd, VIDIOCGWIN, &vw);
    if (rc < 0)
        return -1;

    vw.width  = w;
    vw.height = h;
    vw.flags  = 0;
    if (_type&VID_TYPE_CHROMAKEY) {
        kdDebug() << "v4ldev: Enabling chromakey for V4L overlay." << endl;
        vw.flags |= VIDEO_WINDOW_CHROMAKEY;
    }
    rc = ioctl(_fd, VIDIOCSWIN, &vw);
    if (rc < 0)
        return -1;

    memset(&vw, 0, sizeof(vw));
    rc = ioctl(_fd, VIDIOCGWIN, &vw);
    if (rc < 0)
        return -1;

    if (vw.width != (unsigned)w || vw.height != (unsigned)h)
        return -1;

    if (_overlaid) {
        stopCapture();
        startCapture(vw.x, vw.y);
    }

    _grabW = w;
    _grabH = h;

    _grabNeedsInit = true;
    return 0;
}

///////////////////////////////////////////////////////////////////////////////////////
// Picture parameter accessors
///////////////////////////////////////////////////////////////////////////////////////

#define CreateParmFunc(X,Y)                 \
                                            \
int V4LDev::set##X(int x) {                 \
    struct video_picture vp;                \
                                            \
    memset(&vp, 0, sizeof(vp));             \
    int rc = ioctl(_fd, VIDIOCGPICT, &vp);  \
                                            \
    if (rc >= 0) {                          \
        vp.Y = x;                           \
        rc = ioctl(_fd, VIDIOCSPICT, &vp);  \
        if (rc < 0)                         \
            return -1;                      \
    } else return -1;                       \
                                            \
    return 0;                               \
}                                           \
                                            \
int V4LDev::Y() const {                     \
    struct video_picture vp;                \
                                            \
    memset(&vp, 0, sizeof(vp));             \
    int rc = ioctl(_fd, VIDIOCGPICT, &vp);  \
                                            \
    if (rc >= 0) {                          \
        return vp.Y;                        \
    }                                       \
                                            \
    return -1;                              \
}

CreateParmFunc(Brightness,brightness)
CreateParmFunc(Hue,hue)
CreateParmFunc(Colour,colour)
CreateParmFunc(Contrast,contrast)
CreateParmFunc(Whiteness,whiteness)

#undef CreateParmFunc


int V4LDev::setColourKey(unsigned long x)
{
//    syncCurrentFrame();

    struct video_window vw;
    memset(&vw, 0, sizeof(vw));
    int rc = ioctl(_fd, VIDIOCGWIN, &vw);
    if (rc < 0)
        return -1;
    vw.chromakey = x;
    vw.flags = 0;
    if (_type&VID_TYPE_CHROMAKEY) {
        kdDebug() << "v4ldev: Enabling chromakey for V4L overlay." << endl;
        vw.flags |= VIDEO_WINDOW_CHROMAKEY;
    }

    return ioctl(_fd, VIDIOCSWIN, &vw);
}


unsigned long V4LDev::colourKey() const
{
    struct video_window vw;

    memset(&vw, 0, sizeof(vw));
    int rc = ioctl(_fd, VIDIOCGWIN, &vw);
    if (rc < 0)
        return 0;

    return vw.chromakey;
}

///////////////////////////////////////////////////////////////////////////////////////
// Audio
///////////////////////////////////////////////////////////////////////////////////////

int V4LDev::enableAudio()
{
    int rc;
    struct video_audio va;

    memset(&va, 0, sizeof(va));
    rc = ioctl(_fd, VIDIOCGAUDIO, &va);

    if (rc < 0) {
        perror("v4ldev: VIDIOCGAUDIO");
        return -1;
    }

    va.flags &= ~VIDEO_AUDIO_MUTE;
    rc = ioctl(_fd, VIDIOCSAUDIO, &va);
    if (rc < 0) {
        perror("v4ldev: VIDIOCSAUDIO");
        return -1;
    }

    return 0;
}

bool V4LDev::audioEnabled() const
{
    int rc;
    struct video_audio va;

    memset(&va, 0, sizeof(va));
    rc = ioctl(_fd, VIDIOCGAUDIO, &va);

    if (rc < 0) {
        perror("v4ldev: VIDIOCGAUDIO");
        return false;
    }

    return (va.flags & VIDEO_AUDIO_MUTE);
}

int V4LDev::disableAudio()
{
    int rc;
    struct video_audio va;

    memset(&va, 0, sizeof(va));
    rc = ioctl(_fd, VIDIOCGAUDIO, &va);

    if (rc < 0) {
        perror("v4ldev: VIDIOCGAUDIO");
        return -1;
    }

    va.flags |= VIDEO_AUDIO_MUTE;
    rc = ioctl(_fd, VIDIOCSAUDIO, &va);
    if (rc < 0) {
        perror("v4ldev: VIDIOCSAUDIO");
        return -1;
    }

    return 0;
}

int V4LDev::setAudioMode(const QString& mode)
{
    if (!_audioMap.contains(mode)) return -1;

    int rc;
    struct video_audio va;

    memset(&va, 0, sizeof(va));
    rc = ioctl(_fd, VIDIOCGAUDIO, &va);

    if (rc < 0) {
        perror("v4ldev: VIDIOCGAUDIO");
        return -1;
    }

    va.mode = _audioMap[mode];
    rc = ioctl(_fd, VIDIOCSAUDIO, &va);
    if (rc < 0) {
        perror("v4ldev: VIDIOCSAUDIO");
        return -1;
    }

    return 0;
}

const QStringList& V4LDev::broadcastedAudioModes()
{
    _broadcastedAudioModes.clear();

    int rc;
    struct video_audio va;

    memset(&va, 0, sizeof(va));
    rc = ioctl(_fd, VIDIOCGAUDIO, &va);

    if (rc < 0) {
        perror("v4ldev: VIDIOCGAUDIO");
        return _broadcastedAudioModes;
    }

    for (QMapConstIterator<QString, int> it(_audioMap.begin());
         it != _audioMap.end();
         ++it) {
        if (it.data() & va.mode) {
            _broadcastedAudioModes.append(it.key());
        }
    }

    return _broadcastedAudioModes;
}

///////////////////////////////////////////////////////////////////////////////////////
// Overlay
///////////////////////////////////////////////////////////////////////////////////////

bool V4LDev::canOverlay() const
{
    if (_disableOverlay)
        return false;

    if (_type&VID_TYPE_OVERLAY)
        return true;

    return false;
}

bool V4LDev::overlayOn() const
{
    return _overlaid;
}


void V4LDev::addClip(const QRect& clip)
{
    if (_clips.count() < MAX_CLIP_RECTS)
        _clips.append(clip);
}

void V4LDev::clearClips()
{
    _clips.clear();
}

void V4LDev::reClip()
{
    struct video_window vw;
    memset(&vw, 0, sizeof(vw));
    int rc = ioctl(_fd, VIDIOCGWIN, &vw);

    if (rc == 0) {
        for (unsigned int i = 0; i < _clips.count(); i++) {
            _cliprecs[i].x = _clips[i].x() - vw.x;
            _cliprecs[i].y = _clips[i].y() - vw.y;
            _cliprecs[i].width = _clips[i].width();
            _cliprecs[i].height = _clips[i].height();
        }

        vw.clips = _cliprecs;
        vw.clipcount = _clips.count();
        vw.flags = 0;
        if (_type&VID_TYPE_CHROMAKEY) {
            kdDebug() << "Enabling chromakey for V4L overlay." << endl;
            vw.flags |= VIDEO_WINDOW_CHROMAKEY;
        }
        ioctl(_fd, VIDIOCSWIN, &vw);
        if (_overlaid) {
            int one = 1;
            ioctl(_fd, VIDIOCCAPTURE, &one);
        }
    }
}

int V4LDev::setCaptureGeometry(const QRect& geom)
{
    if (!canOverlay())
        return -1;

    struct video_window vw;

    memset(&vw, 0, sizeof(vw));
    int rc = ioctl(_fd, VIDIOCGWIN, &vw);
    if (rc < 0) {
        perror("v4ldev: VIDIOCGWIN");
        return -1;
    }

    vw.x = geom.x();
    vw.y = geom.y();
    vw.flags = 0;
    if (_type&VID_TYPE_CHROMAKEY) {
        vw.flags |= VIDEO_WINDOW_CHROMAKEY;
    }
    rc = ioctl(_fd, VIDIOCSWIN, &vw);
    if (rc < 0) {
        perror("v4ldev: VIDIOCSWIN");
        return -1;
    }

    return setImageSize(geom.width(), geom.height());
}

int V4LDev::startCapture(int x, int y)
{
    if (!canOverlay())
        return -1;

    if (_overlaid)
        return -1;

    int on = 1;

    struct video_window vw;
    memset(&vw, 0, sizeof(vw));
    int rc = ioctl(_fd, VIDIOCGWIN, &vw);
    if (rc < 0) {
        perror("VIDIOCGWIN");
        return -1;
    }

    vw.x = x;
    vw.y = y;
    vw.flags = 0;
    vw.width = _grabW;
    vw.height = _grabH;
    //kdDebug() << "x=" << x << " y=" << y << " w=" << vw.width << " h=" << vw.height << endl;
    vw.flags = 0;
    if (_type&VID_TYPE_CHROMAKEY) {
        kdDebug() << "v4ldev: Enabling chromakey for V4L overlay." << endl;
        vw.flags |= VIDEO_WINDOW_CHROMAKEY;
    }
    vw.clipcount = 0;
    rc = ioctl(_fd, VIDIOCSWIN, &vw);
    if (rc < 0) {
        perror("v4ldev: VIDIOCSWIN");
        return -1;
    }

    rc = ioctl(_fd, VIDIOCCAPTURE, &on);
    if (rc < 0) {
        perror("v4ldev: VIDIOCCAPTURE");
        return -1;
    }

    _overlaid = true;
    return 0;
}

int V4LDev::stopCapture()
{
    if (!_overlaid)
        return -1;

    int on = 0;

    int rc = ioctl(_fd, VIDIOCCAPTURE, &on);
    if (rc < 0) return -1;

    _overlaid = false;
    return 0;
}

///////////////////////////////////////////////////////////////////////////////////////
// Format conversion
///////////////////////////////////////////////////////////////////////////////////////

int V4LDev::qvideoformat2v4lformat(ImageFormat f)
{
    if(f & FORMAT_YUV422) {
        return VIDEO_PALETTE_YUV422;
    }
    if(f & FORMAT_RGB24) {
        return VIDEO_PALETTE_RGB24;
    }
    if(f & FORMAT_RGB32) {
        return VIDEO_PALETTE_RGB32;
    }
    if(f & FORMAT_RGB555) {
        return VIDEO_PALETTE_RGB555;
    }
    if(f & FORMAT_RGB565) {
        return VIDEO_PALETTE_RGB565;
    }
    if(f & FORMAT_YUYV) {
        return VIDEO_PALETTE_YUYV;
    }
    if(f & FORMAT_UYVY) {
        return VIDEO_PALETTE_UYVY;
    }
    if(f & FORMAT_YUV420) {
        return VIDEO_PALETTE_YUV420;
    }
    if(f & FORMAT_YUV411) {
        return VIDEO_PALETTE_YUV411;
    }
    if(f & FORMAT_YUV422P) {
        return VIDEO_PALETTE_YUV422P;
    }
    if(f & FORMAT_YUV411P) {
        return VIDEO_PALETTE_YUV411P;
    }
    if(f & FORMAT_YUV420P) {
        return VIDEO_PALETTE_YUV420P;
    }
    if(f & FORMAT_YUV410P) {
        return VIDEO_PALETTE_YUV410P;
    }
    if(f & FORMAT_GREY) {
        return VIDEO_PALETTE_GREY;
    }
    if(f & FORMAT_HI240) {
        return VIDEO_PALETTE_HI240;
    }

    kdDebug() << "V4LDev: Unable to figure out a grab format for the desired QImageFormat." << endl;
    return VIDEO_PALETTE_YUV422;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.