[asterisk-commits] rizzo: branch rizzo/video_v2 r83636 - /team/rizzo/video_v2/channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Sep 24 03:30:21 CDT 2007


Author: rizzo
Date: Mon Sep 24 03:30:20 2007
New Revision: 83636

URL: http://svn.digium.com/view/asterisk?view=rev&rev=83636
Log:
update latest code from Sergio Fadda, which brings the processing
of local video source in the video thread.
Still one problem to debug with ast_queue_frame.


Modified:
    team/rizzo/video_v2/channels/console_video.c

Modified: team/rizzo/video_v2/channels/console_video.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/video_v2/channels/console_video.c?view=diff&rev=83636&r1=83635&r2=83636
==============================================================================
--- team/rizzo/video_v2/channels/console_video.c (original)
+++ team/rizzo/video_v2/channels/console_video.c Mon Sep 24 03:30:20 2007
@@ -127,7 +127,7 @@
 	AVCodecContext	*context;	/* encoding context */
 	AVCodec		*codec;
 	AVFrame		*frame;
-	int		lasttxframe;	/* XXX - useless: RTP overwrite seqno */
+	int		lasttxframe;	/* XXX useless: RTP overwrite seqno */
 	struct fbuf_t	encbuf;		/* encoding buffer */
 	int		mtu;
 	struct timeval	last_frame;	/* when we read the last frame ? */
@@ -153,9 +153,7 @@
 	AVCodecParserContext    *parser;
 	int                     completed;	/* probably unnecessary */
 	uint16_t 		next_seq;	/* must be 16 bit */
-	int                     discard;
-	struct timeval	ts;
-	int received;
+	int                     discard;	/* flag for discard status */
 	struct fbuf_t buf;		/* decoded frame */
 };
 
@@ -164,25 +162,23 @@
  * received data descriptors, SDL info, etc.
  */
 struct video_desc {
-	int 	w;
+	int 			w;	/* geometry */
 	int 	h;
-	int 	fps;
+	int 			fps;	/* framerate */
 	int 	bitrate;
 	char videodevice[64];
 
-	ast_mutex_t lock;
-
-	pthread_t vthread;
-	int	shutdown;	/* set to ask the thread to shutdown */
+	pthread_t vthread;	/* video thread */
+	int			shutdown;	/* set to ask the thread to shutdown */
 	struct ast_channel *owner;	/* owner channel */
 
-	struct video_in_desc in;
-	struct video_out_desc out;
+	struct video_in_desc	in;		/* remote video descriptor */
+	struct video_out_desc	out;		/* local video descriptor */
 
 	SDL_Surface             *screen;
 	int                     sdl_ok;
+	ast_mutex_t		sdl_lock;
 	SDL_Overlay             *bmp[2];
-
 };
 
 /*
@@ -244,7 +240,7 @@
 		ast_log(LOG_WARNING, "error creating Ximage\n");
 		goto error;
 	}
-	ast_log(LOG_WARNING, "image: data %p %d bpp, mask 0x%lx 0x%lx 0x%lx\n",
+	ast_log(LOG_NOTICE, "image: data %p %d bpp, mask 0x%lx 0x%lx 0x%lx\n",
 		im->data,
 		im->bits_per_pixel,
 		im->red_mask, im->green_mask, im->blue_mask);
@@ -253,6 +249,7 @@
     }
 #if defined(HAVE_V4L) && HAVE_V4L > 0
     else {
+	/* V4L specific */
 	struct video_window vw = { 0 };	/* camera attributes */
 	struct video_picture vp;
 
@@ -335,7 +332,7 @@
 		return 0;	/* too early */
 	v->last_frame = now; /* XXX actually, should correct for drift */
 
