⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 msv4l2.c

📁 基于osip、eXosip、speex、ffmpeg的VoIP源代码
💻 C
字号:
/*mediastreamer2 library - modular sound and video processing and streamingCopyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.*/#include "mediastreamer-config.h"#ifdef HAVE_LINUX_VIDEODEV2_H#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/ioctl.h>#include <errno.h>#include <string.h>#include <sys/mman.h>#include <poll.h>#include <linux/videodev2.h>#include "mediastreamer2/msvideo.h"#include "mediastreamer2/msticker.h"#include "mediastreamer2/mswebcam.h"typedef struct V4l2State{	int fd;	char *dev;	char *mmapdbuf;	int msize;/*mmapped size*/	MSVideoSize vsize;	MSVideoSize got_vsize;	int pix_fmt;	int int_pix_fmt; /*internal pixel format */	mblk_t *frames[VIDEO_MAX_FRAME];	int frame_ind;	int frame_max;	float fps;	float start_time;	int frame_count;	int queued;	bool_t run;}V4l2State;static int v4l2_open(V4l2State *s){	int fd=open(s->dev,O_RDWR|O_NONBLOCK);	if (fd==-1){		ms_error("Could not open %s: %s",s->dev,strerror(errno));		return -1;	}	s->fd=fd;	return 0;}static int v4l2_close(V4l2State *s){	if (s->fd!=-1){		close(s->fd);		s->fd=-1;	}	return 0;}static bool_t v4lv2_try_format(V4l2State *s, int fmtid){	struct v4l2_format fmt;	memset(&fmt,0,sizeof(fmt));	fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;	fmt.fmt.pix.width       = s->vsize.width; 	fmt.fmt.pix.height      = s->vsize.height;	fmt.fmt.pix.pixelformat = fmtid;	fmt.fmt.pix.field = V4L2_FIELD_ANY;        if (ioctl (s->fd, VIDIOC_S_FMT, &fmt)<0){		return FALSE;	}	return TRUE;}static int v4l2_configure(V4l2State *s){	struct v4l2_capability cap;	struct v4l2_format fmt;        if (ioctl (s->fd, VIDIOC_QUERYCAP, &cap)<0) {		ms_message("Not a v4lv2 driver.");		return -1;        }        if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {		ms_error("%s is not a video capture device\n",s->dev);		return -1;        }	if (!(cap.capabilities & V4L2_CAP_STREAMING)) {		ms_error("%s does not support streaming i/o\n",s->dev);		return -1;	}	if (v4lv2_try_format(s,V4L2_PIX_FMT_YUV420)){		s->pix_fmt=MS_YUV420P;		s->int_pix_fmt=V4L2_PIX_FMT_YUV420;		ms_message("v4lv2: YUV420P choosen");	}else if (v4lv2_try_format(s,V4L2_PIX_FMT_NV12)){		s->pix_fmt=MS_YUV420P;		s->int_pix_fmt=V4L2_PIX_FMT_NV12;		ms_message("v4lv2: V4L2_PIX_FMT_NV12 choosen");	}else if (v4lv2_try_format(s,V4L2_PIX_FMT_MJPEG)){		s->pix_fmt=MS_MJPEG;		s->int_pix_fmt=V4L2_PIX_FMT_MJPEG;		ms_message("v4lv2: MJPEG choosen");	}else if (v4lv2_try_format(s,V4L2_PIX_FMT_YUYV)){		s->pix_fmt=MS_YUYV;		s->int_pix_fmt=V4L2_PIX_FMT_YUYV;		ms_message("v4lv2: V4L2_PIX_FMT_YUYV choosen");	}else if (v4lv2_try_format(s,V4L2_PIX_FMT_RGB24)){		s->pix_fmt=MS_RGB24;		s->int_pix_fmt=V4L2_PIX_FMT_RGB24;		ms_message("v4lv2: RGB24 choosen");	}else{		ms_error("Could not find supported pixel format.");		return -1;	}	memset(&fmt,0,sizeof(fmt));	fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;        if (ioctl (s->fd, VIDIOC_G_FMT, &fmt)<0){		ms_error("VIDIOC_G_FMT failed: %s",strerror(errno));	}else{		ms_message("Size of picture is %ix%i",fmt.fmt.pix.width,fmt.fmt.pix.height);	}	return 0;}static int v4l2_do_mmap(V4l2State *s){	struct v4l2_requestbuffers req;	int i;	enum v4l2_buf_type type;		memset(&req,0,sizeof(req));		req.count               = 4;	req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;	req.memory              = V4L2_MEMORY_MMAP;		if (ioctl (s->fd, VIDIOC_REQBUFS, &req)<0) {		ms_error("Error requesting info on mmap'd buffers: %s",strerror(errno));		return -1;	}		for (i=0; i<req.count; ++i) {		struct v4l2_buffer buf;		mblk_t *msg;		void *start;		memset(&buf,0,sizeof(buf));			buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;		buf.memory=V4L2_MEMORY_MMAP;		buf.index=i;			if (ioctl (s->fd, VIDIOC_QUERYBUF, &buf)<0){			ms_error("Could not VIDIOC_QUERYBUF : %s",strerror(errno));			return -1;		}				start=mmap (NULL /* start anywhere */,			buf.length,			PROT_READ | PROT_WRITE /* required */,			MAP_SHARED /* recommended */,			s->fd, buf.m.offset);			if (start==NULL){			ms_error("Could not mmap: %s",strerror(errno));		}		msg=esballoc(start,buf.length,0,NULL);		msg->b_wptr+=buf.length;		s->frames[i]=msg;	}	s->frame_max=req.count;	/*	for (i = 0; i < s->frame_max; ++i) {		struct v4l2_buffer buf;		memset(&buf,0,sizeof(buf));		buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;		buf.memory      = V4L2_MEMORY_MMAP;		buf.index       = i;		if (-1==ioctl (s->fd, VIDIOC_QBUF, &buf)){			ms_error("VIDIOC_QBUF failed: %s",strerror(errno));		}	}	*/	/*start capture immediately*/	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	if (-1 ==ioctl (s->fd, VIDIOC_STREAMON, &type)){		ms_error("VIDIOC_STREAMON failed: %s",strerror(errno));		return -1;	}	return 0;}static mblk_t * v4lv2_grab_image(V4l2State *s){	struct v4l2_buffer buf;	unsigned int k;	memset(&buf,0,sizeof(buf));	mblk_t *ret=NULL;	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	buf.memory = V4L2_MEMORY_MMAP;		/*queue buffers whose ref count is 1, because they are not	still used anywhere in the filter chain */	for(k=0;k<s->frame_max;++k){		if (s->frames[k]->b_datap->db_ref==1){			buf.index=k;			if (-1==ioctl (s->fd, VIDIOC_QBUF, &buf))				ms_warning("VIDIOC_QBUF %i failed: %s",k,  strerror(errno));			else {				ms_debug("v4l2: queue buf %i",k);				/*increment ref count of queued buffer*/				s->frames[k]->b_datap->db_ref++;				s->queued++;			}		}	}	if (s->queued){		struct pollfd fds;		memset(&fds,0,sizeof(fds));		fds.events=POLLIN;		fds.fd=s->fd;		/*check with poll if there is something to read */		if (poll(&fds,1,0)==1 && fds.revents==POLLIN){			if (ioctl(s->fd, VIDIOC_DQBUF, &buf)<0) {				switch (errno) {				case EAGAIN:				case EIO:					/* Could ignore EIO, see spec. */					break;				default:					ms_warning("VIDIOC_DQBUF failed: %s",strerror(errno));				}			}else{				s->queued--;				ms_debug("v4l2: de-queue buf %i",buf.index);				/*decrement ref count of dequeued buffer */				ret=s->frames[buf.index];				ret->b_datap->db_ref--;				if (buf.index >= s->frame_max){					ms_error("buf.index>=s->max_frames !");					return NULL;				}				if (buf.bytesused<=30){					ms_warning("Ignoring empty buffer...");					return NULL;				}				ret->b_wptr=ret->b_rptr+buf.bytesused;			}		}	}	return ret;}static void v4l2_do_munmap(V4l2State *s){	int i;	enum v4l2_buf_type type;	/*stop capture immediately*/	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	if (-1 ==ioctl (s->fd, VIDIOC_STREAMOFF, &type)){		ms_error("VIDIOC_STREAMOFF failed: %s",strerror(errno));	}	for(i=0;i<s->frame_max;++i){		mblk_t *msg=s->frames[i];		int len=msg->b_datap->db_lim-msg->b_datap->db_base;		if (munmap(msg->b_datap->db_base,len)<0){			ms_warning("MSV4l2: Fail to unmap: %s",strerror(errno));		}		freemsg(s->frames[i]);		s->frames[i]=NULL;	}}static void v4l2_init(MSFilter *f){	V4l2State *s=ms_new0(V4l2State,1);	s->dev=ms_strdup("/dev/video0");	s->fd=-1;	s->vsize=MS_VIDEO_SIZE_CIF;	s->fps=15;	f->data=s;}static void v4l2_uninit(MSFilter *f){	V4l2State *s=(V4l2State*)f->data;	ms_free(s->dev);	ms_free(s);}static void v4l2_process(MSFilter *f){	V4l2State *s=(V4l2State*)f->data;	uint32_t elapsed;	if (s->fd==-1){		if (v4l2_open(s)==0 && v4l2_configure(s)==0 && v4l2_do_mmap(s)==0){			ms_message("V4L2 video capture started.");		}else{			v4l2_close(s);		}		s->start_time=f->ticker->time;	}	if (s->fd!=-1){		/*see it is necessary to output a frame:*/		elapsed=f->ticker->time-s->start_time;		if (((float)elapsed*s->fps/1000.0)>s->frame_count){			mblk_t *m;			m=v4lv2_grab_image(s);			if (m){				mblk_t *om=dupb(m);				mblk_set_marker_info(om,(s->pix_fmt==MS_MJPEG));				ms_queue_put(f->outputs[0],om);				s->frame_count++;			}		}	}}static void v4l2_postprocess(MSFilter *f){	V4l2State *s=(V4l2State*)f->data;	if (s->fd!=-1){		v4l2_do_munmap(s);		v4l2_close(s);	}}static int v4l2_set_fps(MSFilter *f, void *arg){	V4l2State *s=(V4l2State*)f->data;	s->fps=*(float*)arg;	return 0;}static int v4l2_set_vsize(MSFilter *f, void *arg){	V4l2State *s=(V4l2State*)f->data;	s->vsize=*(MSVideoSize*)arg;	return 0;}static int v4l2_get_vsize(MSFilter *f, void *arg){	V4l2State *s=(V4l2State*)f->data;	*(MSVideoSize*)arg=s->vsize;	return 0;}static int v4l2_get_pixfmt(MSFilter *f, void *arg){	V4l2State *s=(V4l2State*)f->data;	if (s->fd==-1){		if (v4l2_open(s)==0){			v4l2_configure(s);			*(MSPixFmt*)arg=s->pix_fmt;			v4l2_close(s);			return 0;		}else return -1;	}	*(MSPixFmt*)arg=s->pix_fmt;	return 0;}static int v4l2_set_devfile(MSFilter *f, void *arg){	V4l2State *s=(V4l2State*)f->data;	if (s->dev) ms_free(s->dev);	s->dev=ms_strdup((char*)arg);	return 0;}static MSFilterMethod v4l2_methods[]={	{	MS_FILTER_SET_FPS	,	v4l2_set_fps	},	{	MS_FILTER_SET_VIDEO_SIZE,	v4l2_set_vsize	},	{	MS_FILTER_GET_VIDEO_SIZE,	v4l2_get_vsize	},	{	MS_FILTER_GET_PIX_FMT	,	v4l2_get_pixfmt	},	{	0			,	NULL		}};MSFilterDesc ms_v4l2_desc={	.id=MS_V4L2_CAPTURE_ID,	.name="MSV4L2Capture",	.text="A filter to grab pictures from Video4Linux2-powered cameras",	.category=MS_FILTER_OTHER,	.ninputs=0,	.noutputs=1,	.init=v4l2_init,	.process=v4l2_process,	.postprocess=v4l2_postprocess,	.uninit=v4l2_uninit,	.methods=v4l2_methods};MS_FILTER_DESC_EXPORT(ms_v4l2_desc)static MSFilter *v4l2_create_reader(MSWebCam *obj){	MSFilter *f=ms_filter_new(MS_V4L2_CAPTURE_ID);	v4l2_set_devfile(f,obj->name);	return f;}static void v4l2_detect(MSWebCamManager *obj);static void v4l2_cam_init(MSWebCam *cam){}MSWebCamDesc v4l2_desc={	"V4L2",	&v4l2_detect,	&v4l2_cam_init,	&v4l2_create_reader,	NULL};static void v4l2_detect(MSWebCamManager *obj){	struct v4l2_capability cap;	char devname[32];	int i;	for(i=0;i<10;++i){		int fd;		snprintf(devname,sizeof(devname),"/dev/video%i",i);		fd=open(devname,O_RDWR);		if (fd!=-1){			if (ioctl (fd, VIDIOC_QUERYCAP, &cap)==0) {				/* is a V4LV2 */				MSWebCam *cam=ms_web_cam_new(&v4l2_desc);				cam->name=ms_strdup(devname);				ms_web_cam_manager_add_cam(obj,cam);			}			close(fd);		}	}}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -