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文章
593瀏覽量
27397 -
嵌入式技術
+關注
關注
10文章
360瀏覽量
35906 -
USB攝像頭
+關注
關注
0文章
22瀏覽量
11263
發布評論請先 登錄
相關推薦
評論