Linux下控制免驱USB摄像头的信息

来源:互联网 发布:天天炫舞抽坐骑软件 编辑:程序博客网 时间:2024/05/01 11:38
Linux下控制免驱USB摄像头的信息-支持arm
--霜之小刀(转载请注明作者)
若有问题,请联系邮箱:lihn1011@163.com
QQ:2279557541
其实在linux下获取摄像头信息非常的简单。(这里我说的是UVC的USB摄像头哈,也就是所谓的免驱摄像头)
另外我操作摄像头使用的是v4l2方式,linux系统自带,无需借助三方库,但是视频的显示使用的是QT使用了第三方库
一般来说也就下面几步。
1、打开摄像头
2、获取摄像头信息
3、设置摄像头信息
4、控制摄像头开始摄像
5、设置视频数据的内存映射
6、获取视频数据
7、将视频数据转换为界面能显示的数据
8、显示
首先摄像头相关的是1~6步骤,我这里分装了一个类,先上代码
camara.h
#ifndef CAMARA_H#define CAMARA_H#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <getopt.h>#include <fcntl.h>#include <unistd.h>#include <errno.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>#include <linux/videodev2.h>#include <string>#include <map>#include <vector>struct CamaraBuffer{void* m_start;unsigned int m_length;};class Camara{public:    Camara();    bool OpenCamara(const std::string& dev_name);    bool Init(const std::string& dev_name, int width, int height);    void* GetVideo();    void FreeVideo();private:    std::string m_camara_name;    int m_camara_fd;    struct v4l2_capability m_camara_info;    std::map<int/*pixmapformat*/, std::pair<int/*type*/,std::string> > m_camara_format;    std::vector<CamaraBuffer> m_buffer_list;    struct v4l2_buffer m_current_buf;};#endif // CAMARA_H
camara.cpp
#include "Camara.h"Camara::Camara():m_camara_fd(0){}bool Camara::OpenCamara(const std::string &dev_name){    //打开摄像头    int fd = open(dev_name.c_str(), O_RDWR,0);    if(fd < 0)    {        printf("Camara Open Fiald:%d\r\n", fd);        return false;    }    m_camara_fd = fd;    m_camara_name = dev_name;    return true;}struct buffer{void* start;unsigned int length;}*buffers;bool Camara::Init(const std::string &dev_name, int width, int height){    int ret;    if(!OpenCamara(dev_name))        return false;    //获取摄像头相关信息    if((ret = ioctl(m_camara_fd, VIDIOC_QUERYCAP, &m_camara_info)))    {        printf("Camara Info Read Faild:%d",ret);        return false;    }    else    {        printf("Camara Info:\r\n");        printf("  driver:%s\r\n",m_camara_info.driver);        printf("  card:%s\r\n", m_camara_info.card);        printf("  bus_info:%s\r\n", m_camara_info.bus_info);        printf("  version:%d\r\n", m_camara_info.version);        if(m_camara_info.capabilities & V4L2_CAP_VIDEO_CAPTURE)            printf("  support: VIDEO_CAPTURE\r\n");        if(m_camara_info.capabilities & V4L2_CAP_VIDEO_OUTPUT)            printf("  support: VIDEO_OUTPUT\r\n");        if(m_camara_info.capabilities & V4L2_CAP_VIDEO_OVERLAY)            printf("  support: VIDEO_OVERLAY\r\n");        if(m_camara_info.capabilities & V4L2_CAP_VBI_CAPTURE)            printf("  support: VBI_CAPTURE\r\n");        if(m_camara_info.capabilities & V4L2_CAP_VBI_OUTPUT)            printf("  support: VBI_OUTPUT\r\n");        if(m_camara_info.capabilities &  V4L2_CAP_SLICED_VBI_CAPTURE)            printf("  support: SLICED_VBI_CAPTURE\r\n");        if(m_camara_info.capabilities &  V4L2_CAP_SLICED_VBI_OUTPUT)            printf("  support: SLICED_VBI_OUTPUT\r\n");        if(m_camara_info.capabilities &  V4L2_CAP_RDS_CAPTURE)            printf("  support: RDS_CAPTURE\r\n");        if(m_camara_info.capabilities &  V4L2_CAP_VIDEO_OUTPUT_OVERLAY)            printf("  support: VIDEO_OUTPUT_OVERLAY\r\n");        if(m_camara_info.capabilities &  V4L2_CAP_HW_FREQ_SEEK)            printf("  support: HW_FREQ_SEEK\r\n");        if(m_camara_info.capabilities &  V4L2_CAP_RDS_OUTPUT)            printf("  support: RDS_OUTPUT\r\n");    }    //get support format    struct v4l2_fmtdesc fmtdesc;    fmtdesc.index=0;    fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;    m_camara_format.clear();    printf("Camara Format Support:\r\n");    while(ioctl(m_camara_fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)    {        printf("  type:%d description:%s pixmapformat:%d\r\n",fmtdesc.type, fmtdesc.description, fmtdesc.pixelformat);        m_camara_format[fmtdesc.pixelformat] = std::pair<int, std::string>                (fmtdesc.type,(char*)fmtdesc.description);        fmtdesc.index++;    }    printf("Set Camara Format:\r\n");    {//set format        struct v4l2_format fmt;        memset ( &fmt, 0, sizeof(fmt) );        fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;        fmt.fmt.pix.width       = width;        fmt.fmt.pix.height      = height;        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;        fmt.fmt.pix.field       = (v4l2_field)0;        if ( (ret = ioctl(m_camara_fd, VIDIOC_S_FMT, &fmt)))        {            printf("Set Camara Format faild:%d\r\n",ret);            return -1;        }    }    struct v4l2_format fmt;    fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;    printf("Camara Format Current:\r\n");    if((ret = ioctl(m_camara_fd,VIDIOC_G_FMT,&fmt)))    {        printf("Get Camara Format Faild:%d\r\n", ret);        return false;    }    else    {    printf("  w:%d h:%d format:%s\r\n",           fmt.fmt.pix.width,           fmt.fmt.pix.height,           m_camara_format[fmt.fmt.pix.pixelformat].second.c_str());    }    //request buffer    struct v4l2_requestbuffers req;    req.count=8;    req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;    req.memory=V4L2_MEMORY_MMAP;    printf("Request Buffer");    if((ret = ioctl(m_camara_fd,VIDIOC_REQBUFS,&req)))    {        printf("Request Buffer Faild:%d\r\n", ret);        return false;    }    printf("Request Buffer Successful\r\n");    //    printf("Query Buffer\r\n");    m_buffer_list.resize(req.count);    for (unsigned int buffer_idx = 0; buffer_idx < req.count; ++buffer_idx)    {        struct v4l2_buffer buf;        memset(&buf, 0, sizeof(buf));        buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;        buf.memory =V4L2_MEMORY_MMAP;        buf.index =buffer_idx;        // 查询序号为n_buffers 的缓冲区,得到其起始物理地址和大小        if ( (ret = ioctl(m_camara_fd, VIDIOC_QUERYBUF, &buf)))        {            printf("buffer query faild:%d\r\n", ret);            return false;        }        m_buffer_list[buffer_idx].m_length= buf.length;        // 映射内存        errno = 0;        m_buffer_list[buffer_idx].m_start=         (char*)mmap (NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,m_camara_fd, buf.m.offset);        if (MAP_FAILED == m_buffer_list[buffer_idx].m_start)        {            printf("mmap faild:%d,%s\r\n", ret,strerror(errno));            return false;        }    }    printf("Query Buffer Successful\r\n");    //Set Buffer To Quene    for (unsigned int i = 0; i< req.count; ++i)    {        struct v4l2_buffer buf;        buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;        buf.memory =V4L2_MEMORY_MMAP;        buf.index = i;        if((ret=ioctl (m_camara_fd, VIDIOC_QBUF, &buf)))        {            printf("Set Buffer To Quene faild:%d,%s\r\n", ret,strerror(errno));            return false;        }    }    printf("Set Buffer To Quene Successful\r\n");    //Stream On    int type =V4L2_BUF_TYPE_VIDEO_CAPTURE;    if((ret = ioctl (m_camara_fd,VIDIOC_STREAMON, &type)))    {        printf("Stream On faild:%d,%s\r\n", ret,strerror(errno));        return false;    }    printf("Stream On Successful\r\n");    return true;}void *Camara::GetVideo(){    //void* video_ptr = 0;    int ret;    memset(&m_current_buf, 0, sizeof(m_current_buf));    m_current_buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;    m_current_buf.memory =V4L2_MEMORY_MMAP;    // 从缓冲区取出一个缓冲帧    if((ret = ioctl (m_camara_fd,VIDIOC_DQBUF, &m_current_buf)))    {         printf("GetVideo faild:%d,%s\r\n", ret,strerror(errno));         return NULL;    }    // 图像处理    ;    //video_ptr = malloc(m_buffer_list[buf.index].m_length);    //memcpy(video_ptr, m_buffer_list[buf.index].m_start, m_buffer_list[buf.index].m_length);    // 将取出的缓冲帧放回缓冲区    //printf("GetVideo Successful\r\n");    return m_buffer_list[m_current_buf.index].m_start;}void Camara::FreeVideo(){    int ret;    if((ret = ioctl (m_camara_fd, VIDIOC_QBUF,&m_current_buf)))    {         printf("GetVideo faild:%d,%s\r\n", ret,strerror(errno));         //return NULL;    }}
这里面要注意一点,我们在代码中获取得到了摄像头的信息,主要是为了知道我们的摄像机到底支持哪些格式,然后在设置进去。如果格式不支持,那么我们设置的时候就会报错。
然后是视频的显示,我这里的界面库使用的是QT。
main.cpp
#include "MainWidget.h"#include <QApplication>#include "Camara.h"#include "MainWidget.h"int main(int argc, char *argv[]){    QApplication a(argc, argv);    MainWidget w;    w.setWindowFlags(Qt::FramelessWindowHint);    w.show();    return a.exec();}


