diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 19:17:32 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 19:17:32 +0000 |
commit | e38d2351b83fa65c66ccde443777647ef5cb6cff (patch) | |
tree | 1897fc20e9f73a81c520a5b9f76f8ed042124883 /src/barcode/barcode_v4l.cpp | |
download | tellico-e38d2351b83fa65c66ccde443777647ef5cb6cff.tar.gz tellico-e38d2351b83fa65c66ccde443777647ef5cb6cff.zip |
Added KDE3 version of Tellico
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/tellico@1097620 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/barcode/barcode_v4l.cpp')
-rw-r--r-- | src/barcode/barcode_v4l.cpp | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/src/barcode/barcode_v4l.cpp b/src/barcode/barcode_v4l.cpp new file mode 100644 index 0000000..f644fe1 --- /dev/null +++ b/src/barcode/barcode_v4l.cpp @@ -0,0 +1,538 @@ +/*************************************************************************** + copyright : (C) 2007 by Sebastian Held + email : sebastian.held@gmx.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of version 2 of the GNU General Public License as * + * published by the Free Software Foundation; * + * * + ***************************************************************************/ + +// uses code from xawtv: webcam.c (c) 1998-2002 Gerd Knorr + +//#include <stdio.h> +//#include <stdlib.h> +#include <fcntl.h> /* low-level i/o */ +//#include <unistd.h> +#include <errno.h> +//#include <malloc.h> +//#include <sys/stat.h> +//#include <sys/types.h> +//#include <sys/time.h> +//#include <sys/mman.h> +#include <sys/ioctl.h> +//#include <asm/types.h> /* for videodev2.h */ + +#include "barcode_v4l.h" +#include "../tellico_debug.h" + +using barcodeRecognition::ng_vid_driver; +using barcodeRecognition::ng_vid_driver_v4l; +using barcodeRecognition::barcode_v4l; +using barcodeRecognition::video_converter; + +QPtrList<barcodeRecognition::video_converter> barcodeRecognition::ng_vid_driver::m_converter; +const char *barcodeRecognition::device_cap[] = { "capture", "tuner", "teletext", "overlay", "chromakey", "clipping", "frameram", "scales", "monochrome", 0 }; +const unsigned int barcodeRecognition::ng_vfmt_to_depth[] = { + 0, /* unused */ + 8, /* RGB8 */ + 8, /* GRAY8 */ + 16, /* RGB15 LE */ + 16, /* RGB16 LE */ + 16, /* RGB15 BE */ + 16, /* RGB16 BE */ + 24, /* BGR24 */ + 32, /* BGR32 */ + 24, /* RGB24 */ + 32, /* RGB32 */ + 16, /* LUT2 */ + 32, /* LUT4 */ + 16, /* YUYV */ + 16, /* YUV422P */ + 12, /* YUV420P */ + 0, /* MJPEG */ + 0, /* JPEG */ + 16, /* UYVY */ +}; + +const char* barcodeRecognition::ng_vfmt_to_desc[] = { + "none", + "8 bit PseudoColor (dithering)", + "8 bit StaticGray", + "15 bit TrueColor (LE)", + "16 bit TrueColor (LE)", + "15 bit TrueColor (BE)", + "16 bit TrueColor (BE)", + "24 bit TrueColor (LE: bgr)", + "32 bit TrueColor (LE: bgr-)", + "24 bit TrueColor (BE: rgb)", + "32 bit TrueColor (BE: -rgb)", + "16 bit TrueColor (lut)", + "32 bit TrueColor (lut)", + "16 bit YUV 4:2:2 (packed, YUYV)", + "16 bit YUV 4:2:2 (planar)", + "12 bit YUV 4:2:0 (planar)", + "MJPEG (AVI)", + "JPEG (JFIF)", + "16 bit YUV 4:2:2 (packed, UYVY)", +}; + +unsigned int barcodeRecognition::ng_yuv_gray[256]; +unsigned int barcodeRecognition::ng_yuv_red[256]; +unsigned int barcodeRecognition::ng_yuv_blue[256]; +unsigned int barcodeRecognition::ng_yuv_g1[256]; +unsigned int barcodeRecognition::ng_yuv_g2[256]; +unsigned int barcodeRecognition::ng_clip[256 + 2 * CLIP]; + +void barcodeRecognition::ng_color_yuv2rgb_init() +{ + int i; +# define RED_NULL 128 +# define BLUE_NULL 128 +# define LUN_MUL 256 +# define RED_MUL 512 +# define BLUE_MUL 512 +#define GREEN1_MUL (-RED_MUL/2) +#define GREEN2_MUL (-BLUE_MUL/6) +#define RED_ADD (-RED_NULL * RED_MUL) +#define BLUE_ADD (-BLUE_NULL * BLUE_MUL) +#define GREEN1_ADD (-RED_ADD/2) +#define GREEN2_ADD (-BLUE_ADD/6) + + /* init Lookup tables */ + for (i = 0; i < 256; i++) { + barcodeRecognition::ng_yuv_gray[i] = i * LUN_MUL >> 8; + barcodeRecognition::ng_yuv_red[i] = (RED_ADD + i * RED_MUL) >> 8; + barcodeRecognition::ng_yuv_blue[i] = (BLUE_ADD + i * BLUE_MUL) >> 8; + barcodeRecognition::ng_yuv_g1[i] = (GREEN1_ADD + i * GREEN1_MUL) >> 8; + barcodeRecognition::ng_yuv_g2[i] = (GREEN2_ADD + i * GREEN2_MUL) >> 8; + } + for (i = 0; i < CLIP; i++) + barcodeRecognition::ng_clip[i] = 0; + for (; i < CLIP + 256; i++) + barcodeRecognition::ng_clip[i] = i - CLIP; + for (; i < 2 * CLIP + 256; i++) + barcodeRecognition::ng_clip[i] = 255; +} + + + + + + + + + + + +barcode_v4l::barcode_v4l() +{ + m_devname = "/dev/video0"; + m_grab_width = 640; + m_grab_height = 480; + m_drv = 0; + m_conv = 0; + + barcodeRecognition::ng_color_yuv2rgb_init(); + //ng_vid_driver::register_video_converter( new barcodeRecognition::yuv422p_to_rgb24() ); + //ng_vid_driver::register_video_converter( new barcodeRecognition::yuv422_to_rgb24() ); + ng_vid_driver::register_video_converter( new barcodeRecognition::yuv420p_to_rgb24() ); + + grab_init(); +} + +barcode_v4l::~barcode_v4l() +{ + if (m_drv) { + m_drv->close(); + delete m_drv; + } +} + +bool barcode_v4l::isOpen() +{ + return m_drv; +} + +QImage barcode_v4l::grab_one2() +{ + if (!m_drv) { + myDebug() << "no driver/device available" << endl; + return QImage(); + } + + QByteArray *cap; + if (!(cap = m_drv->getimage2())) { + myDebug() << "capturing image failed" << endl; + return QImage(); + } + + QByteArray *buf; + if (m_conv) { + buf = new QByteArray( 3*m_fmt.width*m_fmt.height ); + m_conv->frame( buf, cap, m_fmt_drv ); + } else { + buf = new QByteArray(*cap); + } + delete cap; + + int depth = 32; + QByteArray *buf2 = new QByteArray( depth/8 *m_fmt.width*m_fmt.height ); + for (uint i=0; i<m_fmt.width*m_fmt.height; i++) { + (*buf2)[i*4+0] = buf->at(i*3+2); + (*buf2)[i*4+1] = buf->at(i*3+1); + (*buf2)[i*4+2] = buf->at(i*3+0); + (*buf2)[i*4+3] = 0; + } + delete buf; + QImage *temp = new QImage( (uchar*)buf2->data(), m_fmt.width, m_fmt.height, depth, 0, 0, QImage::LittleEndian ); + QImage temp2 = temp->copy(); + delete temp; + delete buf2; + + return temp2; +} + + + + + + + +bool barcode_v4l::grab_init() +{ + m_drv = ng_vid_driver::createDriver( m_devname ); + if (!m_drv) { + myDebug() << "no grabber device available" << endl; + return false; + } + if (!(m_drv->capabilities() & CAN_CAPTURE)) { + myDebug() << "device doesn't support capture" << endl; + m_drv->close(); + delete m_drv; + m_drv = 0; + return false; + } + + /* try native */ + m_fmt.fmtid = VIDEO_RGB24; + m_fmt.width = m_grab_width; + m_fmt.height = m_grab_height; + if (m_drv->setformat( &m_fmt )) { + m_fmt_drv = m_fmt; + return true; + } + + /* check all available conversion functions */ + m_fmt.bytesperline = m_fmt.width * ng_vfmt_to_depth[m_fmt.fmtid] / 8; + for (int i = 0; i<VIDEO_FMT_COUNT; i++) { + video_converter *conv = ng_vid_driver::find_video_converter( VIDEO_RGB24, i ); + if (!conv) + continue; + + m_fmt_drv = m_fmt; + m_fmt_drv.fmtid = conv->fmtid_in(); + m_fmt_drv.bytesperline = 0; + if (m_drv->setformat( &m_fmt_drv )) { + m_fmt.width = m_fmt_drv.width; + m_fmt.height = m_fmt_drv.height; + m_conv = conv; + //m_conv->init( &m_fmt ); + return true; + } + } + + myDebug() << "can't get rgb24 data" << endl; + m_drv->close(); + delete m_drv; + m_drv = 0; + return false; +} + + +ng_vid_driver* ng_vid_driver::createDriver( QString device ) +{ + /* check all grabber drivers */ + ng_vid_driver *drv = new ng_vid_driver_v4l(); + if (!drv->open2( device )) { + myDebug() << "no v4l device found" << endl; + delete drv; + drv = 0; + } + + return drv; +} + +int ng_vid_driver::xioctl( int fd, int cmd, void *arg ) +{ + int rc; + + rc = ioctl(fd,cmd,arg); + if (rc == 0) + return 0; + //print_ioctl(stderr,ioctls_v4l1,PREFIX,cmd,arg); + qDebug( ": %s\n",(rc == 0) ? "ok" : strerror(errno) ); + return rc; +} + + + +void ng_vid_driver::register_video_converter( video_converter *conv ) +{ + if (!conv) + return; + + m_converter.append( conv ); +} + +video_converter *ng_vid_driver::find_video_converter( int out, int in ) +{ + video_converter *conv; + for (conv = m_converter.first(); conv; conv = m_converter.next() ) + if ((conv->fmtid_in() == in) && (conv->fmtid_out() == out)) + return conv; + return 0; +} + + + + + + + + + + + + + + + + + + +ng_vid_driver_v4l::ng_vid_driver_v4l() +{ + m_name = "v4l"; + m_drv = 0; + m_fd = -1; + + m_use_read = false; + + for (int i=0; i<VIDEO_FMT_COUNT; i++) + format2palette[i] = 0; + format2palette[VIDEO_RGB08] = VIDEO_PALETTE_HI240; + format2palette[VIDEO_GRAY] = VIDEO_PALETTE_GREY; + format2palette[VIDEO_RGB15_LE] = VIDEO_PALETTE_RGB555; + format2palette[VIDEO_RGB16_LE] = VIDEO_PALETTE_RGB565; + format2palette[VIDEO_BGR24] = VIDEO_PALETTE_RGB24; + format2palette[VIDEO_BGR32] = VIDEO_PALETTE_RGB32; + format2palette[VIDEO_YUYV] = VIDEO_PALETTE_YUV422; + format2palette[VIDEO_UYVY] = VIDEO_PALETTE_UYVY; + format2palette[VIDEO_YUV422P] = VIDEO_PALETTE_YUV422P; + format2palette[VIDEO_YUV420P] = VIDEO_PALETTE_YUV420P; +} + +bool ng_vid_driver_v4l::open2( QString device ) +{ + /* open device */ + if ((m_fd = ::open( device.latin1(), O_RDWR )) == -1) { + qDebug( "v4l: open %s: %s\n", device.latin1(), strerror(errno) ); + return false; + } + if (ioctl( m_fd, VIDIOCGCAP, &m_capability ) == -1) { + ::close( m_fd ); + return false; + } + +#ifdef Barcode_DEBUG + qDebug( "v4l: open: %s (%s)\n", device.latin1(), m_capability.name ); +#endif + + fcntl( m_fd, F_SETFD, FD_CLOEXEC ); // close on exit + +#ifdef Barcode_DEBUG + myDebug() << " capabilities: " << endl; + for (int i = 0; device_cap[i] != NULL; i++) + if (m_capability.type & (1 << i)) + qDebug( " %s", device_cap[i] ); + qDebug( " size : %dx%d => %dx%d", m_capability.minwidth, m_capability.minheight, m_capability.maxwidth, m_capability.maxheight ); +#endif + +#ifdef Barcode_DEBUG + fprintf(stderr," v4l: using read() for capture\n"); +#endif + m_use_read = true; + + return true; +} + +void ng_vid_driver_v4l::close() +{ +#ifdef Barcode_DEBUG + fprintf(stderr, "v4l: close\n"); +#endif + + if (m_fd != -1) + ::close(m_fd); + m_fd = -1; + return; +} + +int ng_vid_driver_v4l::capabilities() +{ + int ret = 0; + + if (m_capability.type & VID_TYPE_OVERLAY) + ret |= CAN_OVERLAY; + if (m_capability.type & VID_TYPE_CAPTURE) + ret |= CAN_CAPTURE; + if (m_capability.type & VID_TYPE_TUNER) + ret |= CAN_TUNE; + if (m_capability.type & VID_TYPE_CHROMAKEY) + ret |= NEEDS_CHROMAKEY; + return ret; +} + +bool ng_vid_driver_v4l::setformat( ng_video_fmt *fmt ) +{ + bool rc = false; + +#ifdef Barcode_DEBUG + fprintf(stderr,"v4l: setformat\n"); +#endif + if (m_use_read) { + rc = read_setformat( fmt ); + } else { + Q_ASSERT( false ); + } + + m_fmt = *fmt; + + return rc; +} + + + + + +bool ng_vid_driver_v4l::read_setformat( ng_video_fmt *fmt ) +{ + xioctl( m_fd, VIDIOCGCAP, &m_capability ); + if (fmt->width > static_cast<uint>(m_capability.maxwidth)) + fmt->width = m_capability.maxwidth; + if (fmt->height > static_cast<uint>(m_capability.maxheight)) + fmt->height = m_capability.maxheight; + fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8; + + xioctl( m_fd, VIDIOCGPICT, &m_pict ); + m_pict.depth = ng_vfmt_to_depth[fmt->fmtid]; + m_pict.palette = GETELEM(format2palette,fmt->fmtid,0); + m_pict.brightness = 20000; + if (-1 == xioctl( m_fd, VIDIOCSPICT, &m_pict )) + return false; + + xioctl( m_fd, VIDIOCGWIN, &m_win); + m_win.width = m_fmt.width; + m_win.height = m_fmt.height; + m_win.clipcount = 0; + if (-1 == xioctl( m_fd, VIDIOCSWIN, &m_win )) + return false; + + return true; +} + +QByteArray* ng_vid_driver_v4l::getimage2() +{ +#ifdef Barcode_DEBUG + myDebug() << "v4l: getimage2" << endl; +#endif + + return read_getframe2(); +} + + +QByteArray* ng_vid_driver_v4l::read_getframe2() +{ + QByteArray* buf; + int size; + + size = m_fmt.bytesperline * m_fmt.height; + buf = new QByteArray( size ); + if (size != read( m_fd, buf->data(), size )) { + delete( buf ); + return 0; + } + return buf; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#define GRAY(val) barcodeRecognition::ng_yuv_gray[val] +#define RED(gray,red) ng_clip[ CLIP + gray + barcodeRecognition::ng_yuv_red[red] ] +#define GREEN(gray,red,blue) ng_clip[ CLIP + gray + barcodeRecognition::ng_yuv_g1[red] + \ + barcodeRecognition::ng_yuv_g2[blue] ] +#define BLUE(gray,blue) ng_clip[ CLIP + gray + barcodeRecognition::ng_yuv_blue[blue] ] + +void barcodeRecognition::yuv420p_to_rgb24::frame( QByteArray *out, const QByteArray *in, const ng_video_fmt fmt ) +{ + unsigned char *y, *u, *v, *d; + unsigned char *us,*vs; + unsigned char *dp; + unsigned int i,j; + int gray; + + dp = (unsigned char*)out->data(); + y = (unsigned char*)in->data(); + u = y + fmt.width * fmt.height; + v = u + fmt.width * fmt.height / 4; + + for (i = 0; i < fmt.height; i++) { + d = dp; + us = u; vs = v; + for (j = 0; j < fmt.width; j+= 2) { + gray = GRAY(*y); + *(d++) = RED(gray,*v); + *(d++) = GREEN(gray,*v,*u); + *(d++) = BLUE(gray,*u); + y++; + gray = GRAY(*y); + *(d++) = RED(gray,*v); + *(d++) = GREEN(gray,*v,*u); + *(d++) = BLUE(gray,*u); + y++; u++; v++; + } + if (0 == (i % 2)) { + u = us; v = vs; + } + dp += 3*fmt.width; + } +} |