1. 程式人生 > >ARM9+Linux下USB攝像頭影象採集

ARM9+Linux下USB攝像頭影象採集

終於實現了在Micro2440+Linux2.6.29環境下通過NFS檔案系統實現USB攝像頭影象採集。在此,做一個總結,以備後續參考。 

實驗條件:RedHat9.0(核心版本2.4.18),Micro2440開發板,Linux2.6.29(arm9),ANC (Vimicro Corp.) USB PC攝像頭,GCC,SDL-1.2.14.tar,servfox-R1_1_3[1].tar,spcaview-20061208[1].tar。

一、升級Redhat9.0核心

由於Readhat9.0核心版本是2.4,很多核心驅動未包含其中,尤其是USB萬能攝像頭GSPCA和UVC。

二、配置編譯Micro2440上執行核心

重新編譯Micro2440上執行的核心,配置V4L和USB驅動。選擇linux-2.6.29中的config-mini2440為參考,執行:cp config-mini2440 .config;然後make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-;出現相應的圖形化配置視窗。

如果需要在Linux作業系統中使用USB攝像頭進行視訊資料採集,則必須在進行核心配置時,應檢查Linux 核心中是否已經添加了對Video4Linux驅動和對USB攝像頭驅動模組的支援。

利用Linux核心配置make menuconfig命令對Video4Linux支援驅動進行配置,選中多媒體裝置選項“Multimedia device->”(如圖15-1所示)按回車,進入多媒體裝置配置介面。在多媒體配置介面中,選中“Video For Linux”,就可以使核心實現對Video4Linux驅動的支援,為視訊採集裝置提供程式設計介面。

         配置好核心對Video4Linux驅動後,返回核心配置主介面,選中USB支援選項(如圖15-3 所示)“USB support—>” 按回車,進入USB支援配置介面

         配置完成後,執行make uImage ARCH=arm CROSS_COMPILE=arm-linux-。完成後,uImage就生成在arch/arm/boot/中。通過uboot下載uImage到記憶體中,啟動核心,實現NFS起檔案系統。

三、安裝SDL-1.2.14

因為在redhat9.0中顯示視訊影象,呼叫spcaview(後面介紹)需要有SDL庫的支援,否則會報錯。所以,將SDL-1.2.14.tar下載傳送到系統中,解壓後執行.configure;make;make install。完成SDL庫的安裝。

四、servfox-R1_1_3工具

     下載Servfox-R1_1_3解壓進入其目錄,將其中的Makefile.arm修改為Makefile,並修改Makefile裡面的CC為arm -linux -gcc,因為預設的是載入的動態庫,因此還需要修改Makefile中的SERVFLAGS為SERVFLAGS= -O2 –DLINUX $(WARNINGS) –static,其中-static是我們新增的內容,make之後生成servfox。

五、              spcaview,redhat9.0下的視訊顯示工具
下載spcaview原始碼包解壓,進入解壓後的目錄,make後會報錯,一般需要安裝SDL庫,去網上下載後安裝SDL庫,在PC 機上安裝SDL庫:

解壓:tar xvf SDL-1.2.13.tar.tar

配置:./configure

編譯:make

安裝:make install

進入spcaview解壓目錄修改Makefile中的修改Makefile中的SDLLIBS =$(shell sdl-config --libs) 和 SDLFLAGS = $(shell sdl-config --cflags),這兩句主要是指定了SDL庫的庫路徑和編譯選項。Make之後生成spcaview,在客戶端執行spcaview –w 伺服器ip:伺服器埠號。就可以採集影象了,

[[email protected] spcaview-20061208]# ./spcaview -g -w 10.103.4.211:7070
 Spcaview version: 1.1.7 date: 06:11:2006 (C) [email protected] 
using Server 10.103.4.211 Port 7070

六、測試

將新編譯的核心載入到ARM上,通過NFS檔案系統執行servfox :

# ./servfox -d /dev/video0 -g -s 640x480 -w 7070                            

 servfox version: 1.1.3 date: 11:12:2005 (C) [email protected]             

wrong spca5xx device                                                           

Waiting .... for connection. CTrl_c to stop !!!!                             

Got connection from 10.103.4.216

         在redhat9.0中執行spcaview:

[[email protected] spcaview-20061208]# ./spcaview -g -w 10.103.4.211:7070
 Spcaview version: 1.1.7 date: 06:11:2006 (C) [email protected] 
