0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

Linux下V4L2框架基于SDL庫本地USB攝像頭監(jiān)控

嵌入式技術 ? 來源:嵌入式技術 ? 作者:嵌入式技術 ? 2022-12-17 15:37 ? 次閱讀

1.攝像頭框架編程步驟

(1)打開攝像頭設備(/dev/video0 、/dev/video1 );

(2)設置圖像格式:VIDIOC_S_FMT(視頻捕獲格式、圖像顏色數(shù)據(jù)格式、圖像寬和高);

(3)申請緩沖區(qū):VIDIOC_REQBUFS(緩沖區(qū)數(shù)量、緩沖映射方式、視頻捕獲格式);

(4)將緩沖區(qū)映射到進程空間:VIDIOC_QUERYBUF(要映射的緩沖區(qū)下標、緩沖映射方式、視頻捕獲格式);

(5)將緩沖區(qū)添加到隊列中:VIDIOC_QBUF(映射的緩沖區(qū)下標、緩沖映射方式、視頻捕獲格式);

(6)開啟攝像頭采集:VIDIOC_STREAMON (視頻捕獲格式) (7)從采集隊列中取出圖像數(shù)據(jù),通過SDL圖像渲染;

2.攝像頭v4L2框架應用編程示例

#include 
#include 
#include 
#include 
#include 
struct video
{
	int width;//攝像頭采集圖像寬
	int height;//攝像頭采集圖像高
	char *mmapbuf[4];//保存映射的地址
	int mmap_size;/*映射緩沖區(qū)大小*/
};
/*攝像頭應用編程框架*/
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.圖像數(shù)據(jù)格式*/
	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;//緩沖區(qū)個數(shù)
	video_requestbuffers.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//V4L2捕獲框架格式
	video_requestbuffers.memory=V4L2_MEMORY_MMAP;//內(nèi)存映射
	if(ioctl(video_fd,VIDIOC_REQBUFS,&video_requestbuffers))return -3;
	printf("緩沖區(qū)個數(shù):%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.將緩沖區(qū)添加到采集隊列*/
	for(i=0;i

3.攝像頭采集圖像處理線程

/*線程清理函數(shù)*/
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);//申請圖像數(shù)據(jù)緩沖區(qū)
	if(rgb==NULL)
	{
		pthread_exit(NULL);/*結束線程*/
	}
	pthread_cleanup_push(pth_routine,rgb);
	struct pollfd fds;
	fds.fd=video_fd;//監(jiān)聽攝像頭描述符
	fds.events=POLLIN;//讀事件
	fds.revents=0;
	struct v4l2_buffer video_buff;
	while(video_flag)
	{
		poll(&fds,1,-1);
		/*1.從隊列中取數(shù)據(jù)*/
		memset(&video_buff,0,sizeof(struct v4l2_buffer));
		video_buff.memory=V4L2_MEMORY_MMAP;//內(nèi)存映射
		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);//顏色數(shù)據(jù)轉換
        pthread_mutex_lock(&fastmutex);//互斥鎖上鎖
        memcpy(rgb_buff,rgb,video_info.height*video_info.width*3);
        pthread_cond_broadcast(&cond);//廣播喚醒所有線程
        pthread_mutex_unlock(&fastmutex);//互斥鎖解鎖
		/*3.將緩沖區(qū)添加到隊列*/
		if(ioctl(video_fd,VIDIOC_QBUF,&video_buff))break;
	}
	pthread_cleanup_pop(1);/*注銷清理函數(shù)*/
}

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.主函數(shù)main.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "video.h"

