File indexing completed on 2024-05-12 16:45:35

0001 /***************************************************************************
0002     Copyright (C) 2007-2009 Sebastian Held <sebastian.held@gmx.de>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 // uses code from v4lgrab.c         (c) Linux Kernel 2.6.30
0026 
0027 #include "barcode_v4l.h"
0028 #include "../tellico_debug.h"
0029 
0030 #include <fcntl.h>              /* low-level i/o */
0031 #include <errno.h>
0032 #include <sys/ioctl.h>
0033 
0034 extern "C" {
0035 #include <libv4l1.h>
0036 }
0037 
0038 using barcodeRecognition::barcode_v4l;
0039 
0040 #define READ_VIDEO_PIXEL(buf, format, depth, r, g, b)                   \
0041 {                                                                       \
0042   switch (format)                                                 \
0043   {                                                               \
0044     case VIDEO_PALETTE_GREY:                                \
0045       switch (depth)                                  \
0046       {                                               \
0047         case 4:                                 \
0048         case 6:                                 \
0049         case 8:                                 \
0050           (r) = (g) = (b) = (*buf++ << 8);\
0051           break;                          \
0052                   \
0053         case 16:                                \
0054           (r) = (g) = (b) =               \
0055             *((unsigned short *) buf);      \
0056           buf += 2;                       \
0057           break;                          \
0058       }                                               \
0059       break;                                          \
0060                   \
0061                   \
0062     case VIDEO_PALETTE_RGB565:                              \
0063     {                                                       \
0064       unsigned short tmp = *(unsigned short *)buf;    \
0065       (r) = tmp&0xF800;                               \
0066       (g) = (tmp<<5)&0xFC00;                          \
0067       (b) = (tmp<<11)&0xF800;                         \
0068       buf += 2;                                       \
0069     }                                                       \
0070     break;                                                  \
0071                   \
0072     case VIDEO_PALETTE_RGB555:                              \
0073       (r) = (buf[0]&0xF8)<<8;                         \
0074       (g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8;    \
0075       (b) = ((buf[1] << 2 ) & 0xF8)<<8;               \
0076       buf += 2;                                       \
0077       break;                                          \
0078                   \
0079     case VIDEO_PALETTE_RGB24:                               \
0080       (r) = buf[0] << 8; (g) = buf[1] << 8;           \
0081       (b) = buf[2] << 8;                              \
0082       buf += 3;                                       \
0083       break;                                          \
0084                   \
0085     default:                                                \
0086       fprintf(stderr,                                 \
0087         "Format %d not yet supported\n",        \
0088         format);                                \
0089   }                                                               \
0090 }
0091 
0092 barcode_v4l::barcode_v4l()
0093 {
0094   m_devname = QStringLiteral("/dev/video0");
0095   m_grab_width = 640;
0096   m_grab_height = 480;
0097 
0098   m_fd = -1;
0099   m_buffer = nullptr;
0100   m_image = nullptr;
0101 
0102   grab_init();
0103 }
0104 
0105 barcode_v4l::~barcode_v4l()
0106 {
0107   if (m_fd >= 0)
0108     v4l1_close(m_fd);
0109   if (m_buffer)
0110     delete m_buffer;
0111   if (m_image)
0112     delete m_image;
0113 }
0114 
0115 bool barcode_v4l::isOpen()
0116 {
0117   return (m_fd >= 0);
0118 }
0119 
0120 QImage barcode_v4l::grab_one2()
0121 {
0122   unsigned int bpp = 24, x, y;
0123   unsigned int r = 0, g = 0, b = 0;
0124   unsigned int src_depth = 16;
0125   char *src = m_buffer->data();
0126 
0127   static int counter = 0; // adjustment disabled; set to e.g. 20 or 50 to enable the brightness adjustment
0128 
0129   if (!isOpen())
0130     return QImage();
0131 
0132   v4l1_read(m_fd, m_buffer->data(), m_win.width * m_win.height * bpp);
0133 
0134   if (counter) {
0135     long newbright;
0136     int f;
0137     counter--;
0138     f = get_brightness_adj((unsigned char *)m_buffer->data(), m_win.width * m_win.height, &newbright);
0139     if (f) {
0140       m_pict.brightness += (newbright << 8);
0141       myDebug() << "v4l: Adjusting brightness: new brightness " << m_pict.brightness;
0142       if (v4l1_ioctl(m_fd, VIDIOCSPICT, &m_pict) == -1) {
0143         myDebug() << "v4l: Cannot set brightness.";
0144         counter = 0; // do not try again
0145       }
0146     } else
0147       counter = 0; // do not try again
0148   }
0149 
0150   if (m_pict.palette == VIDEO_PALETTE_RGB24) {
0151     // optimized case
0152     QRgb *scanline;
0153     for (y = 0; y < m_win.height; ++y) {
0154       scanline = reinterpret_cast<QRgb*>(m_image->scanLine(y));
0155       for (x = 0; x < m_win.width; ++x) {
0156         const char src1 = *(src++);
0157         const char src2 = *(src++);
0158         const char src3 = *(src++);
0159         scanline[x] = qRgb(src1,src2,src3);
0160       }
0161     }
0162   } else {
0163     // generic case
0164     for (y = 0; y < m_win.height; ++y) {
0165       for (x = 0; x < m_win.width; ++x) {
0166         READ_VIDEO_PIXEL(src, m_pict.palette, src_depth, r, g, b);
0167         m_image->setPixel( x, y, qRgb(r>>8,g>>8,b>>8) );
0168       }
0169     }
0170   }
0171 
0172   return *m_image;
0173 }
0174 
0175 bool barcode_v4l::grab_init()
0176 {
0177   m_fd = v4l1_open(m_devname.toLatin1().constData(), O_RDONLY);
0178   if (m_fd < 0) {
0179     myDebug() << "v4l: open " << m_devname << ": " << strerror(errno);
0180     return false;
0181   }
0182 
0183   if (v4l1_ioctl(m_fd, VIDIOCGCAP, &m_capability) < 0) {
0184     myDebug() << "v4l: ioctl VIDIOCGCAP failed; " << m_devname << " not a video4linux device?";
0185     v4l1_close(m_fd);
0186     m_fd = -1;
0187     return false;
0188   }
0189 
0190   if (v4l1_ioctl(m_fd, VIDIOCGWIN, &m_win) < 0) {
0191     myDebug() << "v4l: ioctl VIDIOCGWIN failed";
0192     v4l1_close(m_fd);
0193     m_fd = -1;
0194     return false;
0195   }
0196 
0197   if (v4l1_ioctl(m_fd, VIDIOCGPICT, &m_pict) < 0) {
0198     myDebug() << "v4l: ioctl VIDIOCGPICT failed";
0199     v4l1_close(m_fd);
0200     m_fd = -1;
0201     return false;
0202   }
0203 
0204   if (m_capability.type & VID_TYPE_MONOCHROME) {
0205     m_pict.depth=8;
0206     m_pict.palette=VIDEO_PALETTE_GREY;    /* 8bit grey */
0207     if (v4l1_ioctl(m_fd, VIDIOCSPICT, &m_pict) < 0) {
0208       myDebug() << "v4l: Unable to find a supported capture format.";
0209       v4l1_close(m_fd);
0210       m_fd = -1;
0211       return false;
0212     }
0213   } else {
0214     m_pict.depth=24;
0215     m_pict.palette=VIDEO_PALETTE_RGB24;
0216     if (v4l1_ioctl(m_fd, VIDIOCSPICT, &m_pict) < 0) {
0217       myDebug() << "v4l: Unable to find a supported capture format.";
0218       v4l1_close(m_fd);
0219       m_fd = -1;
0220       return false;
0221     }
0222   }
0223 
0224   // check the values
0225   video_picture temp;
0226   v4l1_ioctl(m_fd, VIDIOCGPICT, &temp);
0227   if ((temp.depth != m_pict.depth) || (temp.palette != m_pict.palette)) {
0228     myDebug() << "v4l: Unable to find a supported capture format.";
0229     v4l1_close(m_fd);
0230     m_fd = -1;
0231     return false;
0232   }
0233 
0234   int bpp = 24;
0235   m_buffer = new QByteArray;
0236   m_buffer->reserve( m_win.width * m_win.height * bpp ); // FIXME! I think the example from the Linux kernel wastes memory here
0237   m_image = new QImage( m_win.width, m_win.height, QImage::Format_RGB32 );
0238 
0239   return true;
0240 }
0241 
0242 int barcode_v4l::get_brightness_adj(unsigned char *image, long size, long *brightness) {
0243   long i, tot = 0;
0244   for (i=0;i<size*3;i++) {
0245     tot += image[i];
0246   }
0247   *brightness = (128 - tot/(size*3))/3;
0248   return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
0249 }