Linux 下用 QT 打开摄像头并显示

271 篇文章 2 订阅
171 篇文章 0 订阅

作者:叁万英尺

转自:http://www.oschina.net/code/snippet_124925_3789


打开摄像头,并显示。

代码片段(5)[全屏查看所有代码]

1. [文件] videodevice.h ~ 908B     下载(1683)    

01#ifndef VIDEODEVICE_H
02#define VIDEODEVICE_H
03 
04#include <string.h>
05#include <stdlib.h>
06#include <errno.h>
07#include <fcntl.h>
08 
09 
10#include <sys/ioctl.h>
11#include <sys/mman.h>
12 
13#include <asm/types.h>
14#include <linux/videodev2.h>
15 
16#include <QString>
17#include <QObject>
18 
19#define CLEAR(x) memset(&(x), 0, sizeof(x))
20 
21class VideoDevice :public QObject
22{
23    Q_OBJECT
24public:
25    VideoDevice(QString dev_name);
26    //VideoDevice();
27    intopen_device();
28    intclose_device();
29    intinit_device();
30    intstart_capturing();
31    intstop_capturing();
32    intuninit_device();
33    intget_frame(void **, size_t*);
34    intunget_frame();
35 
36private:
37    intinit_mmap();
38 
39    structbuffer
40    {
41        void* start;
42        size_tlength;
43    };
44    QString dev_name;
45    intfd;
46    buffer* buffers;
47    unsigned int n_buffers;
48    intindex;
49 
50signals:
51    voiddisplay_error(QString);
52 
53};
54 
55#endif // VIDEODEVICE_H

2. [文件] videodevice.cpp ~ 7KB     下载(1487)    

