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 }