[svn-commits] rizzo: branch rizzo/video_v2 r89187 - /team/rizzo/video_v2/channels/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Nov 12 12:52:34 CST 2007


Author: rizzo
Date: Mon Nov 12 12:52:33 2007
New Revision: 89187

URL: http://svn.digium.com/view/asterisk?view=rev&rev=89187
Log:
use multiple buffers to store incoming video frames
so we can do the decoding in the video thread and solve
a lot of problems, including not blocking the incoming thread
for a long time, and not having to synchronize on X11 updates.


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=89187&r1=89186&r2=89187
==============================================================================
--- team/rizzo/video_v2/channels/console_video.c (original)
+++ team/rizzo/video_v2/channels/console_video.c Mon Nov 12 12:52:33 2007
@@ -225,6 +225,11 @@
  * and store the result in a suitable frame buffer for later display.
  * NOTE: dec_ctx == NULL means the rest is invalid (e.g. because no
  *	codec, no memory, etc.) and we must drop all incoming frames.
+ *
+ * Incoming payload is stored in one of the dec_in[] buffers, which are
+ * emptied by the video thread. dec_in_cur is the buffer in use by the
+ * incoming frame, dec_in_dpy is the one being displayed.
+ * We synchronize on dec_in_lock;
  */
 struct video_in_desc {
 	struct video_codec_desc *dec;	/* decoder */
@@ -234,7 +239,11 @@
 	AVCodecParserContext    *parser;
 	uint16_t 		next_seq;	/* must be 16 bit */
 	int                     discard;	/* flag for discard status */
-	struct fbuf_t dec_in;	/* incoming bitstream, allocated/extended in fbuf_append() */
+#define N_DEC_IN	3	/* number of incoming buffers */
+	struct fbuf_t		*dec_in_cur;	/* buffer being filled in */
+	struct fbuf_t		*dec_in_dpy;	/* buffer to display */
+	ast_mutex_t		dec_in_lock;
+	struct fbuf_t dec_in[N_DEC_IN];	/* incoming bitstream, allocated/extended in fbuf_append() */
 	struct fbuf_t dec_out;	/* decoded frame, no buffer (data is in AVFrame) */
 	struct fbuf_t rem_dpy;	/* display remote image, no buffer (managed by SDL in bmp[0]) */
 };
@@ -300,7 +309,6 @@
 	struct video_out_desc	out;		/* local video descriptor */
 
 	int                     sdl_ok;
-	ast_mutex_t		sdl_lock;
 	SDL_Surface             *screen;
 	struct display_window	win[WIN_MAX];
 };
@@ -1623,6 +1631,8 @@
 /*! \brief uninitialize the descriptor for remote video stream */
 static int video_in_uninit(struct video_in_desc *v)
 {
+	int i;
+
 	if (v->parser) {
 		av_parser_close(v->parser);
 		v->parser = NULL;
@@ -1639,7 +1649,8 @@
 	v->codec = NULL;	/* only a reference */
 	v->dec = NULL;		/* forget the decoder */
 	v->discard = 1;		/* start in discard mode */
-	fbuf_free(&v->dec_in);
+	for (i = 0; i < N_DEC_IN; i++)
+		fbuf_free(&v->dec_in[i]);
 	fbuf_free(&v->dec_out);
 	fbuf_free(&v->rem_dpy);
 	return -1;	/* error, in case someone cares */
@@ -1828,7 +1839,7 @@
 	env->screen = NULL; /* XXX check reference */
 	bzero(env->win, sizeof(env->win));
 	if (env->sdl_ok)
-		ast_mutex_destroy(&(env->sdl_lock));
+		ast_mutex_destroy(&(env->in.dec_in_lock));
 }
 
 /*! \brief uninitialize the entire environment. */
@@ -1985,13 +1996,11 @@
 	p_out.linesize[2] = bmp->pitches[2];
 
 	my_scale(b_in, p_in, b_out, &p_out);
-	SDL_UnlockYUVOverlay(bmp);
 
 	/* lock to protect access to Xlib by different threads. */
-	ast_mutex_lock(&env->sdl_lock);
 	SDL_UpdateRects(env->screen, 1, &env->win[WIN_KEYPAD].rect);// XXX inefficient
 	SDL_DisplayYUVOverlay(bmp, &env->win[out].rect);
-	ast_mutex_unlock(&env->sdl_lock);
+	SDL_UnlockYUVOverlay(bmp);
 }
 
 static struct video_desc *get_video_desc(struct ast_channel *c);
@@ -2029,6 +2038,8 @@
 		return 0;	/* error */
 	}
 