MainWidget.h
#ifndef MAINWIDGET_H#define MAINWIDGET_H#include <QWidget>#include <QTimer>#include "Camara.h"namespace Ui {class MainWidget;}class MainWidget : public QWidget{    Q_OBJECTpublic:    explicit MainWidget(QWidget *parent = 0);    ~MainWidget();protected:    void paintEvent(QPaintEvent *event);private slots:    void OnTimer();private:    int m_video_width;    int m_video_height;    Ui::MainWidget *ui;    Camara m_camara;    QTimer m_paint_timer;};#endif // MAINWIDGET_H


MainWidget.cpp

#include "MainWidget.h"#include "ui_MainWidget.h"#include <QPainter>MainWidget::MainWidget(QWidget *parent) :    QWidget(parent),    ui(new Ui::MainWidget),m_video_width(640),m_video_height(480){    ui->setupUi(this);    m_camara.Init("/dev/video0",m_video_width, m_video_height);    m_paint_timer.setInterval(50);    connect(&m_paint_timer,SIGNAL(timeout()), this, SLOT(OnTimer()) );    m_paint_timer.start();}MainWidget::~MainWidget(){    delete ui;}int convert_yuv_to_rgb_pixel(int y, int u, int v){    unsigned int pixel32 = 0;    unsigned char *pixel = (unsigned char *)&pixel32;    int r, g, b;    r = y + (1.370705 * (v-128));    g = y - (0.698001 * (v-128)) - (0.337633 * (u-128));    b = y + (1.732446 * (u-128));    if(r > 255) r = 255;    if(g > 255) g = 255;    if(b > 255) b = 255;    if(r < 0) r = 0;    if(g < 0) g = 0;    if(b < 0) b = 0;    pixel[0] = r * 220 / 256;    pixel[1] = g * 220 / 256;    pixel[2] = b * 220 / 256;    return pixel32;}int convert_yuv_to_rgb_buffer(unsigned char *yuv, unsigned char *rgb, unsigned int width, unsigned int height){    unsigned int in, out = 0;    unsigned int pixel_16;    unsigned char pixel_24[3];    unsigned int pixel32;    int y0, u, y1, v;    for(in = 0; in < width * height * 2; in += 4) {        pixel_16 =                yuv[in + 3] << 24 |                yuv[in + 2] << 16 |                yuv[in + 1] <<  8 |                yuv[in + 0];        y0 = (pixel_16 & 0x000000ff);        u  = (pixel_16 & 0x0000ff00) >>  8;        y1 = (pixel_16 & 0x00ff0000) >> 16;        v  = (pixel_16 & 0xff000000) >> 24;        pixel32 = convert_yuv_to_rgb_pixel(y0, u, v);        pixel_24[0] = (pixel32 & 0x000000ff);        pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;        pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;        rgb[out++] = pixel_24[0];        rgb[out++] = pixel_24[1];        rgb[out++] = pixel_24[2];        pixel32 = convert_yuv_to_rgb_pixel(y1, u, v);        pixel_24[0] = (pixel32 & 0x000000ff);        pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;        pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;        rgb[out++] = pixel_24[0];        rgb[out++] = pixel_24[1];        rgb[out++] = pixel_24[2];    }    return 0;}#include <QDateTime>void MainWidget::paintEvent(QPaintEvent *event){    QPainter pt(this);    QDateTime time = QDateTime::currentDateTime();    printf("%d:%d:%d:%d\r\n", time.time().hour(),time.time().minute(),time.time().second(),time.time().msec());    unsigned char* data = (unsigned char*)m_camara.GetVideo();    unsigned char* rgb24 = (unsigned char*)malloc(614400*2);    QImage img(rgb24, m_video_width,m_video_height,QImage::Format_RGB888);    convert_yuv_to_rgb_buffer(data,rgb24,m_video_width,m_video_height/*QWidget::width(),QWidget::height()*/);    img.loadFromData((uchar *)rgb24,/*len*/320 * 240 * 3 * sizeof(char));    //scale    img = img.scaled(640,480);    pt.drawImage(0,0,img);    m_camara.FreeVideo();    free(rgb24);    time = QDateTime::currentDateTime();    printf("%d:%d:%d:%d\r\n", time.time().hour(),time.time().minute(),time.time().second(),time.time().msec());}void MainWidget::OnTimer(){    printf("ontimer\r\n");    update();}


0 0
原创粉丝点击