File indexing completed on 2024-05-12 05:09:21

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   delete m_buffer;
0110   delete m_image;
0111 }
0112 
0113 bool barcode_v4l::isOpen()
0114 {
0115   return (m_fd >= 0);
0116 }
0117 
0118 QImage barcode_v4l::grab_one2()
0119 {
0120   unsigned int bpp = 24, x, y;
0121   unsigned int r = 0, g = 0, b = 0;
0122   unsigned int src_depth = 16;
0123   char *src = m_buffer->data();
0124 
0125   static int counter = 0; // adjustment disabled; set to e.g. 20 or 50 to enable the brightness adjustment
0126 
0127   if (!isOpen())
0128     return QImage();
0129 
0130   v4l1_read(m_fd, m_buffer->data(), m_win.width * m_win.height * bpp);
0131 
0132   if (counter) {
0133     long newbright;
0134     int f;
0135     counter--;
0136     f = get_brightness_adj((unsigned char *)m_buffer->data(), m_win.width * m_win.height, &newbright);
0137     if (f) {
0138       m_pict.brightness += (newbright << 8);
0139       myDebug() << "v4l: Adjusting brightness: new brightness " << m_pict.brightness;
0140       if (v4l1_ioctl(m_fd, VIDIOCSPICT, &m_pict) == -1) {
0141         myDebug() << "v4l: Cannot set brightness.";
0142         counter = 0; // do not try again
0143       }
0144     } else
0145       counter = 0; // do not try again
0146   }
0147 
0148   if (m_pict.palette == VIDEO_PALETTE_RGB24) {
0149     // optimized case
0150     QRgb *scanline;
0151     for (y = 0; y < m_win.height; ++y) {
0152       scanline = reinterpret_cast<QRgb*>(m_image->scanLine(y));
0153       for (x = 0; x < m_win.width; ++x) {
0154         const char src1 = *(src++);
0155         const char src2 = *(src++);
0156         const char src3 = *(src++);
0157         scanline[x] = qRgb(src1,src2,src3);
0158       }
0159     }
0160   } else {
0161     // generic case
0162     for (y = 0; y < m_win.height; ++y) {
0163       for (x = 0; x < m_win.width; ++x) {
0164         READ_VIDEO_PIXEL(src, m_pict.palette, src_depth, r, g, b);
0165         m_image->setPixel( x, y, qRgb(r>>8,g>>8,b>>8) );
0166       }
0167     }
0168   }
0169 
0170   return *m_image;
0171 }
0172 
0173 bool barcode_v4l::grab_init()
0174 {
0175   m_fd = v4l1_open(m_devname.toLatin1().constData(), O_RDONLY);
0176   if (m_fd < 0) {
0177     myDebug() << "v4l: open " << m_devname << ": " << strerror(errno);
0178     return false;
0179   }
0180 
0181   if (v4l1_ioctl(m_fd, VIDIOCGCAP, &m_capability) < 0) {
0182     myDebug() << "v4l: ioctl VIDIOCGCAP failed; " << m_devname << " not a video4linux device?";
0183     v4l1_close(m_fd);
0184     m_fd = -1;
0185     return false;
0186   }
0187 
0188   if (v4l1_ioctl(m_fd, VIDIOCGWIN, &m_win) < 0) {
0189     myDebug() << "v4l: ioctl VIDIOCGWIN failed";
0190     v4l1_close(m_fd);
0191     m_fd = -1;
0192     return false;
0193   }
0194 
0195   if (v4l1_ioctl(m_fd, VIDIOCGPICT, &m_pict) < 0) {
0196     myDebug() << "v4l: ioctl VIDIOCGPICT failed";
0197     v4l1_close(m_fd);
0198     m_fd = -1;
0199     return false;
0200   }
0201 
0202   if (m_capability.type & VID_TYPE_MONOCHROME) {
0203     m_pict.depth=8;
0204     m_pict.palette=VIDEO_PALETTE_GREY;    /* 8bit grey */
0205     if (v4l1_ioctl(m_fd, VIDIOCSPICT, &m_pict) < 0) {
0206       myDebug() << "v4l: Unable to find a supported capture format.";
0207       v4l1_close(m_fd);
0208       m_fd = -1;
0209       return false;
0210     }
0211   } else {
0212     m_pict.depth=24;
0213     m_pict.palette=VIDEO_PALETTE_RGB24;
0214     if (v4l1_ioctl(m_fd, VIDIOCSPICT, &m_pict) < 0) {
0215       myDebug() << "v4l: Unable to find a supported capture format.";
0216       v4l1_close(m_fd);
0217       m_fd = -1;
0218       return false;
0219     }
0220   }
0221 
0222   // check the values
0223   video_picture temp;
0224   v4l1_ioctl(m_fd, VIDIOCGPICT, &temp);
0225   if ((temp.depth != m_pict.depth) || (temp.palette != m_pict.palette)) {
0226     myDebug() << "v4l: Unable to find a supported capture format.";
0227     v4l1_close(m_fd);
0228     m_fd = -1;
0229     return false;
0230   }
0231 
0232   int bpp = 24;
0233   m_buffer = new QByteArray;
0234   m_buffer->reserve( m_win.width * m_win.height * bpp ); // FIXME! I think the example from the Linux kernel wastes memory here
0235   m_image = new QImage( m_win.width, m_win.height, QImage::Format_RGB32 );
0236 
0237   return true;
0238 }
0239 
0240 int barcode_v4l::get_brightness_adj(unsigned char *image, long size, long *brightness) {
0241   long i, tot = 0;
0242   for (i=0;i<size*3;i++) {
0243     tot += image[i];
0244   }
0245   *brightness = (128 - tot/(size*3))/3;
0246   return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
0247 }