-	if (v->image) {	// X11 grabber
+	if (v->image) {
 		/* read frame from X11 */
 		XGetSubImage(v->dpy,
 		    RootWindow(v->dpy, DefaultScreen(v->dpy)),
@@ -368,9 +365,8 @@
 		int r, l = v->buf.size - v->buf.used;
 		r = read(v->fd, v->buf.data + v->buf.used, l);
 		// ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l);
-		if (r < 0) {	/* read error */
+		if (r < 0)	/* read error */
 			return 0;
-		}
 		if (r == 0)	/* no data */
 			return 0;
 		v->buf.used += r;
@@ -403,6 +399,7 @@
 	return CODEC_ID_NONE;
 }
 
+/*! \brief uninitialize the descriptor for remote video stream */
 static int video_in_uninit(struct video_in_desc *v)
 {
 	if (v->context) {
@@ -432,7 +429,6 @@
 	v->completed = 0;
 	v->discard = 1;
 
-	v->ts = ast_tvnow();
 	codec = map_video_format(format, CM_RD);
 
 	v->codec = avcodec_find_decoder(codec);
@@ -466,6 +462,7 @@
 	return 0;	/* ok */
 }
 
+/*! \brief uninitialize the descriptor for local video stream */
 static int video_out_uninit(struct video_out_desc *v)
 {
 	if (v->context) {
@@ -492,12 +489,10 @@
 }
 
 /*
- * Initialize the encoder for the local source.
- * - AVCodecContext
- * - AVCodec
- * - AVFrame
- * - encbuf
- * - mtu
+ * Initialize the encoder for the local source:
+ * - AVCodecContext, AVCodec, AVFrame are used by ffmpeg for encoding;
+ * - encbuf is used to store the encoded frame (to be sent)
+ * - mtu is used to determine the max size of video fragment
  */
 static int video_out_init(struct video_out_desc *v, uint32_t format)
 {
@@ -574,23 +569,34 @@
 	return 0;
 }
 
-/*
- * Freeing all memory used and uninitialize
- * the ffmpeg and SDL environments.
- */
+/*! \brief uninitialize the entire environment. */
 static void console_video_uninit(struct video_desc *env)
 {
 	env->shutdown = 1;
+	/*
+	 * XXX the locking here must be revised.
+	 * When asterisk calls shutdown, the channel is locked; however
+	 * the video thread might also need to acquire the lock on the channel
+	 * to enqueue the frames. So, we unlock the channel here to give
+	 * vthread a chance to exit the critical section and terminate.
+	 */
+	ast_channel_unlock(env->owner);
+	/* wait for video thread to finish */
 	pthread_join(env->vthread, NULL);
-	ast_log(LOG_WARNING, "thread terminated\n");
+	ast_channel_lock(env->owner);
+
+	/* uninitialize the local and remote video environments */
 	video_in_uninit(&env->in);
 	video_out_uninit(&env->out);
+
+	/* uninitialize the SDL environment */
 	if (env->sdl_ok) {
 	    if (env->bmp[0])
 		SDL_FreeYUVOverlay(env->bmp[0]);
 	    if (env->bmp[1])
 		SDL_FreeYUVOverlay(env->bmp[1]);
 	    SDL_Quit();
+	    ast_mutex_destroy(&(env->sdl_lock));
 	}
 	{	/* clear the struct but restore some fields */
 		struct video_desc x = *env; /* make a copy */
@@ -602,7 +608,6 @@
 		env->fps = x.fps;
 		env->bitrate = x.bitrate;
 	}
-	ast_mutex_destroy(&env->lock);
 }
 
 #define MAKE_MASK(bits)                ( (1<<(bits)) -1 )
@@ -676,9 +681,10 @@
 }
 
 /*
- * It decodes a valid H.263 frame.
- * The av_parser_parse should merge a randomly choped up stream into proper frames.
- * After that, if we have a valid frame, we decode it until the entire frame is processed.
+ * Decode a valid H.263 frame.
+ * av_parser_parse should merge a randomly chopped up stream into
+ * proper frames. After that, if we have a valid frame, we decode it
+ * until the entire frame is processed.
  */
 static int decode_video(struct video_in_desc *v)
 {
@@ -700,16 +706,15 @@
 			src += ret;
 			srclen -= ret;
 		}
-		// ast_log(LOG_WARNING, "in %d ret %d/%d outlen %d complete %d\n", v->buf.used, srclen, ret, datalen, v->completed);
 	}
 	return 1;
 }
 
 /*
- * Display the decoded video frame using the SDL library.
+ * Display video frames (from local or remote stream) using the SDL library.
  * - Set the video mode to use the resolution specified by the codec context
- * - Create a YUV Overlay to copy into it the decoded frame
- * - After the decoded frame is copied into the overlay, we display it
+ * - Create a YUV Overlay to copy the frame into it;
+ * - After the frame is copied into the overlay, display it
  *
  * The size is taken from the configuration.
  *
@@ -791,7 +796,10 @@
 	rect.w = w;
 	rect.h = h;
 
+	/* lock to protect access to Xlib by different threads. */
+	ast_mutex_lock(&env->sdl_lock);
 	SDL_DisplayYUVOverlay(bmp, &rect);
+	ast_mutex_unlock(&env->sdl_lock);
 	SDL_UnlockYUVOverlay(bmp);
 }
 
