[asterisk-commits] rizzo: branch rizzo/astobj2 r77314 - /team/rizzo/astobj2/channels/chan_oss.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Jul 26 11:34:56 CDT 2007


Author: rizzo
Date: Thu Jul 26 11:34:55 2007
New Revision: 77314

URL: http://svn.digium.com/view/asterisk?view=rev&rev=77314
Log:
more webcam/video bits.
Add code to open a v4l device and read from it,
plus some debugging code to show various info
(when a frame is ready, its size, and so on).
All what's missing now it the call to the encoding
routines, and possibly a secondary SDL window for
the local stream.

Modified:
    team/rizzo/astobj2/channels/chan_oss.c

Modified: team/rizzo/astobj2/channels/chan_oss.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/channels/chan_oss.c?view=diff&rev=77314&r1=77313&r2=77314
==============================================================================
--- team/rizzo/astobj2/channels/chan_oss.c (original)
+++ team/rizzo/astobj2/channels/chan_oss.c Thu Jul 26 11:34:55 2007
@@ -42,6 +42,7 @@
  * experimental support to decode a video session.
  */
 //#define DROP_PACKETS	5	// if set, simulate this percentage of lost video packets
+#define HAVE_V4L	1
 #define HAVE_SDL	1
 #define HAVE_FFMPEG	1
 
@@ -84,13 +85,6 @@
 #include "asterisk/musiconhold.h"
 #include "asterisk/app.h"
 
-#if HAVE_FFMPEG
-#include <ffmpeg/avcodec.h>
-#endif
-#if HAVE_SDL
-#include <SDL/SDL.h>
-#endif
-
 /* ringtones we use */
 #include "busy.h"
 #include "ringtone.h"
@@ -327,6 +321,9 @@
  * Examples for video encoding are at
 http://www.irisa.fr/texmex/people/dufouil/ffmpegdoxy/apiexample_8c-source.html
  */
+
+#include <ffmpeg/avcodec.h>
+#include <SDL/SDL.h>
 
 /* Structures for ffmpeg processing */
 /*
@@ -350,6 +347,19 @@
 	int received;
 
 	struct ast_frame *echo;
+
+	/* webcam support.
+	 * videodevice and geometry are read from the config file.
+	 * At the right time we try to open it and allocate a buffer.
+	 * If we are successful, webcam_bufsize > 0 and we can read.
+	 */
+	const char *videodevice;	/* pointer in the parent struct */
+	int w;			/* geometry */
+	int h;
+	int webcam_fd;		/* file descriptor */
+	int webcam_bufsize;	/* buffer size, also total bytes per frame */
+	int webcam_ofs;		/* offset for next read */
+	char *webcam_imgbuf;	/* malloced area of size webcam_bufsize */
 };
 
 struct _cm {	/* map ffmpeg codec types to asterisk formats */
@@ -361,6 +371,124 @@
 	{ AST_FORMAT_H263_PLUS,	CODEC_ID_H263 },
 	{ 0,			0 },
 };
