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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Oct 9 08:32:56 CDT 2007


Author: rizzo
Date: Tue Oct  9 08:32:55 2007
New Revision: 85091

URL: http://svn.digium.com/view/asterisk?view=rev&rev=85091
Log:
some restructuring from Sergio Fadda to deal with different codecs.


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

Modified: team/rizzo/video_v2/channels/chan_alsa.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/video_v2/channels/chan_alsa.c?view=diff&rev=85091&r1=85090&r2=85091
==============================================================================
--- team/rizzo/video_v2/channels/chan_alsa.c (original)
+++ team/rizzo/video_v2/channels/chan_alsa.c Tue Oct  9 08:32:55 2007
@@ -1083,11 +1083,54 @@
 	return res;
 }
 
+/*! generic console command handler. Basically a wrapper for a subset
+ *  *  of config file options.
+ *   */
+static char *console_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct chan_alsa_pvt *o = &alsa;
+	const char *var, *value;
+
+	switch (cmd) {
+		case CLI_INIT:
+			e->command = "console [sendvideo|device|videodevice|fps|bitrate|videowidth|videoheight]";
+			e->usage =
+				"Usage: console ...\n"
+				"       Generic handler for console commands.\n";
+				return NULL;
+
+		case CLI_GENERATE:
+			return NULL;
+	}
+	if (a->argc < e->args)
+		return CLI_SHOWUSAGE;
+	var = a->argv[e->args-1];
+	value = a->argc > e->args ? a->argv[e->args] : NULL;
+	//if (value)      /* handle setting */
+	//	store_config_core(o, var, value);
+	/* XXX these should be moved to console_video.c */
+	if (!strcasecmp(var, "videodevice")) {
+		ast_cli(a->fd, "videodevice is [%s]\n", o->env->videodevice);
+	} else if (!strcasecmp(var, "videowidth")) {
+		ast_cli(a->fd, "videowidth is [%d]\n", o->env->w);
+	} else if (!strcasecmp(var, "videoheight")) {
+		ast_cli(a->fd, "videoheight is [%d]\n", o->env->h);
+	} else if (!strcasecmp(var, "bitrate")) {
+		ast_cli(a->fd, "bitrate is [%d]\n", o->env->bitrate);
+	} else if (!strcasecmp(var, "fps")) {
+		ast_cli(a->fd, "fps is [%d]\n", o->env->fps);
+	} else if (!strcasecmp(var, "device")) {
+		ast_cli(a->fd, "device is [in: %s - out: %s]\n", indevname, outdevname);
+	}
+	return CLI_SUCCESS;
+}
+
 static const char dial_usage[] =
 	"Usage: console dial [extension[@context]]\n"
 	"       Dials a given extension (and context if specified)\n";
 
 static struct ast_cli_entry cli_alsa[] = {
+	NEW_CLI(console_cmd, "Generic console command"),
 	{ { "console", "answer", NULL },
 	console_answer, "Answer an incoming console call",
 	answer_usage },

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=85091&r1=85090&r2=85091
==============================================================================
--- team/rizzo/video_v2/channels/console_video.c (original)
+++ team/rizzo/video_v2/channels/console_video.c Tue Oct  9 08:32:55 2007
@@ -240,17 +240,17 @@
 
 /*! \brief encapsulate the bistream in RTP frames */
 /* XXX len is redundant */
-typedef struct ast_frame (*encoder_encap_f)(struct video_out_desc *out,
-		int len, struct ast_frame **tail);
+typedef struct ast_frame *(*encoder_encap_f)(struct video_out_desc *out,
+		struct ast_frame **tail);
 
 /*! \brief inizialize the decoder */
 typedef int (*decoder_init_f)(struct video_in_desc *v);
 
 /*! \brief extract the bitstream from RTP frames */
-typedef int (*decoder_decap_f)(struct video_in_desc *v);
+typedef uint8_t *(*decoder_decap_f)(uint8_t *data, int *len);
 
 /*! \brief actually call the decoder */
-typedef int (*decoder_decode_f)(struct video_in_desc *v);
+typedef int (*decoder_decode_f)(struct video_in_desc *v, struct fbuf_t *b);
 
 struct video_codec_desc {
 	int			format;		/* AST_FORMAT_* */
@@ -272,8 +272,7 @@
 	int 			fps;	/* framerate */
 	int 			bitrate;
 	char			videodevice[64];
-
-	int			rtp_fmt;	/* compressed format, AST_FORMAT_* */
+	char			codec_name[64];
 
 	pthread_t		vthread;	/* video thread */
 	int			shutdown;	/* set to shutdown vthread */
@@ -281,6 +280,8 @@
 
 	struct video_in_desc	in;		/* remote video descriptor */
 	struct video_out_desc	out;		/* local video descriptor */
+
+	struct video_codec_desc *current_codec;
 
 	SDL_Surface             *screen;
 	int                     sdl_ok;
@@ -293,7 +294,7 @@
  * The list of video formats we support. You can OR the formats, and
  * provide corresponding ffmpeg mappings in the table below.
  */
-#define CONSOLE_FORMAT_VIDEO	AST_FORMAT_H263_PLUS
+#define CONSOLE_FORMAT_VIDEO	(AST_FORMAT_H263_PLUS | AST_FORMAT_H263 | AST_FORMAT_H261)
 
 static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p);
 
@@ -310,12 +311,59 @@
 	b->pix_fmt = x.pix_fmt;
 }
 