using Server 10.103.4.211 Port 7070

此時,視訊能在redhat9.0視窗中顯示,如圖所示。 

七、總結

在實現影象採集的過程中,碰到很多問題,嘗試過很多方法,走了很多彎路,雖然很多碰壁,但也有不少收穫。

編譯核心:嘗試編譯高版本的核心,或者編譯新核心的時候,最好選擇和現有的配置檔案相近的系統的配置檔案作為參考。在原有基礎上增加一些模組,編譯,然後試驗。如果一次性增加模組過多,容易造成編譯錯誤等問題。

編譯工具:在編譯某些外掛的時候,如:servfox、spcaview等,經常會報一些檔案未定義、庫不存在等錯誤,一般是由於系統缺少相應的庫檔案,需要下載安裝,如SDL,或者由於系統本身版本不匹配,庫檔案安裝位置不符造成。熟練運用goole、百度進行搜尋,找到問題解決方法。同時,很多工具、庫、外掛等在開源社群網站都有穩定版本下載,使用這些網站提供的版本可靠性更好。

重點難點:makefile、kconfig等檔案的書寫,kit工具使用等。

附錄:視訊採集原始碼分析(看程式碼採用Lucida Console或者Consolas等寬字型較好,0和o區別明顯,不易混淆)

/*

 *  V4L2 video capture example

 *

 *  This program can be used and distributed without restrictions.

 */

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

#include <getopt.h>             /* getopt_long() */

#include <fcntl.h>              /* low-level i/o */

#include <unistd.h>

#include <errno.h>

#include <malloc.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>          /* for videodev2.h */

#include <linux/videodev2.h>

#define CLEAR(x) memset (&(x), 0, sizeof (x))

typedef enum {

        IO_METHOD_READ,

        IO_METHOD_MMAP,

        IO_METHOD_USERPTR,

} io_method;        //一共有三種視訊採集方式:使用read、write方式;記憶體對映方式和使用者指標模式

struct buffer {

        void *                  start;

        size_t                  length;

};  // 定義緩衝區

static char *           dev_name        = NULL;   // 裝置名稱,可根據裝置名開啟裝置

static io_method        io              = IO_METHOD_MMAP;// 視訊採集方式,記憶體對映方式

static int              fd              = -1;

struct buffer *         buffers         = NULL;

static unsigned int     n_buffers       = 0;

static void errno_exit (const char *s)// 錯誤退出,並列印錯誤資訊

{

        fprintf (stderr, "%s error %d, %s\n",s, errno, strerror (errno));

        exit (EXIT_FAILURE);

}

static intxioctl  (int fd,int request,void *arg)// 根據引數對裝置進行控制

{

        int r;

        do r = ioctl (fd, request, arg);

        while (-1 == r && EINTR == errno);

        return r;

}

static void process_image (const void * p)// 影象處理

{

        fputc ('.', stdout);

        fflush (stdout);// 重新整理輸出緩衝

}

static int read_frame (void)// 對影象幀進行讀取

{

        struct v4l2_buffer buf;//這是視訊介面V4L2中相關檔案定義的,在videodev2.h中

        unsigned int i;

        switch (io)      

        case IO_METHOD_READ:

                if (-1 == read (fd, buffers[0].start, buffers[0].length)) {

                        switch (errno) {

                        case EAGAIN:

                                return 0;

                        case EIO:

                                /* Could ignore EIO, see spec. */

                                /* fall through */

                        default:

                                errno_exit ("read");

                        }

                }

                process_image (buffers[0].start);

                break;

        case IO_METHOD_MMAP://採用記憶體對映的方式

                CLEAR (buf);//對緩衝區清零

                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

                buf.memory = V4L2_MEMORY_MMAP;

                if (-1 == ioctl (fd, VIDIOC_DQBUF, &buf)) {

                  //VIDIOC_DQBUF控制引數作用是申請視訊緩衝區

                        switch (errno) {

                        case EAGAIN:

                                return 0;

                        case EIO:

                                /* Could ignore EIO, see spec. */

                                /* fall through */

                        default:

                                errno_exit ("VIDIOC_DQBUF");

                        }

                }

                assert (buf.index < n_buffers);

                process_image (buffers[buf.index].start);

                if (-1 == ioctl (fd, VIDIOC_QBUF, &buf))

                        errno_exit ("VIDIOC_QBUF");

                break;

        case IO_METHOD_USERPTR:

                CLEAR (buf);

                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

                buf.memory = V4L2_MEMORY_USERPTR;

                if (-1 == ioctl (fd, VIDIOC_DQBUF, &buf)) {

                        switch (errno) {

                        case EAGAIN:

                                return 0;

                        case EIO:

                                /* Could ignore EIO, see spec. */

                                /* fall through */

                        default:

                                errno_exit ("VIDIOC_DQBUF");

                        }

                }

                for (i = 0; i < n_buffers; ++i)

                        if (buf.m.userptr == (unsigned long) buffers[i].start

                            && buf.length == buffers[i].length)

                                break;

                assert (i < n_buffers);

                process_image ((void *) buf.m.userptr);

                if (-1 == ioctl (fd, VIDIOC_QBUF, &buf))

                        errno_exit ("VIDIOC_QBUF");

                break;

        }

        return 1;

}