+
+/*! \brief support to open a webcam using video4linux1 and read()
+ *
+ */
+#if !defined(HAVE_V4L) || HAVE_V4L != 1
+/* stubs */
+static int webcam_open(struct video_desc *env)
+{
+	return -1;
+}
+static int webcam_read(struct video_desc *env)
+{
+	return 0;
+}
+
+#else
+
+/* the real thing */
+#include <linux/videodev.h>
+
+static int webcam_open(struct video_desc *env)
+{
+	int fd, i;
+	const char *device = env->videodevice;
+	struct video_window vw = { 0 };	/* camera attributes */
+	struct video_picture vp;
+
+	int bufsize;
+	char *imgbuf = NULL;
+
+	if (env->webcam_imgbuf)
+		return env->webcam_fd;
+
+	fd = open(device, O_RDONLY | O_NONBLOCK);
+	if (fd < 0) {
+		ast_log(LOG_WARNING, "error opening camera %s\n", device);
+		return fd;
+	}
+
+	i = fcntl(fd, F_GETFL);
+	if (-1 == fcntl(fd, F_GETFL, i | O_NONBLOCK)) {
+		ast_log(LOG_WARNING, "error F_SETFL for %s\n", device);
+		goto error;
+	}
+	/* set format */
+	vw.width = env->w;
+	vw.height = env->h;
+	bufsize = (vw.width * vw.height * 3)/2;	/* yuv411 */
+	if (ioctl(fd, VIDIOCSWIN, &vw) == -1) {
+		ast_log(LOG_WARNING, "error setting format for %s\n", device);
+		goto error;
+	}
+	if (ioctl(fd, VIDIOCGPICT, &vp) == -1) {
+                ast_log(LOG_WARNING, "error reading picture info\n");
+                return -1;
+        }
+	ast_log(LOG_WARNING, "contrast %d bright %d colour %d hue %d whiteness %d palette %d\n",
+                vp.contrast, vp.brightness,
+                vp.colour, vp.hue,
+                vp.whiteness, vp.palette);
+	vp.palette = VIDEO_PALETTE_YUV420P;
+	if(ioctl(fd,VIDIOCSPICT,&vp) == -1) {
+		ast_log(LOG_WARNING, "error setting picture info\n");
+		goto error;
+        }
+	imgbuf = malloc(bufsize);
+	if (!imgbuf)
+		goto error;
+
+	env->webcam_fd = fd;
+	env->webcam_bufsize = bufsize;
+	env->webcam_ofs = 0;
+	env->webcam_imgbuf = imgbuf;
+	ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n", device, env->w, env->h, bufsize);
+	return fd;
+
+error:
+	if (fd >= 0)
+		close(fd);
+	if (imgbuf)
+		free(imgbuf);
+	env->webcam_fd = -1;
+	return -1;
+}
+
+/*! \brief complete a buffer from the webcam */
+static int webcam_read(struct video_desc *env)
+{
+	if (env->webcam_bufsize == 0)
+		return 0;
+
+	for (;;) {
+		int r, l = env->webcam_bufsize - env->webcam_ofs;
+		r = read(env->webcam_fd, env->webcam_imgbuf + env->webcam_ofs, l);
+		// ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l);
+		if (r < 0) {	/* read error */
+			return 0;
+		}
+		if (r == 0)	/* no data */
+			return 0;
+		env->webcam_ofs += r;
+		if (r == l) {
+			env->webcam_ofs = 0; /* prepare for next frame */
+			return env->webcam_bufsize;
+		}
+	}
+}
+#endif /* HAVE_V4L */
+
+static void show_frame(struct video_desc *env);
+
+static void webcam_encode(struct video_desc *env)
+{
+	struct timeval now = ast_tvnow();
+	ast_log(LOG_WARNING, "video frame ready at %d.%06d\n",
+		(int)now.tv_sec % 1000, (int)now.tv_usec);
+	show_frame(env);
+}
 
 /* Helper function to process incoming video.
  * For each incoming video call invoke ffmpeg_init() to intialize
@@ -372,18 +500,11 @@
  * to display the frame.
  *
  */
-/* Extract the bitstream from the RTP payload */
-static uint8_t *pre_process_data(uint8_t *, int *);
-/* Decode video frame once completed */
-static int decode_video(struct video_desc *);
-/* Dispaly decoded frame */
-static void show_frame(struct video_desc *);
 
 static struct video_desc *get_video_desc(struct ast_channel *c);
 
 /* Macros used as a wrapper around the actual video format we want to use */
 #define AST_FORMAT_CUSTOM (AST_FORMAT_H263_PLUS)
-static int write_video(struct ast_channel *chan, struct ast_frame *f);
 
 /*! \brief map an asterisk format into an ffmpeg one */
 static enum CodecID map_video_format(uint32_t ast_format)
@@ -498,8 +619,21 @@
 	if(env->bmp)
 		SDL_FreeYUVOverlay(env->bmp);
 	SDL_Quit();