+/*!
+ * Build an ast_frame for a given chunk of data, and link it into
+ * the queue, with possibly 'head' bytes at the beginning to
+ * fill in some fields later.
+ */
+static struct ast_frame *create_video_frame(uint8_t *start, uint8_t *end,
+	               int format, int head, struct ast_frame *prev)
+{
+	int len = end-start;
+	uint8_t *data;
+	struct ast_frame *f;
+
+	data = ast_calloc(1, len+head);
+	f = ast_calloc(1, sizeof(*f));
+	if (f == NULL || data == NULL) {
+		ast_log(LOG_WARNING, "--- frame error f %p data %p len %d format %d\n",
+				f, data, len, format);
+		if (f)
+			ast_free(f);
+		if (data)
+			ast_free(data);
+		return NULL;
+	}
+	memcpy(data+head, start, len);
+	f->data = data;
+	f->mallocd = AST_MALLOCD_DATA | AST_MALLOCD_HDR;
+	//f->has_timing_info = 1;
+	//f->ts = ast_tvdiff_ms(ast_tvnow(), out->ts);
+	f->datalen = len+head;
+	f->frametype = AST_FRAME_VIDEO;
+	f->subclass = format;
+	f->samples = 0;
+	f->offset = 0;
+	f->src = "Console";
+	f->delivery.tv_sec = 0;
+	f->delivery.tv_usec = 0;
+	f->seqno = 0;
+	AST_LIST_NEXT(f, frame_list) = NULL;
+
+	if (prev)
+	        AST_LIST_NEXT(prev, frame_list) = f;
+
+	return f;
+}
+
+
 /*----- codec specific code --------*/
 
 /*
  * For each codec, we define the various callback in use
  */
 