static void mainloop (void)//迴圈採集

{

        unsigned int count;

        count = 100;

        while (count-- > 0) {

                for (;;) {

                        fd_set fds;

                        struct timeval tv;//時間結構體

                        int r;

                        FD_ZERO (&fds);//清零

                        FD_SET (fd, &fds);

                        /* Timeout. */

                        tv.tv_sec = 2;

                        tv.tv_usec = 0;

                        r = select (fd + 1, &fds, NULL, NULL, &tv);//等待一幀影象採集完成,超時定為2秒

                        if (-1 == r) {

                                if (EINTR == errno)

                                        continue;

                                errno_exit ("select");

                        }

                        if (0 == r) {

                                fprintf (stderr, "select timeout\n");

                                exit (EXIT_FAILURE);

                        }

                        if (read_frame ())//讀取一幀影象

                                break;

                        /* EAGAIN - continue select loop. */

                }

        }

}

static void stop_capturing (void)//終止採集

{

        enum v4l2_buf_type type;

        switch (io) {

        case IO_METHOD_READ:

                /* Nothing to do. */

                break;

        case IO_METHOD_MMAP:

        case IO_METHOD_USERPTR:

                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

                if (-1 == ioctl (fd, VIDIOC_STREAMOFF, &type))

                        errno_exit ("VIDIOC_STREAMOFF");

                break;

        }

}

static void start_capturing (void)//開始採集

{

        unsigned int i;

        enum v4l2_buf_type type;

        switch (io) {

        case IO_METHOD_READ:

                /* Nothing to do. */

                break;

        case IO_METHOD_MMAP:

                for (i = 0; i < n_buffers; ++i) {

                        struct v4l2_buffer buf;

                        CLEAR (buf);

                        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;

                        buf.memory      = V4L2_MEMORY_MMAP;

                        buf.index       = i;

                        if (-1 == ioctl (fd, VIDIOC_QBUF, &buf))

                                errno_exit ("VIDIOC_QBUF");

                }

                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

                if (-1 == ioctl (fd, VIDIOC_STREAMON, &type))

                        errno_exit ("VIDIOC_STREAMON");

                break;

        case IO_METHOD_USERPTR:

                for (i = 0; i < n_buffers; ++i) {

                        struct v4l2_buffer buf;

                        CLEAR (buf);

                        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;

                        buf.memory      = V4L2_MEMORY_USERPTR;

                        buf.index       = i;

                        buf.m.userptr   = (unsigned long) buffers[i].start;

                        buf.length      = buffers[i].length;

                        if (-1 == ioctl (fd, VIDIOC_QBUF, &buf))

                                errno_exit ("VIDIOC_QBUF");

                }

                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

                if (-1 == ioctl (fd, VIDIOC_STREAMON, &type))

                        errno_exit ("VIDIOC_STREAMON");

                break;

        }

}

static void uninit_device (void)//解除安裝裝置

{

        unsigned int i;

        switch (io) {

        case IO_METHOD_READ:

                free (buffers[0].start);

                break;

        case IO_METHOD_MMAP:

                for (i = 0; i < n_buffers; ++i)

                        if (-1 == munmap (buffers[i].start, buffers[i].length))

                                errno_exit ("munmap");

                break;

        case IO_METHOD_USERPTR:

                for (i = 0; i < n_buffers; ++i)

                        free (buffers[i].start);

                break;

        }

        free (buffers);

}

static void init_read (unsigned int buffer_size)//初始化讀取

