1.攝像頭框架編程步驟
(1)打開攝像頭設備(/dev/video0 、/dev/video1 );
(2)設置圖像格式:VIDIOC_S_FMT(視頻捕獲格式、圖像顏色數據格式、圖像寬和高);
(3)申請緩沖區:VIDIOC_REQBUFS(緩沖區數量、緩沖映射方式、視頻捕獲格式);
(4)將緩沖區映射到進程空間:VIDIOC_QUERYBUF(要映射的緩沖區下標、緩沖映射方式、視頻捕獲格式);
(5)將緩沖區添加到隊列中:VIDIOC_QBUF(映射的緩沖區下標、緩沖映射方式、視頻捕獲格式);
(6)開啟攝像頭采集:VIDIOC_STREAMON (視頻捕獲格式) (7)從采集隊列中取出圖像數據,通過SDL圖像渲染;
2.攝像頭v4L2框架應用編程示例
#include #include #include #include #include struct video { int width;//攝像頭采集圖像寬 int height;//攝像頭采集圖像高 char *mmapbuf[4];//保存映射的地址 int mmap_size;/*映射緩沖區大小*/ }; /*攝像頭應用編程框架*/ int Video_Init(u8 *dev,int video_fd,struct video *video_info) { /*1.打開攝像設備文件*/ video_fd=open(dev,O_RDWR); if(video_fd<0)return -1; /*2.圖像數據格式*/ struct v4l2_format video_format; memset(&video_format,0,sizeof(struct v4l2_format)); video_format.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//捕獲格式 video_format.fmt.pix.width=1920; video_format.fmt.pix.height=1080; video_format.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV; if(ioctl(video_fd,VIDIOC_S_FMT,&video_format))return -2; video_info->width=video_format.fmt.pix.width; video_info->height=video_format.fmt.pix.height; printf("圖像尺寸:%d * %dn",video_info->width,video_info->height); /*3.申請空間*/ struct v4l2_requestbuffers video_requestbuffers; memset(&video_requestbuffers,0,sizeof(struct v4l2_requestbuffers)); video_requestbuffers.count=4;//緩沖區個數 video_requestbuffers.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//V4L2捕獲框架格式 video_requestbuffers.memory=V4L2_MEMORY_MMAP;//內存映射 if(ioctl(video_fd,VIDIOC_REQBUFS,&video_requestbuffers))return -3; printf("緩沖區個數:%dn",video_requestbuffers.count); /*4.將緩沖映射到進程空間*/ int i=0; struct v4l2_buffer video_buffer; for(i=0;immap_size=video_buffer.length;/*映射大小*/ video_info->mmapbuf[i]=mmap(NULL,video_buffer.length,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,video_buffer.m.offset); } /*5.將緩沖區添加到采集隊列*/ for(i=0;i
3.攝像頭采集圖像處理線程
/*線程清理函數*/ void pth_routine(void *arg) { /*關閉攝像頭*/ free(arg); pthread_mutex_lock(&fastmutex);//互斥鎖上鎖 pthread_cond_broadcast(&cond);//廣播喚醒所有線程 pthread_mutex_unlock(&fastmutex);//互斥鎖解鎖 video_flag=0; printf("資源清理完成n"); } /*攝像頭處理線程*/ void *Video_CollectImage(void *arg) { u8 *rgb=malloc(video_info.height*video_info.width*3);//申請圖像數據緩沖區 if(rgb==NULL) { pthread_exit(NULL);/*結束線程*/ } pthread_cleanup_push(pth_routine,rgb); struct pollfd fds; fds.fd=video_fd;//監聽攝像頭描述符 fds.events=POLLIN;//讀事件 fds.revents=0; struct v4l2_buffer video_buff; while(video_flag) { poll(&fds,1,-1); /*1.從隊列中取數據*/ memset(&video_buff,0,sizeof(struct v4l2_buffer)); video_buff.memory=V4L2_MEMORY_MMAP;//內存映射 video_buff.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//V4L2視頻捕獲 if(ioctl(video_fd,VIDIOC_DQBUF,&video_buff))break; /*yuv轉RGB*/ yuv_to_rgb(video_info.mmapbuf[video_buff.index],rgb,video_info.width,video_info.height);//顏色數據轉換 pthread_mutex_lock(&fastmutex);//互斥鎖上鎖 memcpy(rgb_buff,rgb,video_info.height*video_info.width*3); pthread_cond_broadcast(&cond);//廣播喚醒所有線程 pthread_mutex_unlock(&fastmutex);//互斥鎖解鎖 /*3.將緩沖區添加到隊列*/ if(ioctl(video_fd,VIDIOC_QBUF,&video_buff))break; } pthread_cleanup_pop(1);/*注銷清理函數*/ }
4.YUYV(YUV422)轉RGB888
/*YUYV轉RGB888*/ void yuv_to_rgb(unsigned char *yuv_buffer,unsigned char *rgb_buffer,int iWidth,int iHeight) { int x; int z=0; unsigned char *ptr = rgb_buffer; unsigned char *yuyv= yuv_buffer; for (x = 0; x < iWidth*iHeight; x++) { int r, g, b; int y, u, v; if (!z) y = yuyv[0] << 8; else y = yuyv[2] << 8; u = yuyv[1] - 128; v = yuyv[3] - 128; b = (y + (359 * v)) >> 8; g = (y - (88 * u) - (183 * v)) >> 8; r = (y + (454 * u)) >> 8; *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r); if(z++) { z = 0; yuyv += 4; } } }
5.主函數main.c
#include #include #include #include #include #include #include #include #include "video.h" #define CAMERA_DEV "/dev/video0" //攝像頭設備節點 int video_fd;/*攝像頭描述符*/ struct video video_info;/*攝像頭結構體信息*/ void *Video_CollectImage(void *arg);/*攝像頭圖像采集*/ u8 *rgb_buff=NULL; u8 video_flag=1; pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;//互斥鎖 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//條件變量 typedef enum { false=0, true, }bool; int main() { /*初始化攝像頭*/ video_fd=Video_Init(CAMERA_DEV,video_fd,&video_info); if(video_fd<=0) { printf("攝像頭初始化失敗,res=%dn",video_fd); return 0; } /*創建窗口 */ SDL_Window *window=SDL_CreateWindow("SDL_VIDEO", SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,800,480,SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_RESIZABLE); /*創建渲染器*/ SDL_Renderer *render=SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED); /*清空渲染器*/ SDL_RenderClear(render); printf("圖像尺寸:%d * %dn",video_info.width,video_info.height); /*創建紋理*/ SDL_Texture*sdltext=SDL_CreateTexture(render,SDL_PIXELFORMAT_RGB24,SDL_TEXTUREACCESS_STREAMING,video_info.width,video_info.height); /*創建攝像頭采集線程*/ u8 *rgb_data=malloc(video_info.height*video_info.width*3); rgb_buff=malloc(video_info.height*video_info.width*3);//保存RGB顏色數據 //printf("size=%dn",video_info.mmap_size); video_flag=1;/*攝像頭采集標志*/ pthread_t pthid; pthread_create(&pthid,NULL,Video_CollectImage, NULL); bool quit=true; SDL_Event event; SDL_Rect rect; while(quit) { while(SDL_PollEvent(&event))/*事件監測*/ { if(event.type==SDL_QUIT)/*退出事件*/ { quit=false; video_flag=0; pthread_cancel(pthid);/*殺死指定線程*/ continue; } } if(!video_flag) { quit=false; continue; } pthread_mutex_lock(&fastmutex);//互斥鎖上鎖 pthread_cond_wait(&cond,&fastmutex); memcpy(rgb_data,rgb_buff,video_info.height*video_info.width*3); pthread_mutex_unlock(&fastmutex);//互斥鎖解鎖 SDL_UpdateTexture(sdltext,NULL,rgb_data, video_info.width*3); //SDL_RenderCopy(render, sdltext, NULL,NULL); // 拷貝紋理到渲染器 SDL_RenderCopyEx(render, sdltext,NULL,NULL,0,NULL,SDL_FLIP_NONE); SDL_RenderPresent(render); // 渲染 } SDL_DestroyTexture(sdltext);/*銷毀紋理*/ SDL_DestroyRenderer(render);/*銷毀渲染器*/ SDL_DestroyWindow(window);/*銷毀窗口 */ SDL_Quit();/*關閉SDL*/ pthread_mutex_destroy(&fastmutex);/*銷毀互斥鎖*/ pthread_cond_destroy(&cond);/*銷毀條件變量*/ free(rgb_buff); free(rgb_data); }
6.運行效果
審核編輯:劉清
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
Linux系統
+關注
關注
4文章
567瀏覽量
26926 -
嵌入式技術
+關注
關注
10文章
349瀏覽量
34283 -
USB攝像頭
+關注
關注
0文章
22瀏覽量
11191
發布評論請先 登錄
相關推薦
全志D1-H開發板USB攝像頭拍照Demo
庫如:FFmpeg和OpenCV對V4L2均支持。
本例就使用V4L2庫完成攝像頭對圖片的捕捉,并將其保存為一張圖片。
依照Tina SKD
發表于 03-04 10:48
如何在Raspberry Pi(樹莓派)上調用V4L2來操縱攝像頭拍照
如何在Raspberry Pi(樹莓派)上調用V4L2來操縱攝像頭拍照簡單地說,它就是一個基于ARM CPU的、信用卡那么大的迷你計算機。我曾經寫過一篇教程,展示了如何調用OpenCV,來控制攝像頭
發表于 06-30 21:39
【WRTnode2R試用體驗】使用V4L2獲取攝像頭的信息
V4L2全稱是Video for Linux 2,通過它可以驅動攝像頭。在Ubuntu中,已經內置了V4L2,因此不需要安裝多余的東西。在W
發表于 10-26 20:36
CSI攝像頭接口及在英創主板上的應用
加載相應的驅動,加載驅動后會自動生成設備節點:“/dev/video0",應用程序可以操作該設備節點對攝像頭進行圖像的采集和控制?! SI攝像頭都是用了V4L2驅動提供的標準API來操作
發表于 10-20 13:36
【100ASK_IMX6ULL(帶屏) 開發板試用體驗】基于samba v4l2庫和libjpeg遠程攝像頭圖像讀取
100ms,這個效率對于網絡監控行業來說完全沒法達到及格水準,但是對于IMX6ULL這樣性能入門的主控來說是這樣的了。使用v4l2庫進行攝像頭圖像采集的代碼之前已經放出過了,今天放調用
發表于 11-07 16:33
香橙派OrangePi PC Plus開發板連接5MP攝像頭測試
排線接到開發板的 CIS 攝像頭接口上,接好攝 像頭后再啟動 linux 系統(不要在上電后再插入攝像頭)3) 進入系統后查看下 ov5640 4
發表于 05-20 15:34
全志H3芯片香橙派OrangePi PC開發板連接USB攝像頭測試說明
v4l2 中的 l 是小寫字母 l,不是數字 1)命令查看下 USB 攝像頭的設備節點,從下面的輸出可知
發表于 06-08 11:34
全志H2芯片香橙派Zero開發板連接USB攝像頭的使用方法
使用 lsmod 查看系統是否自動加載了 uvcvideo 內核模塊3) 然后通過 v4l2-ctl(注意 v4l2 中的 l 是小寫字母 l,不是數字 1)命令查看下
發表于 10-28 17:23
全志H5芯片開發板香橙派PC2在Linux系統下連接USB攝像頭的使用方法
v4l2 中的 l 是小寫字母 l,不是數字 1)命令查看下 USB 攝像頭的設備節點,從下面的輸出可知
發表于 11-16 11:41
【觸覺智能 IDO-SBC2D06-V1B-12W開發板試用】USB接口UVC攝像頭
識別到了攝像頭,說明系統自帶了UVC驅動:可見生成了/dev/video0節點。V4L2是Video for linux2的簡稱,為linux中關于視頻設備的內核驅動。在
發表于 12-12 20:38
運行linuxtv官網的v4l2代碼,capture攝像頭時select超時怎么解決?
編譯,運行linuxtv官網的v4l2代碼,capture 攝像頭時select超時,這怎么搞?
發表于 12-31 06:12
運行linuxtv官網的v4l2代碼,capture攝像頭時select超時怎么解決?
[td]編譯,運行linuxtv官網的v4l2代碼,capture 攝像頭時select超時,這怎么搞?
發表于 01-14 07:02
如何在OKMX6UL-C上利用攝像頭做圖像采集呢
攝像頭進行圖像采集,大體的框架是什么? 底層驅動和頂層程序顯示需要做些什么?3. 需要用到v4l2、OpenCV等這些程序嗎?不了解利用攝像頭進行圖像采集的過程,感謝各位大神指教
發表于 12-02 06:49
評論