+/*! \brief initialization of h263p */
 static int h263p_enc_init(struct video_out_desc *v)
 {
 	/* modes supported are
@@ -340,20 +388,21 @@
 
 
 /*
- * Create RTP/H.263 fragmets to avoid IP fragmentation
+ * Create RTP/H.263 fragments to avoid IP fragmentation
  */
 static struct ast_frame *h263p_encap(struct video_out_desc *out,
-	int len, struct ast_frame **tail)
+	struct ast_frame **tail)
 {
 	struct ast_frame *cur = NULL, *first = NULL;
 	uint8_t *d = out->enc_out.data;
+	int len = out->enc_out.used;
 	int l = len; /* size of the current fragment. If 0, must look for a psc */
 	int frags = 0;
 
 	for (;len > 0; len -= l, d += l) {
 		uint8_t *data;
 		struct ast_frame *f;
-		int i;
+		int i, h;
 
 		if (len >= 3 && d[0] == 0 && d[1] == 0 && d[2] >= 0x80) {
 			/* we are starting a new block, so look for a PSC. */
@@ -371,46 +420,27 @@
 			ast_log(LOG_WARNING, "--- frame error l %d\n", l);
 			break;
 		}
-		f = ast_calloc(1, sizeof(*f));
-		data = ast_calloc(1, l+2); /* 2 extra bytes for header */
-		if (f == NULL || data == NULL) {
-			ast_log(LOG_WARNING, "--- frame error f %p d %p l %d\n",
-				f, d, l);
-			if (f)
-				ast_free(f);
-			if (data)
-				ast_free(data);
+		
+		if (d[0] == 0 && d[1] == 0) { /* we start with a psc */
+			h = 0;
+		} else { /* no psc, create a header */
+			h = 2;
+		}
+
+		f = create_video_frame(d, d+l, AST_FORMAT_H263_PLUS, h, cur);
+		if (!f)
 			break;
+
+		data = f->data;
+		if (h == 0) {	/* we start with a psc */
+			data[0] |= 0x04;	// set P == 1, and we are done
+		} else {	/* no psc, create a header */
+			data[0] = data[1] = 0;	// P == 0
 		}
-		f->mallocd = AST_MALLOCD_DATA | AST_MALLOCD_HDR;
-		f->data = data;
-
-		if (d[0] == 0 && d[1] == 0) { /* we start with a psc */
-			memcpy(data, d, l);
-			data[0] |= 0x04; // set P == 1, and we are done
-			f->datalen = l;
-		} else { /* no psc, create a header */
-			data[0] = data[1] = 0; // P == 0
-			memcpy(data + 2, d, l);
-			f->datalen = l + 2;
-		}
-
-		//f->has_timing_info = 1;
-		//f->ts = ast_tvdiff_ms(ast_tvnow(), out->ts);
-		f->frametype = AST_FRAME_VIDEO;
-		f->subclass = CONSOLE_FORMAT_VIDEO;
-		f->samples = 0;
-		f->offset = 0;
-		f->src = "Console";
-		f->delivery.tv_sec = 0;
-		f->delivery.tv_usec = 0;
-		f->seqno = ++(out->lasttxframe);
-		AST_LIST_NEXT(f, frame_list) = NULL;
-
-		if (cur)
-			AST_LIST_NEXT(cur, frame_list) = f;
-		else
+
+		if (!cur)
 			first = f;
+
 		cur = f;
 		frags++;
 		// ast_log(LOG_WARNING, "-- frag %d size %d left %d\n", frags, f->datalen, len - l);
@@ -495,12 +525,13 @@
 }
 
 /*
- * Decode a valid H.263 frame.
+ * Generic decoder, which is used by h263p, h263 and h261 as it simply
+ * invokes ffmpeg's decoder.
  * 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 h263p_decode(struct video_in_desc *v, struct fbuf_t *b)
+static int ffmpeg_decode(struct video_in_desc *v, struct fbuf_t *b)
 {
 	uint8_t *src = b->data;
 	int srclen = b->used;
@@ -523,6 +554,228 @@
 	}
 	return 1;
 }
+
+struct video_codec_desc h263p_codec = {
+	.format = AST_FORMAT_H263_PLUS,
+	.enc_init = h263p_enc_init,
+	.enc_encap = h263p_encap,
+	.enc_run = NULL,
+	.dec_init = NULL,
+	.dec_decap = h263p_decap,
+	.dec_run = ffmpeg_decode
+};
+
+/*--- plain H263 support --------*/
+
+static int h263_enc_init(struct video_out_desc *v)
+{
+	/* XXX check whether these are supported */
+	v->enc_ctx->flags |= CODEC_FLAG_H263P_UMV;
+	v->enc_ctx->flags |= CODEC_FLAG_H263P_AIC;
+	v->enc_ctx->flags |= CODEC_FLAG_H263P_SLICE_STRUCT;
+	v->enc_ctx->flags |= CODEC_FLAG_AC_PRED;
+
+	v->enc_ctx->bit_rate = v->bitrate;
+	v->enc_ctx->gop_size = v->fps*5;
+	v->enc_ctx->qmin = 3;
+
+	return 0;
+}
+
+/*
+ * h263 encapsulation is specified in RFC2190. There are three modes
+ * defined (A, B, C), with 4, 8 and 12 bytes of header, respectively.
+ * The header is made as follows
+ *     0.....................|.......................|.............|....31
+ *	F:1 P:1 SBIT:3 EBIT:3 SRC:3 I:1 U:1 S:1 A:1 R:4 DBQ:2 TRB:3 TR:8
+ * FP = 0- mode A, (only one word of header)
+ * FP = 10 mode B, and also means this is an I or P frame
+ * FP = 11 mode C, and also means this is a PB frame.
+ * SBIT, EBIT nuber of bits to ignore at beginning (msbits) and end (lsbits)
+ * SRC  bits 6,7,8 from the h263 PTYPE field
+ * I = 0 intra-coded, 1 = inter-coded (bit 9 from PTYPE)
+ * U = 1 for Unrestricted Motion Vector (bit 10 from PTYPE)
+ * S = 1 for Syntax Based Arith coding (bit 11 from PTYPE)
+ * A = 1 for Advanced Prediction (bit 12 from PTYPE)
+ * R = reserved, must be 0
+ * DBQ = differential quantization, DBQUANT from h263, 0 unless we are using
+ *	PB frames
+ * TRB = temporal reference for bframes, also 0 unless this is a PB frame
+ * TR = temporal reference for P frames, also 0 unless PB frame.
+ *
+ * Mode B and mode C description omitted.
+ *
+ * Note - Group Of Blocks (GOB) are byte-aligned, they start with
+ *	PSC:22 0000 0000 0000 0000 1000 00 	picture start code
+ *	TR:8   .... ....			temporal reference
+ *      PTYPE:13 or more 			ptype...
+ * If we don't fragment a GOB SBIT and EBIT = 0.
+ * reference, 8 bit) 
+ * 
+ */
+static struct ast_frame *h263_encap(struct video_out_desc *out,
+		struct ast_frame **tail)
+{
+	uint8_t *nextgob = NULL;
+	uint8_t *d = out->enc_out.data;
+	uint8_t *end = d + out->enc_out.used;
+	struct ast_frame *f, *cur = NULL, *first = NULL;
+	const int pheader_len = 4;	/* Use RFC-2190 Mode A */
+
+	for (; d != end; d = nextgob) {
+		uint8_t *data = NULL;
+		int l;
+		uint16_t test = 0xffff;
+
+		/* XXX double check this.
+		 * look for two consecutive 0s and at least 5 bytes
+		 * of data. On exit, nextgob points two bytes before
+		 * the 00 marker, or right at the end of data.
+		 */
+		for (nextgob = d; nextgob < end; nextgob++) {
+			test = (test << 8) | (*nextgob);
+			if (test == 0 && nextgob - d > 4) {
+				nextgob -= 3;
+				break;
+			}
+		}
+
+		/* We cannot split the block even if larger than MTU */
+		l = nextgob - d;
+
+		f = create_video_frame(d, d+l, AST_FORMAT_H263,
+				pheader_len, cur);
+
+		if (!f)
+			break;
+		data = f->data;
+
+		/* Now set the header bytes */
+		data[0] =  0;	/* this is easy, F:1 P:1 SBIT:3 EBIT:3 */
+		/* ptype starts 30 bits in the GOB, so the first useful
+		 * bit for us is bit 36 i.e. within d[4] (0 is the msbit).
+		 * SRC = d[4] & 0x1c goes into data[1] & 0xe0
+		 * I   = d[4] & 0x02 goes into data[1] & 0x10
+		 * U   = d[4] & 0x01 goes into data[1] & 0x08
+		 * S   = d[5] & 0x80 goes into data[1] & 0x04
+		 * A   = d[5] & 0x40 goes into data[1] & 0x02
+		 * R   = 0           goes into data[1] & 0x01
+		 * Optimizing it, we have
+		 */
+		data[1] =  	/* SRC:3 I:1 U:1 S:1 A:1 R:1 */
+			( (d[4] & 0x1f) << 3 ) |	/* SRC, I, U */
+			( (d[5] & 0xc0) >> 5 );		/* S, A, R */
+		/* in mode A, all other fields are 0 */
+		data[2] = 0;
+		data[3] = 0;
+		if (!cur)
+			first = f;
+		cur = f;
+	}
+
+	if (cur)
+		cur->subclass |= 1;	// RTP Marker
+
+	*tail = cur;
+	return first;
+}
+
+/* XXX We only drop the header here, but maybe we need more. */
+static uint8_t *h263_decap(uint8_t *data, int *len)
+{
+	if (*len < 4) {
+		ast_log(LOG_WARNING, "invalid framesize %d\n", *len);
+		*len = 0;
+		return data;
+	}
+
+	if ( (data[0] & 0x80) == 0) {
+		*len -= 4;
+		return data+4;
+	} else {
+		ast_log(LOG_WARNING, "unsupported mode 0x%x\n",
+			data[0]);
+	}
+	return data;
+}
+
+struct video_codec_desc h263_codec = {
+	.format = AST_FORMAT_H263,
+	.enc_init = h263_enc_init,
+	.enc_encap = h263_encap,
+	.enc_run = NULL,
+	.dec_init = NULL,
+	.dec_decap = h263_decap,
+	.dec_run = ffmpeg_decode
+						
+};
+
+/*---- plain H261 support -----*/
+static int h261_enc_init(struct video_out_desc *v)
+{
+	return 0;
+}
+
+static struct ast_frame *h261_encap(struct video_out_desc *out,
+		struct ast_frame **tail)
+{
+	struct ast_frame *f, *cur = NULL, *first = NULL;
+	uint8_t *d = out->enc_out.data;
+	int len = out->enc_out.used;
+	uint8_t *end = d+len;
+	int l;
+
+	for (; len > 0; len -= l, d +=l) {
+		uint8_t *iter;
+		uint8_t *data;
+		for (iter = d+2; iter < end-2; iter++)
+			if (iter[0] == 0x00 && iter[1] == 0x01)
+				break;
+
+		if (iter == end-2)
+			iter = end;
+		l = iter-d;
+		f = create_video_frame(d, iter, AST_FORMAT_H261, 4, cur);
+		if (!f)
+			break;
+
+		data = f->data;
+		data[0] = 0x03;
+
+		if (!cur)
+			first = f;
+
+		cur = f;
+	}
+
+	if (cur)
+		cur->subclass |= 1;	// RTP Marker
+
+	*tail = cur;
+	return first;
+}
+
+static uint8_t *h261_decap(uint8_t *data, int *len)
+{
+	if (*len < 4) {
+		ast_log(LOG_WARNING, "invalid framesize %d\n", *len);
+		*len = 0;
+		return data;
+	}
+
+	*len -= 4;
+	return data+4;
+}
+
+struct video_codec_desc h261_codec = {
+	.format = AST_FORMAT_H261,
+	.enc_init = h261_enc_init,
+	.enc_encap = h261_encap,
+	.enc_run = NULL,
+	.dec_init = NULL,
+	.dec_decap = h261_decap,
+	.dec_run = ffmpeg_decode
+};
 
 /*------ end codec specific code -----*/
 
@@ -739,6 +992,7 @@
 	{ AST_FORMAT_H263_PLUS,	CODEC_ID_H263P, CM_WR },
 	{ AST_FORMAT_H263,	CODEC_ID_H263, CM_RD },
 	{ AST_FORMAT_H263,	CODEC_ID_H263, CM_WR },
+	{ AST_FORMAT_H261,	CODEC_ID_H261, CM_RDWD },
 	{ 0,			0, 0 },
 };
 
@@ -752,6 +1006,32 @@
 		if (ast_format & i->ast_format && rw & i->rw && rw & i->rw)
 			return i->codec;
 	return CODEC_ID_NONE;
+}
+
+struct _config_map {	/* map config format to asterisk format */
+	char			*name;
+	struct video_codec_desc	*codec;
+} str_format_map[] = {
+	{ "h263+",	&h263p_codec },
+	{ "h263",	&h263_codec },
+	{ "h261",	&h261_codec },
+	{ NULL,		NULL }
+};
+
+/*
+ * Map the codec name to the library. If not recognised, use a default.
+ */
+static struct video_codec_desc *map_config_video_format(char *name)
+{
+	int i;
+
+	for (i = 0; str_format_map[i].name != NULL; i++)
+		if(strcasecmp(name, str_format_map[i].name) == 0)
+			return str_format_map[i].codec;
+	ast_log(LOG_WARNING, "Cannot find codec for '%s', using '%s'\n",
+		name, str_format_map[0].name);
+	strcpy(name, str_format_map[0].name);
+	return str_format_map[i].codec;
 }
 
 /*! \brief uninitialize the descriptor for remote video stream */