{

        buffers = calloc (1, sizeof (*buffers));

        if (!buffers) {

                fprintf (stderr, "Out of memory\n");

                exit (EXIT_FAILURE);

        }

        buffers[0].length = buffer_size;

        buffers[0].start = malloc (buffer_size);

        if (!buffers[0].start) {

                fprintf (stderr, "Out of memory\n");

                exit (EXIT_FAILURE);

        }

}

static void init_mmap (void)//初始化記憶體對映

{

        struct v4l2_requestbuffers req;

        CLEAR (req);

        req.count               = 4;

        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        req.memory              = V4L2_MEMORY_MMAP;

        if (-1 == ioctl (fd, VIDIOC_REQBUFS, &req)) {

                if (EINVAL == errno) {

                        fprintf (stderr, "%s does not support "

                                 "memory mapping\n", dev_name);

                        exit (EXIT_FAILURE);

                } else {

                        errno_exit ("VIDIOC_REQBUFS");

                }

        }

        if (req.count < 2) {

                fprintf (stderr, "Insufficient buffer memory on %s\n",

                         dev_name);

                exit (EXIT_FAILURE);

        }

        buffers = calloc (req.count, sizeof (*buffers));

        if (!buffers) {

                fprintf (stderr, "Out of memory\n");

                exit (EXIT_FAILURE);

        }

        for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {

                struct v4l2_buffer buf;   //代表驅動中的一幀

                CLEAR (buf);

                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;

                buf.memory      = V4L2_MEMORY_MMAP;

                buf.index       = n_buffers;

                if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf))

                        errno_exit ("VIDIOC_QUERYBUF");

                buffers[n_buffers].length = buf.length;

                buffers[n_buffers].start =

                        mmap (NULL /* start anywhere */,

                              buf.length,

                              PROT_READ | PROT_WRITE /* required */,

                              MAP_SHARED /* recommended */,

                              fd, buf.m.offset);

                if (MAP_FAILED == buffers[n_buffers].start)

                        errno_exit ("mmap");

        }

}

static void init_userp (unsigned int buffer_size)