001#include "videodevice.h"
002 
003VideoDevice::VideoDevice(QString dev_name)
004{
005    this->dev_name = dev_name;
006    this->fd = -1;
007    this->buffers = NULL;
008    this->n_buffers = 0;
009    this->index = -1;
010 
011}
012 
013int VideoDevice::open_device()
014{
015    fd = open(dev_name.toStdString().c_str(), O_RDWR/*|O_NONBLOCK*/, 0);
016   // fd = open(dev_name.toStdString().c_str(), O_RDWR|O_NONBLOCK, 0);
017 
018    if(-1 == fd)
019    {
020        emit display_error(tr("open: %1").arg(QString(strerror(errno))));
021        return-1;
022    }
023    return0;
024}
025 
026int VideoDevice::close_device()
027{
028    if(-1 == close(fd))
029    {
030        emit display_error(tr("close: %1").arg(QString(strerror(errno))));
031        return-1;
032    }
033    return0;
034}
035 
036int VideoDevice::init_device()
037{
038    v4l2_capability cap;
039    v4l2_cropcap cropcap;
040    v4l2_crop crop;
041    v4l2_format fmt;
042 
043    if(-1 == ioctl(fd, VIDIOC_QUERYCAP, &cap))
044    {
045        if(EINVAL ==errno)
046        {
047            emit display_error(tr("%1 is no V4l2 device").arg(dev_name));
048        }
049        else
050        {
051            emit display_error(tr("VIDIOC_QUERYCAP: %1").arg(QString(strerror(errno))));
052        }
053        return-1;
054    }
055 
056    if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
057    {
058        emit display_error(tr("%1 is no video capture device").arg(dev_name));
059        return-1;
060    }
061 
062    if(!(cap.capabilities & V4L2_CAP_STREAMING))
063    {
064        emit display_error(tr("%1 does not support streaming i/o").arg(dev_name));
065        return-1;
066    }
067 
068    CLEAR(cropcap);
069 
070    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
071 
072    if(0 == ioctl(fd, VIDIOC_CROPCAP, &cropcap))
073    {
074        CLEAR(crop);
075        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
076        crop.c = cropcap.defrect;
077 
078        if(-1 == ioctl(fd, VIDIOC_S_CROP, &crop))
079        {
080            if(EINVAL ==errno)
081            {
082//                emit display_error(tr("VIDIOC_S_CROP not supported"));
083            }
084            else
085            {
086                emit display_error(tr("VIDIOC_S_CROP: %1").arg(QString(strerror(errno))));
087                return-1;
088            }
089        }
090    }
091    else
092    {
093        emit display_error(tr("VIDIOC_CROPCAP: %1").arg(QString(strerror(errno))));
094        return-1;
095    }
096 
097    CLEAR(fmt);
098 
099    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
100    fmt.fmt.pix.width = 640;
101    fmt.fmt.pix.height = 480;
102    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
103    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
104 
105    if(-1 == ioctl(fd, VIDIOC_S_FMT, &fmt))
106    {
107        emit display_error(tr("VIDIOC_S_FMT").arg(QString(strerror(errno))));
108        return-1;
109    }
110 
111    if(-1 == init_mmap())
112    {
113        return-1;
114    }
115 
116    return0;
117}
118 
119int VideoDevice::init_mmap()
120{
121    v4l2_requestbuffers req;
122    CLEAR(req);
123 
124    req.count = 4;
125    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
126    req.memory = V4L2_MEMORY_MMAP;
127 
128    if(-1 == ioctl(fd, VIDIOC_REQBUFS, &req))
129    {
130        if(EINVAL ==errno)
131        {
132            emit display_error(tr("%1 does not support memory mapping").arg(dev_name));
133            return-1;
134        }
135        else
136        {
137            emit display_error(tr("VIDIOC_REQBUFS %1").arg(QString(strerror(errno))));
138            return-1;
139        }
140    }
141 
142    if(req.count < 2)
143    {
144        emit display_error(tr("Insufficient buffer memory on %1").arg(dev_name));
145        return-1;
146    }
147 
148    buffers = (buffer*)calloc(req.count,sizeof(*buffers));
149 
150    if(!buffers)
151    {
152        emit display_error(tr("out of memory"));
153        return-1;
154    }
155 
156    for(n_buffers = 0; n_buffers < req.count; ++n_buffers)
157    {
158        v4l2_buffer buf;
159        CLEAR(buf);
160 
161        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
162        buf.memory = V4L2_MEMORY_MMAP;
163        buf.index = n_buffers;
164 
165        if(-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
166        {
167            emit display_error(tr("VIDIOC_QUERYBUF: %1").arg(QString(strerror(errno))));
168            return-1;
169        }
170 
171        buffers[n_buffers].length = buf.length;
172        buffers[n_buffers].start =
173                mmap(NULL,// start anywhere
174                     buf.length,
175                     PROT_READ | PROT_WRITE,
176                     MAP_SHARED,
177                     fd, buf.m.offset);
178 
179        if(MAP_FAILED == buffers[n_buffers].start)
180        {
181            emit display_error(tr("mmap %1").arg(QString(strerror(errno))));
182            return-1;
183        }
184    }
185    return0;
186 
187}
188 
189int VideoDevice::start_capturing()
190{
191    unsigned int i;
192    for(i = 0; i < n_buffers; ++i)
193    {
194        v4l2_buffer buf;
195        CLEAR(buf);
196 
197        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
198        buf.memory =V4L2_MEMORY_MMAP;
199        buf.index = i;
200//        fprintf(stderr, "n_buffers: %d\n", i);
201 
202        if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))
203        {
204            emit display_error(tr("VIDIOC_QBUF: %1").arg(QString(strerror(errno))));
205            return-1;
206        }
207    }
208 
209    v4l2_buf_type type;
210    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
211 
212    if(-1 == ioctl(fd, VIDIOC_STREAMON, &type))
213    {
214        emit display_error(tr("VIDIOC_STREAMON: %1").arg(QString(strerror(errno))));
215        return-1;
216    }
217    return0;
218}
219 
220int VideoDevice::stop_capturing()
221{
222    v4l2_buf_type type;
223    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
224 
225    if(-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))
226    {
227        emit display_error(tr("VIDIOC_STREAMOFF: %1").arg(QString(strerror(errno))));
228        return-1;
229    }
230    return0;
231}
232 
233int VideoDevice::uninit_device()
234{
235    unsigned int i;
236    for(i = 0; i < n_buffers; ++i)
237    {
238        if(-1 == munmap(buffers[i].start, buffers[i].length))
239        {
240            emit display_error(tr("munmap: %1").arg(QString(strerror(errno))));
241            return-1;
242        }
243 
244    }
245    free(buffers);
246    return0;
247}
248 
249int VideoDevice::get_frame(void**frame_buf, size_t* len)
250{
251    v4l2_buffer queue_buf;
252    CLEAR(queue_buf);
253 
254    queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
255    queue_buf.memory = V4L2_MEMORY_MMAP;
256 
257    if(-1 == ioctl(fd, VIDIOC_DQBUF, &queue_buf))
258    {
259        switch(errno)
260        {
261        caseEAGAIN:
262//            perror("dqbuf");
263            return-1;
264        caseEIO:
265            return-1 ;
266        default:
267            emit display_error(tr("VIDIOC_DQBUF: %1").arg(QString(strerror(errno))));
268            return-1;
269        }
270    }
271 
272    *frame_buf = buffers[queue_buf.index].start;
273    *len = buffers[queue_buf.index].length;
274    index = queue_buf.index;
275 
276    return0;
277 
278}
279 
280int VideoDevice::unget_frame()
281{
282    if(index != -1)
283    {
284        v4l2_buffer queue_buf;
285        CLEAR(queue_buf);
286 
287        queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
288        queue_buf.memory = V4L2_MEMORY_MMAP;
289        queue_buf.index = index;
290 
291        if(-1 == ioctl(fd, VIDIOC_QBUF, &queue_buf))
292        {
293            emit display_error(tr("VIDIOC_QBUF: %1").arg(QString(strerror(errno))));
294            return-1;
295        }
296        return0;
297    }
298    return-1;
299}