@@ -848,11 +1128,12 @@
  * - 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)
+static int video_out_init(struct video_desc *env)
 {
 	int codec;
 	int size;
 	struct fbuf_t *enc_in;
+	struct video_out_desc *v = &env->out;
 
 	v->enc_ctx		= NULL;
 	v->codec		= NULL;
@@ -864,7 +1145,7 @@
 		ast_log(LOG_WARNING, "No local source active\n");
 		return video_out_uninit(v);
 	}
-	codec = map_video_format(format, CM_WR);
+	codec = map_video_format(env->current_codec->format, CM_WR);
 	v->codec = avcodec_find_encoder(codec);
 	if (!v->codec) {
 		ast_log(LOG_WARNING, "Cannot find the encoder for format %d\n",
@@ -912,7 +1193,7 @@
 	v->enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
 	v->enc_ctx->bit_rate_tolerance = v->enc_ctx->bit_rate/2;
 
-	h263p_enc_init(v);
+	env->current_codec->enc_init(v);
  
 	ast_log(LOG_WARNING, "w: %d h: %d fps: %d\n", v->w, v->h, v->fps);
 	v->enc_ctx->time_base = (AVRational){1, v->fps};
@@ -1081,6 +1362,7 @@
 		AVCodecContext *c = env->in.dec_ctx;
 		b_in = &env->in.dec_out;
                 b_in->pix_fmt = c->pix_fmt;
+	ast_log(LOG_WARNING, "dec_in pix_fmt %d %dx%d\n",  c->pix_fmt, c->width, c->height);
                 b_in->w = c->width;
                 b_in->h = c->height;
 
@@ -1176,7 +1458,7 @@
 		return 0;
 	}
 	len = f->datalen;
-	data = h263p_decap(f->data, &len);
+	data = env->current_codec->dec_decap(f->data, &len);
 	if (len < 1 || len > 128*1024) {
 		ast_log(LOG_WARNING, "--- huge frame %d\n", len);
 		v->discard = 1;
@@ -1206,7 +1488,7 @@
 	v->dec_in.used += len;
 	v->dec_in.data[v->dec_in.used] = '\0';
 	if (f->subclass & 0x01) {	// RTP Marker
-		if (h263p_decode(v, &v->dec_in)) {
+		if (env->current_codec->dec_run(v, &v->dec_in)) {
 			show_frame(env, 0);
 			v->completed = 0;
 			v->dec_in.used = 0;
@@ -1252,7 +1534,7 @@
 	if (!v->sendvideo)
 		return NULL;
 	b->used = avcodec_encode_video(v->enc_ctx, b->data, b->size, v->frame);
-	return h263p_encap(v, b->used, tail);
+	return env->current_codec->enc_encap(v, tail);
 }
 
 /*
@@ -1362,8 +1644,10 @@
 	 */
 	avcodec_init();
 	avcodec_register_all();
+	env->current_codec = map_config_video_format(env->codec_name);
+
 	av_log_set_level(AV_LOG_ERROR);	/* only report errors */
-	if (video_in_init(&env->in, CONSOLE_FORMAT_VIDEO)) {
+	if (video_in_init(&env->in, env->current_codec->format)) {
 		/* This is not fatal, but we won't have incoming video */
 		ast_log(LOG_WARNING, "Cannot initialize input decoder - %s\n",
 			SDL_GetError());
@@ -1436,7 +1720,7 @@
 		 */
 		if (env->out.fd >= 0)
 			ast_channel_set_fd(owner, 1, env->out.fd);
-		video_out_init(&env->out, CONSOLE_FORMAT_VIDEO);
+		video_out_init(env);
 	}
 	ast_pthread_create_background(&env->vthread, NULL, video_thread, env);
 }
@@ -1463,6 +1747,7 @@
 	const char *var, const char *val)
 {
 	struct video_desc *env;
+	char name[10];
 	M_START(var, val);
 
 	if (penv == NULL) {
@@ -1486,6 +1771,7 @@
         M_UINT("videoheight", env->h)
         M_UINT("fps", env->fps)
         M_UINT("bitrate", env->bitrate)
+	M_STR("videoformat", name)
 	M_END(return 1;)	/* the 'nothing found' case */
 	return 0;		/* found something */
 }




More information about the asterisk-commits mailing list