-	bzero(env, sizeof(struct video_desc));
-	env->initialized = 0;
+
+	if (env->webcam_imgbuf) {
+		free(env->webcam_imgbuf);
+		if (env->webcam_fd >= 0)
+		close(env->webcam_fd);
+	}
+	{	/* clear the struct but restore some fields */
+		const char *vd = env->videodevice;
+		int w = env->w, h = env->h;
+		bzero(env, sizeof(struct video_desc));
+		/* restore fields... */
+		env->videodevice = vd;
+		env->w = w;
+		env->h = h;
+	}
 }
 
 #define MAKE_MASK(bits)                ( (1<<(bits)) -1 )
@@ -585,6 +719,8 @@
 	uint8_t *data;
 	int datalen;
 
+	if (!len)
+		return 0;
 	while(len) {
 		ret = av_parser_parse(env->parser, env->context, &data, &datalen, aux, len, 0, 0);
 		if(datalen) {
@@ -613,6 +749,8 @@
 	AVPicture pict;
 	SDL_Rect rect;
 
+	if (!env->initialized)
+		return;
 	if(env->screen == NULL) {
 		env->screen = SDL_SetVideoMode(env->context->width, env->context->height, 0, 0);
 		if(!env->screen) {
@@ -638,7 +776,12 @@
 		(AVPicture *)env->frame, env->context->pix_fmt,
 		env->context->width, env->context->height);
 	SDL_UnlockYUVOverlay(env->bmp);
-
+#if 0	/* more testing, overlay the received image with the local picture */
+	ast_log(LOG_WARNING, "show_frame: linesize %d %d %d\n", pict.linesize[0], pict.linesize[1], pict.linesize[2]);
+	if (env->webcam_imgbuf) {
+		bcopy(env->webcam_imgbuf, pict.data[0], env->context->width*env->context->height);
+	}
+#endif
 	rect.x = 0; rect.y = 0;
 	rect.w = env->context->width;
 	rect.h = env->context->height;
@@ -661,16 +804,19 @@
 	struct video_desc *env = get_video_desc(chan);
 	struct timeval now = ast_tvnow();
 	int i;
-	struct ast_frame *f1, **fp;
 
 	if(!env->initialized)
 		ffmpeg_init(env, f->subclass);
 	if(!env->initialized)
 		return -1;	/* error */
-	f1 = ast_frdup(f);
-	for (fp = &env->echo; (*fp) != NULL ; fp = &AST_LIST_NEXT((*fp), frame_list) )
-		;
-	*fp = f1;
+
+	if (0) {	/* echo frames back to the sender */
+		struct ast_frame *f1, **fp;
+		f1 = ast_frdup(f);
+		for (fp = &env->echo; (*fp) != NULL ; fp = &AST_LIST_NEXT((*fp), frame_list) )
+			;
+		*fp = f1;
+	}
 
 	i = ast_tvdiff_ms(now, env->ts);
 	if (i > 1000) {
@@ -838,6 +984,7 @@
 	int readpos;				/*!< read position above */
 	struct ast_frame read_f;	/*!< returned by oss_read */
 
+	char videodevice[64];
 #if HAVE_FFMPEG
 	struct video_desc env;
 #endif
@@ -1237,6 +1384,8 @@
 	res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
 	res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
 	/* it may fail if we are in half duplex, never mind */
+
+	fd = webcam_open(&o->env);
 	return 0;
 }
 
@@ -1402,6 +1551,9 @@
 	struct timeval tb;
 
 	struct video_desc *env = get_video_desc(c);
+
+	if (webcam_read(env) && 0)
+		webcam_encode(env);	/* get frames and put them in the queue */
 	if (env->echo) {
 		struct ast_frame *f1;
 		int i = 0;
@@ -2039,9 +2191,13 @@
 		M_F("mixer", store_mixer(o, v->value))
 		M_F("callerid", store_callerid(o, v->value))
 		M_F("boost", store_boost(o, v->value))
+		M_STR("videodevice", o->videodevice)
+		M_UINT("videowidth", o->env.w)
+		M_UINT("videoheight", o->env.h)
 
 		M_END(/* */);
 	}
+	o->env.videodevice = o->videodevice;
 	if (ast_strlen_zero(o->device))
 		ast_copy_string(o->device, DEV_DSP, sizeof(o->device));
 	if (o->mixer_cmd) {




More information about the asterisk-commits mailing list