3. [文件] processImage.h ~ 677B     下载(1412)    

01#ifndef PROCESSIMAGE_H
02#define PROCESSIMAGE_H
03 
04#include <QtGui>
05#include "videodevice.h"
06 
07class ProcessImage :public QWidget
08{
09    Q_OBJECT
10public:
11    ProcessImage(QWidget *parent=0);
12    ~ProcessImage();
13 
14private:
15    QPainter *painter;
16    QLabel *label;
17    QImage *frame;
18    //QPixmap *frame;
19    QTimer *timer;
20    intrs;
21    uchar *pp;
22    uchar * p;
23    unsigned int len;
24    intconvert_yuv_to_rgb_pixel(inty, int u, int v);
25    intconvert_yuv_to_rgb_buffer(unsigned char*yuv, unsigned char *rgb, unsigned int width, unsignedint height);
26    VideoDevice *vd;
27 
28private slots:
29    voidpaintEvent(QPaintEvent *);
30    voiddisplay_error(QString err);
31 
32 
33};
34 
35#endif

4. [文件] processImage.cpp ~ 4KB     下载(1422)    

001#include <QtGui>
002#include "processImage.h"
003#include "videodevice.h"
004extern "C"
005{
006#include <stdio.h>
007#include <stdlib.h>
008}
009ProcessImage::ProcessImage(QWidget *parent):QWidget(parent)
010{
011    pp = (unsignedchar *)malloc(640 * 480/*QWidget::width()*QWidget::height()*/* 3 *sizeof(char));
012    painter =new QPainter(this);
013    frame = new QImage(pp,640,480,QImage::Format_RGB888);
014   // frame = new QPixmap(640,320);
015    label = new QLabel();
016    vd = new VideoDevice(tr("/dev/video0"));
017 
018    connect(vd, SIGNAL(display_error(QString)),this,SLOT(display_error(QString)));
019    rs = vd->open_device();
020    if(-1==rs)
021    {
022        QMessageBox::warning(this,tr("error"),tr("open /dev/dsp error"),QMessageBox::Yes);
023        vd->close_device();
024    }
025 
026    rs = vd->init_device();
027    if(-1==rs)
028    {
029        QMessageBox::warning(this,tr("error"),tr("init failed"),QMessageBox::Yes);
030        vd->close_device();
031    }
032 
033    rs = vd->start_capturing();
034    if(-1==rs)
035    {
036        QMessageBox::warning(this,tr("error"),tr("start capture failed"),QMessageBox::Yes);
037        vd->close_device();
038    }
039 
040    if(-1==rs)
041    {
042        QMessageBox::warning(this,tr("error"),tr("get frame failed"),QMessageBox::Yes);
043        vd->stop_capturing();
044    }
045 
046    timer = new QTimer(this);
047    connect(timer,SIGNAL(timeout()),this,SLOT(update()));
048    timer->start(30);
049 
050    QHBoxLayout *hLayout =new QHBoxLayout();
051    hLayout->addWidget(label);
052    setLayout(hLayout);
053    setWindowTitle(tr("Capture"));
054}
055 
056ProcessImage::~ProcessImage()
057{
058    rs = vd->stop_capturing();
059    rs = vd->uninit_device();
060    rs = vd->close_device();
061}
062 
063void ProcessImage::paintEvent(QPaintEvent *)
064{
065    rs = vd->get_frame((void**)&p,&len);
066    convert_yuv_to_rgb_buffer(p,pp,640,480/*QWidget::width(),QWidget::height()*/);
067    frame->loadFromData((uchar *)pp,/*len*/640 * 480 * 3 *sizeof(char));
068 
069//    painter->begin(this);
070//    painter->drawImage(0,0,*frame);
071//    painter->end();
072//    rs = vd->unget_frame();
073   // frame->load("./img3.jpg");
074 
075    label->setPixmap(QPixmap::fromImage(*frame,Qt::AutoColor));
076   // label->show();
077    rs = vd->unget_frame();
078   // label->drawFrame();
079 
080    //    QPixmap *pixImage = new QPixmap();
081//    pixImage->loadFromData((uchar *)pp,sizeof(pp),0,Qt::AutoColor);
082//    QPainter painter(this);
083//    painter.begin(this);
084//    painter.drawPixmap(0,0,QWidget::width(),QWidget::height(),*pixImage);
085//    painter.end();
086}
087 
088void ProcessImage::display_error(QString err)
089{
090    QMessageBox::warning(this,tr("error"), err,QMessageBox::Yes);
091}
092 
093/*yuv格式转换为rgb格式*/
094int ProcessImage::convert_yuv_to_rgb_buffer(unsignedchar *yuv, unsigned char *rgb, unsigned intwidth, unsigned int height)
095{
096 unsigned int in, out = 0;
097 unsigned int pixel_16;
098 unsigned char pixel_24[3];
099 unsigned int pixel32;
100 inty0, u, y1, v;
101 for(in = 0; in < width * height * 2; in += 4) {
102  pixel_16 =
103   yuv[in + 3] << 24 |
104   yuv[in + 2] << 16 |
105   yuv[in + 1] <<  8 |
106   yuv[in + 0];
107  y0 = (pixel_16 & 0x000000ff);
108  u  = (pixel_16 & 0x0000ff00) >>  8;
109  y1 = (pixel_16 & 0x00ff0000) >> 16;
110  v  = (pixel_16 & 0xff000000) >> 24;
111  pixel32 = convert_yuv_to_rgb_pixel(y0, u, v);
112  pixel_24[0] = (pixel32 & 0x000000ff);
113  pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;
114  pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;
115  rgb[out++] = pixel_24[0];
116  rgb[out++] = pixel_24[1];
117  rgb[out++] = pixel_24[2];
118  pixel32 = convert_yuv_to_rgb_pixel(y1, u, v);
119  pixel_24[0] = (pixel32 & 0x000000ff);
120  pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;
121  pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;
122  rgb[out++] = pixel_24[0];
123  rgb[out++] = pixel_24[1];
124  rgb[out++] = pixel_24[2];
125 }
126 return0;
127}
128 
129int ProcessImage::convert_yuv_to_rgb_pixel(inty, int u, int v)
130{
131 unsigned int pixel32 = 0;
132 unsigned char *pixel = (unsigned char *)&pixel32;
133 intr, g, b;
134 r = y + (1.370705 * (v-128));
135 g = y - (0.698001 * (v-128)) - (0.337633 * (u-128));
136 b = y + (1.732446 * (u-128));
137 if(r > 255) r = 255;
138 if(g > 255) g = 255;
139 if(b > 255) b = 255;
140 if(r < 0) r = 0;
141 if(g < 0) g = 0;
142 if(b < 0) b = 0;
143 pixel[0] = r * 220 / 256;
144 pixel[1] = g * 220 / 256;
145 pixel[2] = b * 220 / 256;
146 returnpixel32;
147}
148/*yuv格式转换为rgb格式*/

5. [文件] main.cpp ~ 212B     下载(1410)    

01#include <QtGui>
02#include "processImage.h"
03 
04int main(intargc,char *argv[])
05{
06    QApplication app(argc,argv);
07    ProcessImage process;
08    process.resize(640,480);
09    process.show();
10 
11    returnapp.exec();
12}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值