+	if (v->dec_in_cur == NULL)	/* no buffer for incoming frames, drop */
+		return 0;
 #if defined(DROP_PACKETS) && DROP_PACKETS > 0
 	/* Simulate lost packets */
 	if ((random() % 10000) <= 100*DROP_PACKETS) {
@@ -2045,8 +2056,8 @@
 		 * normally used for audio so there is no interference.
 		 */
 		if (f->subclass & 0x01) {
-			v->dec_in.used = 0;
-			v->dec_in.ebit = 0;
+			v->dec_in_cur->used = 0;
+			v->dec_in_cur->ebit = 0;
 			v->next_seq = f->seqno + 1;	/* wrap at 16 bit */
 			v->discard = 0;
 			ast_log(LOG_WARNING, "out of discard mode, frame %d\n", f->seqno);
@@ -2071,13 +2082,23 @@
 		ast_log(LOG_WARNING, "empty video frame, discard\n");
 		return 0;
 	}
-	if (v->dec->dec_decap(&v->dec_in, f->data, f->datalen)) {
+	if (v->dec->dec_decap(v->dec_in_cur, f->data, f->datalen)) {
 		ast_log(LOG_WARNING, "error in dec_decap, enter discard\n");
 		v->discard = 1;
 	}
 	if (f->subclass & 0x01) {	// RTP Marker
-		if (v->dec->dec_run(v, &v->dec_in))
-			show_frame(env, WIN_REMOTE);
+		/* prepare to decode: advance the buffer so the video thread knows. */
+		struct fbuf_t *tmp = v->dec_in_cur;	/* store current pointer */
+		ast_mutex_lock(&v->dec_in_lock);
+		fprintf(stderr, "using buffer %d\n", v->dec_in_cur - v->dec_in);
+		if (++v->dec_in_cur == &v->dec_in[N_DEC_IN])	/* advance to next, circular */
+			v->dec_in_cur = &v->dec_in[0];
+		if (v->dec_in_dpy == NULL) {	/* were not displaying anything, so set it */
+			v->dec_in_dpy = tmp;
+		} else if (v->dec_in_dpy == v->dec_in_cur) { /* current slot is busy */
+			v->dec_in_cur = NULL;
+		}
+		ast_mutex_unlock(&v->dec_in_lock);
 	}
 	return 0;
 }
@@ -2123,6 +2144,18 @@
 	return v->enc->enc_encap(v, tail);
 }
 
+static void eventhandler(struct video_desc *env)
+{
+	SDL_Event event;
+	return;
+
+	if (!SDL_PollEvent(&event)) {
+		fprintf(stderr, "-- no event\n");
+	} else {
+		fprintf(stderr, "-- event %d at %d %d\n",
+			event.type, event.button.x, event.button.y);
+	}
+}
 /*
  * Helper thread to periodically poll the video source and enqueue the
  * generated frames to the channel's queue.
@@ -2148,7 +2181,8 @@
 		/* XXX 20 times/sec */
 		struct timeval t = { 0, 50000 };
 		struct ast_frame *p, *f;
-		
+		struct video_in_desc *v = &env->in;
+
 		struct ast_channel *chan = env->owner;
 		int fd = chan->alertpipe[1];
 
@@ -2170,8 +2204,32 @@
 		}
 		/* sleep for a while */
 		ast_select(0, NULL, NULL, NULL, &t);
-		
-		f = get_video_frames(env, &p);
+
+		/*
+		 * While there is something to display, call the decoder and free
+		 * the buffer, possibly enabling the receiver to store new data.
+		 */
+		while (v->dec_in_dpy) {
+			struct fbuf_t *tmp = v->dec_in_dpy;	/* store current pointer */
+
+			if (v->dec->dec_run(v, tmp))
+				show_frame(env, WIN_REMOTE);
+			tmp->used = 0;	/* mark buffer as free */
+			tmp->ebit = 0;
+			ast_mutex_lock(&v->dec_in_lock);
+			if (++v->dec_in_dpy == &v->dec_in[N_DEC_IN])	/* advance to next, circular */
+				v->dec_in_dpy = &v->dec_in[0];
+
+			if (v->dec_in_cur == NULL)	/* receiver was idle, enable it... */
+				v->dec_in_cur = tmp;	/* using the slot just freed */
+			else if (v->dec_in_dpy == v->dec_in_cur) /* this was the last slot */
+				v->dec_in_dpy = NULL;	/* nothing more to display */
+			ast_mutex_unlock(&v->dec_in_lock);
+		}
+
+		eventhandler(env);
+
+		f = get_video_frames(env, &p);	/* read and display */
 		if (!f)
 			continue;
 		chan = env->owner;
@@ -2366,7 +2424,9 @@
 		goto no_sdl;
 #endif
 
-	ast_mutex_init(&env->sdl_lock);
+	ast_mutex_init(&env->in.dec_in_lock);
+	env->in.dec_in_cur = &env->in.dec_in[0];
+	env->in.dec_in_dpy = NULL;	/* nothing to display */
 	env->sdl_ok = 1;
 
 no_sdl:




More information about the svn-commits mailing list