@@ -819,7 +827,6 @@
 		return 0;	/* error */
 	}
 
-	v->received++;
 #if defined(DROP_PACKETS) && DROP_PACKETS > 0
 	/*
 	 * Fragment of code to simulate lost/delayed packets
@@ -865,7 +872,6 @@
 		return 0;
 	}
 	len = f->datalen;
-	// ast_log(LOG_WARNING, "received video frame %d size %d\n", f->seqno, f->datalen);
 	data = pre_process_data(f->data, &len);
 	if (len < 1 || len > 128*1024) {
 		ast_log(LOG_WARNING, "--- huge frame %d\n", len);
@@ -873,7 +879,8 @@
 		return 0;
 	}
 
-	/* Allocate buffer. ffmpeg wants an extra FF_INPUT_BUFFER_PADDING_SIZE,
+	/*
+	 * Allocate buffer. ffmpeg wants an extra FF_INPUT_BUFFER_PADDING_SIZE,
 	 * and also wants 0 as a buffer terminator to prevent trouble.
 	 */
 	need = len + FF_INPUT_BUFFER_PADDING_SIZE;
@@ -934,7 +941,6 @@
 			}
 		}
 		if (l > out->mtu || l > len) { /* psc not found, split */
-			// ast_log(LOG_WARNING, "no psc in frame sized %d\n", len);
 			l = MIN(len, out->mtu);
 		}
 		if (l < 1 || l > out->mtu) {
@@ -993,6 +999,10 @@
 	return first;
 }
 
+/*! \brief read a frame from webcam or X11 through video_read(),
+ * display it,  then encode and split it.
+ * Return a list of ast_frame representing the video fragments.
+ */
 static struct ast_frame *get_video_frames(struct video_desc *env)
 {
 	int buflen;
@@ -1029,19 +1039,37 @@
 	struct video_desc *env = arg;
 	for (;;i++) {
 		struct timeval t = { 1, 0 };
-		struct ast_frame *f;
+		struct ast_frame *p, *f;
+		struct ast_channel *chan = env->owner;
+		int fd = chan->alertpipe[1];
 
 		if (env->shutdown) {
 			ast_log(LOG_WARNING, "video_thread shutting down%d\n", i);
 			break;
 		}
+		/* sleep for a while */
 		ast_select(0, NULL, NULL, NULL, &t);
-		if (0) {
-		    f = get_video_frames(env);
-		    ast_channel_lock(env->owner);
-		    // enqueue on env->owner->readq
-		}
-	}
+		f = get_video_frames(env);
+		if (!f)
+			continue;
+		chan = env->owner;
+		ast_channel_lock(chan);
+		/*
+		 * more or less same as ast_queue_frame, but extra
+		 * write on the alertpipe to signal frames.
+		 */
+		AST_LIST_INSERT_TAIL(&(chan->readq), f, frame_list);
+		if (fd > -1) {
+			int blah = 1, l = sizeof(blah);
+			for (p = f; p; p = AST_LIST_NEXT(p, frame_list)) {
+				if (write(fd, &blah, l) != l)
+					ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d: %s!\n",
+					    chan->name, f->frametype, f->subclass, strerror(errno));
+			}
+		}
+		ast_channel_unlock(chan);
+	}
+	/* thread terminating, here could call the uninit */
 	return NULL;
 }
 
@@ -1067,7 +1095,6 @@
 	 * Register all codecs supported by the ffmpeg library.
 	 * Doing it once is enough.
 	 */
-	ast_mutex_init(&env->lock);
 
 	avcodec_init();
 	avcodec_register_all();
@@ -1099,8 +1126,10 @@
 	SDL_WM_SetCaption("Asterisk console Video Output", NULL);
 	env->bmp[0] = SDL_CreateYUVOverlay(env->w, env->h, fmt, env->screen);
 	env->bmp[1] = SDL_CreateYUVOverlay(env->w, env->h, fmt, env->screen);
-	if (env->bmp[0] && env->bmp[1])
+	if (env->bmp[0] && env->bmp[1]) {
+		ast_mutex_init(&env->sdl_lock);
 		env->sdl_ok = 1;
+	}
 	/* otherwise should release the screen */
 
 no_sdl:




More information about the asterisk-commits mailing list