{

        struct v4l2_requestbuffers req;

        unsigned int page_size;

        page_size = getpagesize ();

相關推薦

ARM9+LinuxUSB攝像頭影象採集

終於實現了在Micro2440+Linux2.6.29環境下通過NFS檔案系統實現USB攝像頭影象採集。在此,做一個總結,以備後續參考。  實驗條件:RedHat9.0(核心版本2.4.18),Micro2440開發板,Linux2.6.29(arm9),ANC

linux USB 攝像頭的使用說明

此處我只說用uvc通用驅動 查詢攝像頭是否是UVC裝置,參見官網 1 找到CAMERA ID 2 lsusb -d VID:PID -v | grep “14 Video” 如果輸出有下面資訊說明支援 bFunctionClass

在Ubuntu16.04安裝OpenCV3.1並實現USB攝像頭影象採集

硬體平臺:Windows7 64 bit + USB攝像頭C270 軟體平臺:VMware® Workstation 12 Pro+ Ubuntu16.04 + arm-linux-gcc4.3.2 + OpenCV3.1 一、知識補充 1.

Python+Opencv+Qt4編寫Windows攝像頭影象採集顯示程式

# -*- coding: utf-8 -*- # Form implementation generated from reading ui file '1.ui' # # Created: Tue Nov 14 09:45:29 2017 #      by: Py

Opencv開發環境VS2017配置---USB攝像頭視訊採集

一、下載OpenCV3庫     (2)解壓縮安裝到 C盤根目錄下 二、開啟VS2017新建一個專案 配置【附加包含目錄】 新增附加庫Lib 設定依賴庫 opencv_world343.lib opencv_world343d.lib

LinuxUSB轉串列埠驅動

Linux發行版自帶usb to serial驅動,以模組方式編譯驅動,在核心原始碼目錄下執行Make MenuConfig選擇Devces drivers-->USB seupport--> <M>USB Serial Converter support --> <M

linuxUSB轉串列埠的設定

在linux下利用簡訊modem傳送簡訊,由於簡訊modem使用的是USB串列埠轉換器(晶片為PL2303),把在配置和除錯的過程和方法在此記錄下,希望給有同樣需求的同仁提供一點幫助。 【一】、驅動相關說明:如果直接使用串列埠線,而沒有用到USB轉串列埠裝置,就不需要安裝驅

OpenCV入門學習之讀取usb攝像頭影象,實時顯示

首先,新建一個.cpp的源程式檔案,例如,gedit test.cpp 在該檔案中新增以下程式: #include <opencv2/core/core.hpp> #include

基於arm平臺linuxUSB音效卡驅動安裝和使用

核心配置 <*> Advanced Linux Sound Architecture —> usb音效卡安裝 1.apt-get install alsa-base 2

C語言高階應用---操作linuxV4L2攝像頭應用程式

#include "CameralOpt.h" int video_fd ; int length ; char *yuv[COUNT] ; struct v4l2_buffer enqueue , dequeue ; //定義出入隊的操作結構體成員 int Init_Cameral(int

OV7725攝像頭影象採集基礎知識

目前FPGA用於影象採集 傳輸 處理 顯示應用越來越多,主要原因是影象處理領域的火熱以及FPGA強大的並行處理能力。本文以OV7725為例,對攝像頭使用方面的基礎知識做個小的總結,為後續做個鋪墊。   XCLK:工作時鐘輸入,由主控器產生,頻率為24MH

linuxUSB轉串列埠識別1

minicom是linux下串列埠通訊的軟體,它的使用完全依靠鍵盤的操作,雖然沒有“超級終端”那麼易用,但是使用習慣之後讀者將會體會到它的高效與便利,下面將講解minicom的安裝和配置。 一、安裝minicom: 使用以下命令: # sudo apt-get instal

關於怎樣把普通usb攝像頭影象釋出到ros的topic

前言:一個人搞某個領域的東西,沒個人帶真不行,整天糾結於各種小毛問題   這是一個很容易提出的問題,ORB_SLAM做線上單目必須牽扯到怎樣把usb_cam(這裡指筆記本自帶攝像頭)的資料釋出到ros的topic供使用,這裡給出方法如下: Step2:新

linux 和 windows 用ffmpeg 操作usb攝像頭

windows : 列裝置  ffmpeg -list_devices true -f dshow -i dummy 編碼為H.264,儲存為本地檔案  ffmpeg -f&nb

USB攝像頭採集影象(DirectShow)

攝像頭除了可以捕獲視訊流還可以捕獲單張靜止的圖片,靜止的圖片質量比流的質量要高。支援輸出靜態圖片的攝像頭一般要提供一個靜態圖片PIN,這個PIN的種類是PIN_CATEGORY_STILL。 捕捉靜態圖片常用的filter是Sample Graber filter,它的用

Zedboard & Zynq 影象採集(五) 板端Linux視訊TCP傳送 & Linux上位機QT視訊顯示

前面幾篇已經陸續講述了影象採集,傳輸,Linux系統搭建等,這一篇就講一下自制一個簡單的板端視訊傳送和Linux上位機視訊顯示客戶端。板端視訊傳送用Zedboard做視訊資料傳輸,我能想到的是兩條路,一條就是網口,一條就是USB,USB傳輸方式打算以後研究一下,用網口是比較熟

Linux利用nginx流伺服器推送攝像頭實時採集視訊

應用環境:伺服器:Ubuntu 14.04.5 (cat /etc/issue檢視)。 USB攝像頭:直插在Linux上。 ffmpeg -f video4linux2 -i /dev/video0 -f flv rtmp://192.168.1.200/live/live

兩個usb攝像頭的同時採集影象的一般方法。

很多人都為兩個usb攝像頭同步採集影象而苦惱,而且在網上也有很多基於opencv的usb攝像頭的採集影象方法。 我也曾經為了實現同步採集而煩惱了。。。 可現在終於知道了很簡單而且很好地方法。 方法如下: 首先讓自己的電腦自帶的攝像頭禁用(這你可以搞定吧?如果不知道就問我。

Linux環境使用V4L2+opencv以MJPEG格式讀取USB攝像頭並實時顯示

轉眼間,V4L2已經搞了很長時間,從最開始的一竅不通,到後來的漸漸熟悉,從最開始照貓畫虎的使用YUYV格式之間轉換,到後來使用MJPEG格式讀取,中間頗有周折。趁任務完成間隙,來簡單總結下V4L2的使用。(文章只主要寫了過程,完整程式已經附在最後) 有讀者要問,open

linux通過V4L2驅動USB攝像頭

目錄 前言 在移植羅技C270攝像頭到6818的過程中,核心已經檢測到了USB攝像頭,但是直接用OpenCV的API(比如CvCapture*cvCaptureFromCAM(int index)介面,無法開啟USB攝像頭,至少目前我是這麼認為的。