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

📄 input-v4l.c

📁 spook是一个linux下开源的流媒体服务器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of 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 of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <config.h>#include <sys/types.h>#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <errno.h>#include <pthread.h>#include <sys/mman.h>#include <sys/ioctl.h>#ifdef HAVE_ASM_TYPES_H#include <asm/types.h>#endif#ifdef HAVE_LINUX_COMPILER_H#include <linux/compiler.h>#endif#include <linux/videodev.h>#ifdef HAVE_PWC_IOCTL_H#include <pwc-ioctl.h>#endif#include <event.h>#include <log.h>#include <frame.h>#include <stream.h>#include <inputs.h>#include <conf_parse.h>#define	INPUTTYPE_WEBCAM	1#define INPUTTYPE_NTSC		2#define INPUTTYPE_PAL		3struct v4l_input {	struct stream *output;	struct frame_exchanger *ex;	char device[256];	int width;	int height;	int fincr;	int fbase;	int inputport;	int inputtype;#ifdef HAVE_PWC_IOCTL_H	struct pwc_whitebalance pwc_whitebalance;#endif	int fps;	int fd;	struct video_mbuf vm;	unsigned char *mmap_buf;	int cur_frame;	pthread_t thread;	int running;};static void copy_yuv420p_to_uyvy( unsigned char *dest, unsigned char *src,		int width, int height ){	unsigned char *p, *y, *u, *v;	int r, c;	p = dest;	y = src;	u = y + width * height;	v = u + ( width / 2 ) * ( height / 2 );	for( r = 0; r < height; ++r )		for( c = 0; c < width; c += 2 )		{			*(p++) = u[( r / 2 ) * ( width / 2 ) + ( c / 2 )];			*(p++) = y[r * width + c];			*(p++) = v[( r / 2 ) * ( width / 2 ) + ( c / 2 )];			*(p++) = y[r * width + c + 1];		}}static void *capture_loop( void *d ){	struct v4l_input *conf = (struct v4l_input *)d;	struct video_mmap mm;	struct frame *f;	struct timeval now, start;	int frames = 0, cur_buf, i;	start.tv_sec = 0;	mm.frame = 0;	mm.width = conf->width;	mm.height = conf->height;	mm.format = VIDEO_PALETTE_YUV420P;	if( ioctl( conf->fd, VIDIOCMCAPTURE, &mm ) < 0 )	{		spook_log( SL_ERR, "v4l: aborting on error in VIDIOCMCAPTURE: %s",				strerror( errno ) );		exit( 1 );	}	cur_buf = 1;	for(;;)	{		mm.frame = cur_buf;		mm.width = conf->width;		mm.height = conf->height;		mm.format = VIDEO_PALETTE_YUV420P;		if( ioctl( conf->fd, VIDIOCMCAPTURE, &mm ) < 0 )		{			spook_log( SL_ERR,				"v4l: aborting on error in VIDIOCMCAPTURE: %s",				strerror( errno ) );			exit( 1 );		}		cur_buf = cur_buf ^ 1;		if( ioctl( conf->fd, VIDIOCSYNC, &cur_buf ) < 0 )		{			spook_log( SL_ERR,				"v4l: aborting on error in VIDIOCSYNC: %s",				strerror( errno ) );			exit( 1 );		}		if( conf->fincr == 0 )		{			if( start.tv_sec == 0 )			{				gettimeofday( &start, NULL );				continue;			}			gettimeofday( &now, NULL );			++frames;			if( now.tv_sec >= start.tv_sec + 8 &&					now.tv_usec >= start.tv_usec )			{				i = ( now.tv_sec - start.tv_sec ) * 1000000 +					now.tv_usec - start.tv_usec;				i = ( (double)1000000 * (double)frames					/ (double)i + 0.005 ) * (double)100;				if( i % 100 == 0 )				{					conf->fincr = 1;					conf->fbase = i / 100;				} else if( i % 10 == 0 )				{					conf->fincr = 10;					conf->fbase = i / 10;				} else				{					conf->fincr = 100;					conf->fbase = i;				}				spook_log( SL_INFO, "guessed frame rate at %.2f",					(double)conf->fbase/(double)conf->fincr );				spook_log( SL_DEBUG, "fincr = %d, fbase = %d",						conf->fbase, conf->fincr );				frames = 0;			}			continue;		}		if( ! conf->running )		{			frames = 0;			f = NULL;			continue;		}		++frames;		if( ! ( f = get_next_frame( conf->ex, 0 ) ) )		{			spook_log( SL_WARN, "v4l: dropping frame" );			continue;		}		f->length = conf->width * conf->height * 2;		f->format = FORMAT_RAW_UYVY;		f->width = conf->width;		f->height = conf->height;		f->key = 1;		frames = 0;		copy_yuv420p_to_uyvy( f->d,				conf->mmap_buf + conf->vm.offsets[cur_buf],				f->width, f->height );		deliver_frame( conf->ex, f );	}	return NULL;}static void get_back_frame( struct frame *f, void *d ){	struct v4l_input *conf = (struct v4l_input *)d;	exchange_frame( conf->ex, new_frame() );	deliver_frame_to_stream( f, conf->output );}static int v4l_setup( struct v4l_input *conf ){	struct video_capability vc;	struct video_channel chan;	struct video_picture pict;	struct video_window win;	int i, pwc, real_width, real_height;#ifdef HAVE_PWC_IOCTL_H	struct pwc_probe pwc_probe;#ifdef VIDIOCPWCGREALSIZE	struct pwc_imagesize pwc_imagesize;#endif#endif	conf->cur_frame = -1;	if( ( conf->fd = open( conf->device, O_RDWR ) ) < 0 )	{		spook_log( SL_ERR, "v4l: unable to open %s: %s",				conf->device, strerror( errno ) );		return -1;	}	if( ioctl( conf->fd, VIDIOCGCAP, &vc ) < 0 )	{		spook_log( SL_ERR, "v4l: error determining device capabilities" );		return -1;	}	spook_log( SL_INFO, "v4l: using capture device \"%s\"", vc.name );	if( conf->width > vc.maxwidth )		spook_log( SL_ERR,			"v4l: device supports a maximum frame width of %d; %d is too large",			vc.maxwidth, conf->width );	if( conf->height > vc.maxheight )		spook_log( SL_ERR,			"v4l: device supports a maximum frame height of %d; %d is too large",			vc.maxheight, conf->height );	if( conf->width > vc.maxwidth || conf->height > vc.maxheight )		return -1;#ifdef HAVE_PWC_IOCTL_H	/* This is apparently how we're supposed to probe for PWC devices... */	if( sscanf( vc.name, "Philips %d webcam", &i ) == 1 ||		( ioctl( conf->fd, VIDIOCPWCPROBE, &pwc_probe ) == 0 &&			! strcmp( vc.name, pwc_probe.name ) ) )	{		spook_log( SL_INFO, "v4l: activating support for Philips webcams" );		pwc = 1;	} else#endif		pwc = 0;	if( conf->inputport < 0 || conf->inputport >= vc.channels )	{		spook_log( SL_ERR,			"v4l: input port is invalid!  Valid input ports:" );		for( i = 0; i < vc.channels; ++i )		{			chan.channel = i;			if( ioctl( conf->fd, VIDIOCGCHAN, &chan ) < 0 )			{				spook_log( SL_ERR,					"v4l: error getting info on input port" );				return -1;			}			spook_log( SL_INFO, "v4l: input port %d: %s",					chan.channel, chan.name );		}		return -1;	}	chan.channel = conf->inputport;	switch( conf->inputtype )	{	case INPUTTYPE_NTSC:		chan.norm = VIDEO_MODE_NTSC;		break;	case INPUTTYPE_PAL:		chan.norm = VIDEO_MODE_PAL;		break;	default:		chan.norm = VIDEO_MODE_AUTO;		break;	}	if( ioctl( conf->fd, VIDIOCSCHAN, &chan ) < 0 )	{		spook_log( SL_ERR, "v4l: error selecting input port" );		return -1;	}	if( ioctl( conf->fd, VIDIOCGPICT, &pict ) < 0 )	{		spook_log( SL_ERR, "v4l: error querying palette parameters" );		return -1;	}	pict.palette = VIDEO_PALETTE_YUV420P;	pict.depth = 24;	if( ioctl( conf->fd, VIDIOCSPICT, &pict ) < 0 )	{		spook_log( SL_ERR, "v4l: error setting palette parameters" );		return -1;	}	win.x = win.y = 0;	win.width = conf->width;	win.height = conf->height;	win.chromakey = 0;	win.flags = 0;	win.clips = NULL;	win.clipcount = 0;	if( conf->inputtype == INPUTTYPE_WEBCAM && conf->fps > 0 )	{#ifdef HAVE_PWC_IOCTL_H		if( pwc ) win.flags |= conf->fps << PWC_FPS_SHIFT;		else#endif		{			spook_log( SL_ERR, "v4l: don't know how to set frame rate; try using \"FrameRate auto\"" );			return -1;		}	}		if( ioctl( conf->fd, VIDIOCSWIN, &win ) < 0 )	{		if( conf->inputtype == INPUTTYPE_WEBCAM && conf->fps > 0 )			spook_log( SL_ERR,				"v4l: unable to set requested frame size/frame rate" );		else			spook_log( SL_ERR,				"v4l: unable to set requested frame size" );		return -1;	}	memset( &win, 0, sizeof( win ) );	if( ioctl( conf->fd, VIDIOCGWIN, &win ) < 0 )	{

⌨️ 快捷键说明

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