#define CAMERA_DEV "/dev/video0" //攝像頭設備節(jié)點
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;
    }    
    /*創(chuàng)建窗口 */
	SDL_Window *window=SDL_CreateWindow("SDL_VIDEO", SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,800,480,SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_RESIZABLE);
    /*創(chuàng)建渲染器*/
	SDL_Renderer *render=SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
	/*清空渲染器*/
	SDL_RenderClear(render);
    printf("圖像尺寸:%d * %dn",video_info.width,video_info.height);
    /*創(chuàng)建紋理*/
	SDL_Texture*sdltext=SDL_CreateTexture(render,SDL_PIXELFORMAT_RGB24,SDL_TEXTUREACCESS_STREAMING,video_info.width,video_info.height);
    /*創(chuàng)建攝像頭采集線程*/
    u8 *rgb_data=malloc(video_info.height*video_info.width*3);
    rgb_buff=malloc(video_info.height*video_info.width*3);//保存RGB顏色數(shù)據(jù)
   //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))/*事件監(jiān)測*/
		{
			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.運行效果

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center








審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Linux系統(tǒng)

    關注

    4

    文章

    590

    瀏覽量

    27315
  • 嵌入式技術
    +關注

    關注

    10

    文章

    360

    瀏覽量

    35518
  • USB攝像頭
    +關注

    關注

    0

    文章

    22

    瀏覽量

    11250
收藏 人收藏

    評論

    相關推薦

    Linux攝像頭應用編程

    V4L2是Video for linux2的簡稱,為linux中關于視頻設備的內(nèi)核驅(qū)動。在Linux中,視頻設備是設備文件,可以像訪問普通文件一樣對其進行讀寫,
    的頭像 發(fā)表于 08-26 21:39 ?2769次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>下</b><b class='flag-5'>攝像頭</b>應用編程

    百問網(wǎng)全志系列開發(fā)板攝像頭V4L2編程步驟詳解

    7 攝像頭V4L2編程 7.1 V4L2簡介 ?Video for Linux two(Video4Linux2)簡稱
    發(fā)表于 08-13 09:45

    如何在Raspberry Pi(樹莓派)上調(diào)用V4L2來操縱攝像頭拍照

    如何在Raspberry Pi(樹莓派)上調(diào)用V4L2來操縱攝像頭拍照簡單地說,它就是一個基于ARM CPU的、信用卡那么大的迷你計算機。我曾經(jīng)寫過一篇教程,展示了如何調(diào)用OpenCV,來控制攝像頭
    發(fā)表于 06-30 21:39

    【W(wǎng)RTnode2R試用體驗】使用V4L2獲取攝像頭的信息

    V4L2全稱是Video for Linux 2,通過它可以驅(qū)動攝像頭。在Ubuntu中,已經(jīng)內(nèi)置了V4L2,因此不需要安裝多余的東西。在W
    發(fā)表于 10-26 20:36

    【100ASK_IMX6ULL(帶屏) 開發(fā)板試用體驗】基于samba v4l2和libjpeg遠程攝像頭圖像讀取

    100ms,這個效率對于網(wǎng)絡監(jiān)控行業(yè)來說完全沒法達到及格水準,但是對于IMX6ULL這樣性能入門的主控來說是這樣的了。使用v4l2進行攝像頭圖像采集的代碼之前已經(jīng)放出過了,今天放調(diào)用
    發(fā)表于 11-07 16:33

    全志H2芯片香橙派Zero開發(fā)板連接USB攝像頭的使用方法

    使用 lsmod 查看系統(tǒng)是否自動加載了 uvcvideo 內(nèi)核模塊3) 然后通過 v4l2-ctl(注意 v4l2 中的 l 是小寫字母 l,不是數(shù)字 1)命令查看下
    發(fā)表于 10-28 17:23

    全志H5芯片開發(fā)板香橙派PC2Linux系統(tǒng)連接USB攝像頭的使用方法

    v4l2 中的 l 是小寫字母 l,不是數(shù)字 1)命令查看下 USB 攝像頭的設備節(jié)點,從下面的輸出可知
    發(fā)表于 11-16 11:41

    運行l(wèi)inuxtv官網(wǎng)的v4l2代碼,capture攝像頭時select超時怎么解決?

    編譯,運行l(wèi)inuxtv官網(wǎng)的v4l2代碼,capture 攝像頭時select超時,這怎么搞?
    發(fā)表于 12-31 06:12

    運行l(wèi)inuxtv官網(wǎng)的v4l2代碼,capture攝像頭時select超時怎么解決?

    [td]編譯,運行l(wèi)inuxtv官網(wǎng)的v4l2代碼,capture 攝像頭時select超時,這怎么搞?
    發(fā)表于 01-14 07:02

    什么是V4L2?有何作用

    1.什么是V4L2Video for(4) Linux 2 的簡稱,V4L的升級版。V4L2
    發(fā)表于 01-17 09:05

    需要了解Linux V4L2的驅(qū)動架構

    video4linux2(V4L2)是Linux內(nèi)核中關于視頻設備的中間驅(qū)動層,向上為Linux應用程序訪問視頻設備提供了通用接口,向下為linux
    發(fā)表于 04-28 17:29 ?1101次閱讀
    需要了解<b class='flag-5'>Linux</b> <b class='flag-5'>V4L2</b>的驅(qū)動架構

    Linux應用開發(fā)【第七章】攝像頭V4L2編程應用開發(fā)

    文章目錄 7 攝像頭V4L2編程應用開發(fā) 7.1 V4L2簡介 7.2 V4L2視頻采集原理 7.3 V4L2程序?qū)崿F(xiàn)流程 7.4
    的頭像 發(fā)表于 12-10 19:23 ?3032次閱讀
    <b class='flag-5'>Linux</b>應用開發(fā)【第七章】<b class='flag-5'>攝像頭</b><b class='flag-5'>V4L2</b>編程應用開發(fā)

    V4L2學習筆記

    1.什么是V4L2Video for(4) Linux 2 的簡稱,V4L的升級版。V4L2
    發(fā)表于 01-17 13:43 ?12次下載
    <b class='flag-5'>V4L2</b>學習筆記

    如何使用v4l2 API讀取攝像頭

    V4L2是Video For Linux的第二個版本,它是Linux的視頻捕獲的API。在這里,您可以找到有關的文檔。它提供了很方便的c,c++和python接口
    發(fā)表于 02-07 11:16 ?4次下載
    如何使用<b class='flag-5'>v4l2</b> API讀取<b class='flag-5'>攝像頭</b>

    Linux開發(fā)_攝像頭編程(實現(xiàn)拍照功能)

    這篇文章主要介紹LinuxUVC免驅(qū)攝像頭操作流程,介紹V4L2框架、完成攝像頭拍照保存為BM
    的頭像 發(fā)表于 09-17 15:34 ?1760次閱讀