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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Oct 5 15:14:51 CDT 2007


Author: rizzo
Date: Fri Oct  5 15:14:51 2007
New Revision: 84860

URL: http://svn.digium.com/view/asterisk?view=rev&rev=84860
Log:
move h263p-specific code in a single block, and start adding
codec descriptors to make them configurable.


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=84860&r1=84859&r2=84860
==============================================================================
--- team/rizzo/video_v2/channels/console_video.c (original)
+++ team/rizzo/video_v2/channels/console_video.c Fri Oct  5 15:14:51 2007
@@ -230,6 +230,39 @@
 };
 
 /*
+ * Each codec is defined by a number of callbacks
+ */
+/*! \brief initialize the encoder */
+typedef int (*encoder_init_f)(struct video_out_desc *v);
+
+/*! \brief actually call the encoder */
+typedef int (*encoder_encode_f)(struct video_out_desc *v);
+
+/*! \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);
+
+/*! \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);
+
+/*! \brief actually call the decoder */
+typedef int (*decoder_decode_f)(struct video_in_desc *v);
+
+struct video_codec_desc {
+	int			format;		/* AST_FORMAT_* */
+	encoder_init_f		enc_init;
+	encoder_encap_f		enc_encap;
+	encoder_encode_f	enc_run;
+	decoder_init_f		dec_init;
+	decoder_decap_f		dec_decap;
+	decoder_decode_f	dec_run;
+};
+
+/*
  * The overall descriptor, with room for config info, video source and
  * received data descriptors, SDL info, etc.
  */
@@ -240,6 +273,8 @@
 	int 			bitrate;
 	char			videodevice[64];
 
+	int			rtp_fmt;	/* compressed format, AST_FORMAT_* */
+
 	pthread_t		vthread;	/* video thread */
 	int			shutdown;	/* set to shutdown vthread */
 	struct ast_channel	*owner;		/* owner channel */
@@ -254,30 +289,11 @@
 	SDL_Rect		rect[2];	/* loc. of images */
 };
 
-/*
- * Table of translation between asterisk and ffmpeg formats.
- * We need also a field for read and write (encoding and decoding), because
- * e.g. H263+ uses different codec IDs in ffmpeg when encoding or decoding.
- */
-struct _cm {	/* map ffmpeg codec types to asterisk formats */
-	uint32_t	ast_format;	/* 0 is a terminator */
-	enum CodecID	codec;
-	enum { CM_RD = 1, CM_WR = 2, CM_RDWD = 3 } rw;	/* read or write or both ? */
-};
-
 /*!
  * 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
-
-static struct _cm video_formats[] = {
-	{ AST_FORMAT_H263_PLUS,	CODEC_ID_H263, CM_RD }, /* incoming H263P ? */
-	{ 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 },
-	{ 0,			0, 0 },
-};
 
 static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p);
 
@@ -294,805 +310,40 @@
 	b->pix_fmt = x.pix_fmt;
 }
 
-/* Video4Linux stuff is only used in video_open() */
-#if HAVE_V4L > 0
-#include <linux/videodev.h>
-#endif
-
-/*!
- * Open the local video source and allocate a buffer
- * for storing the image. Return 0 on success, -1 on error
- */
-static int video_open(struct video_out_desc *v)
-{
-	struct fbuf_t *b = &v->loc_src;
-	if (b->data)	/* buffer allocated means device already open */
-		return v->fd;
-	v->fd = -1;
-	/*
-	 * if the device is "X11", then open the x11 grabber
-	 */
-    if (!strcasecmp(v->device, "X11")) {
-	int x_ofs = 0;
-	int y_ofs = 0;
-	XImage *im;
-
-	v->dpy = XOpenDisplay(NULL);
-	if (v->dpy == NULL) {
-		ast_log(LOG_WARNING, "error opening display\n");
-		goto error;
-	}
-	v->image = im = XGetImage(v->dpy,
-		RootWindow(v->dpy, DefaultScreen(v->dpy)),
-		x_ofs, y_ofs, b->w, b->h, AllPlanes, ZPixmap);
-	if (v->image == NULL) {
-		ast_log(LOG_WARNING, "error creating Ximage\n");
-		goto error;
-	}
-	switch (im->bits_per_pixel) {
-	case 32:
-		b->pix_fmt = PIX_FMT_RGBA32;
-		break;
-	case 16:
-		b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555;
-		break;
-	}
-	ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n",
-		im->data,
-		im->bits_per_pixel,
-		b->pix_fmt,
-		im->red_mask, im->green_mask, im->blue_mask);
-	/* set the pointer but not the size as this is not malloc'ed */
-	b->data = (uint8_t *)im->data;
-	v->fd = -2;
-    }
-#if HAVE_V4L > 0
-    else {
-	/* V4L specific */
-	struct video_window vw = { 0 };	/* camera attributes */
-	struct video_picture vp;
-	int i;
-
-	v->fd = open(v->device, O_RDONLY | O_NONBLOCK);
-	if (v->fd < 0) {
-		ast_log(LOG_WARNING, "error opening camera %s\n", v->device);
-		return v->fd;
-	}
-
-	i = fcntl(v->fd, F_GETFL);
-	if (-1 == fcntl(v->fd, F_SETFL, i | O_NONBLOCK)) {
-		/* non fatal, just emit a warning */
-		ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n",
-			v->device, strerror(errno));
-	}
-	/* set format for the camera.
-	 * In principle we could retry with a different format if the
-	 * one we are asking for is not supported.
-	 */
-	vw.width = v->loc_src.w;
-	vw.height = v->loc_src.h;
-	vw.flags = v->fps << 16;
-	if (ioctl(v->fd, VIDIOCSWIN, &vw) == -1) {
-		ast_log(LOG_WARNING, "error setting format for %s [%s]\n",
-			v->device, strerror(errno));
-		goto error;
-	}
-	if (ioctl(v->fd, VIDIOCGPICT, &vp) == -1) {
-		ast_log(LOG_WARNING, "error reading picture info\n");
-		goto error;
-	}
-	ast_log(LOG_WARNING,
-		"contrast %d bright %d colour %d hue %d white %d palette %d\n",
-		vp.contrast, vp.brightness,
-		vp.colour, vp.hue,
-		vp.whiteness, vp.palette);
-	/* set the video format. Here again, we don't necessary have to
-	 * fail if the required format is not supported, but try to use
-	 * what the camera gives us.
-	 */
-	b->pix_fmt = vp.palette;
-	vp.palette = VIDEO_PALETTE_YUV420P;
-	if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) {
-		ast_log(LOG_WARNING, "error setting palette, using %d\n",
-			b->pix_fmt);
-	} else
-		b->pix_fmt = vp.palette;
-	/* allocate the source buffer.
-	 * XXX, the code here only handles yuv411, for other formats
-	 * we need to look at pix_fmt and set size accordingly
-	 */
-	b->size = (b->w * b->h * 3)/2;	/* yuv411 */
-	ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n",
-		v->device, b->w, b->h, b->size);
-	v->loc_src.data = ast_calloc(1, b->size);
-	if (!b->data) {
-		ast_log(LOG_WARNING, "error allocating buffer %d bytes\n",
-			b->size);
-		goto error;
-	}
-	ast_log(LOG_WARNING, "success opening camera\n");
-    }
-#endif /* HAVE_V4L */
-
-	if (v->image == NULL && v->fd < 0)
-		goto error;
-	b->used = 0;
-	return 0;
-
-error:
-	ast_log(LOG_WARNING, "fd %d dpy %p img %p data %p\n",
-		v->fd, v->dpy, v->image, v->loc_src.data);
-	if (v->dpy)
-		XCloseDisplay(v->dpy);
-	v->dpy = NULL;
-	if (v->fd >= 0)
-		close(v->fd);
-	v->fd = -1;
-	free_fbuf(&v->loc_src);
-	return -1;
-}
-
-/*! \brief complete a buffer from the local video source.
- * Called by get_video_frames(), in turn called by the video thread.
- */
-static int video_read(struct video_out_desc *v)
-{
-	struct timeval now = ast_tvnow();
-	struct fbuf_t *b = &v->loc_src;
-
-	if (b->data == NULL)	/* not initialized */
-		return 0;
-
-	/* check if it is time to read */
-	if (ast_tvzero(v->last_frame))
-		v->last_frame = now;
-	if (ast_tvdiff_ms(now, v->last_frame) < 1000/v->fps)
-		return 0;	/* too early */
-	v->last_frame = now; /* XXX actually, should correct for drift */
-
-	if (v->image) {
-		/* read frame from X11 */
-		AVPicture p;
-		XGetSubImage(v->dpy,
-		    RootWindow(v->dpy, DefaultScreen(v->dpy)),
-		    0, 0, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0);
-
-		b->data = (uint8_t *)v->image->data;
-		fill_pict(b, &p);
-		return p.linesize[0] * b->h;
-	}
-	if (v->fd < 0)			/* no other source */
-		return 0;
-	for (;;) {
-		int r, l = v->loc_src.size - v->loc_src.used;
-		r = read(v->fd, v->loc_src.data + v->loc_src.used, 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;
-		v->loc_src.used += r;
-		if (r == l) {
-			v->loc_src.used = 0; /* prepare for next frame */
-			return v->loc_src.size;
-		}
-	}
-}
-
-/* Helper function to process incoming video.
- * For each incoming video call invoke ffmpeg_init() to intialize
- * the decoding structure then incoming video frames are processed
- * by write_video() which in turn calls pre_process_data(), to extract
- * the bitstream; accumulates data into a buffer within video_desc. When
- * a frame is complete (determined by the marker bit in the RTP header)
- * call decode_video() to decoding and if it successful call show_frame()
- * to display the frame.
- */
-
-
-/*! \brief map an asterisk format into an ffmpeg one */
-static enum CodecID map_video_format(uint32_t ast_format, int rw)
-{
-	struct _cm *i;
-
-	for (i = video_formats; i->ast_format != 0; i++)
-		if (ast_format & i->ast_format && rw & i->rw && rw & i->rw)
-			return i->codec;
-	return CODEC_ID_NONE;
-}
-
-/*! \brief uninitialize the descriptor for remote video stream */
-static int video_in_uninit(struct video_in_desc *v)
-{
-	if (v->dec_ctx) {
-		avcodec_close(v->dec_ctx);
-		av_free(v->dec_ctx);
-	}
-	if (v->frame)
-		av_free(v->frame);
-	free_fbuf(&v->dec_in);
-	free_fbuf(&v->dec_out);
-	free_fbuf(&v->rem_dpy);
-	bzero(v, sizeof(*v));	/* XXX too much, we are losing config info */
-	return -1;	/* error, in case someone cares */
-}
-
-/*
- * initialize ffmpeg resources used for decoding frames from the network.
- */
-static int video_in_init(struct video_in_desc *v, uint32_t format)
-{
-	enum CodecID codec;
-
-	v->codec = NULL;
-	v->dec_ctx = NULL;
-	v->frame = NULL;
-	v->parser = NULL;
-	v->completed = 0;
-	v->discard = 1;
-
-	codec = map_video_format(format, CM_RD);
-
-	v->codec = avcodec_find_decoder(codec);
-	if (!v->codec) {
-		ast_log(LOG_WARNING, "Unable to find the decoder for format %d\n", codec);
-		return video_in_uninit(v);
-	}
-	/*
-	* Initialize the codec context.
+/*----- codec specific code --------*/
+
+/*
+ * For each codec, we define the various callback in use
+ */
+
+static int h263p_enc_init(struct video_out_desc *v)
+{
+	/* modes supported are
+	- Unrestricted Motion Vector (annex D)
+	- Advanced Prediction (annex F)
+	- Advanced Intra Coding (annex I)
+	- Deblocking Filter (annex J)
+	- Slice Structure (annex K)
+	- Alternative Inter VLC (annex S)
+	- Modified Quantization (annex T)
 	*/
-	v->dec_ctx = avcodec_alloc_context();
-	if (avcodec_open(v->dec_ctx, v->codec) < 0) {
-		ast_log(LOG_WARNING, "Cannot open the codec context\n");
-		av_free(v->dec_ctx);
-		v->dec_ctx = NULL;
-		return video_in_uninit(v);
-	}
-
-	v->parser = av_parser_init(codec);
-	if (!v->parser) {
-		ast_log(LOG_WARNING, "Cannot initialize the decoder parser\n");
-		return video_in_uninit(v);
-	}
-
-	v->frame = avcodec_alloc_frame();
-	if (!v->frame) {
-		ast_log(LOG_WARNING, "Cannot allocate decoding video frame\n");
-		return video_in_uninit(v);
-	}
-	return 0;	/* ok */
-}
-
-/*! \brief uninitialize the descriptor for local video stream */
-static int video_out_uninit(struct video_out_desc *v)
-{
-	if (v->enc_ctx) {
-		avcodec_close(v->enc_ctx);
-		av_free(v->enc_ctx);
-	}
-
-	if (v->frame) 
-		av_free(v->frame);
-	free_fbuf(&v->loc_src);
-	free_fbuf(&v->enc_in);
-	free_fbuf(&v->enc_out);
-	free_fbuf(&v->loc_dpy);
-	if (v->image) {	/* X11 grabber */
-		XCloseDisplay(v->dpy);
-		v->dpy = NULL;
-		v->image = NULL;
-	}
-	if (v->fd >= 0) 
-		close(v->fd);
-	bzero(v, sizeof(*v));
-	v->fd = -1;
-	return -1;
-}
-
-/*
- * 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)
-{
-	int codec;
-	int size;
-	struct fbuf_t *enc_in;
-
-	v->enc_ctx		= NULL;
-	v->codec		= NULL;
-	v->frame		= NULL;
-	v->lasttxframe		= -1;
-	v->enc_out.data		= NULL;
-
-	if (v->loc_src.data == NULL) {
-		ast_log(LOG_WARNING, "No local source active\n");
-		return video_out_uninit(v);
-	}
-	codec = map_video_format(format, CM_WR);
-	v->codec = avcodec_find_encoder(codec);
-	if (!v->codec) {
-		ast_log(LOG_WARNING, "Cannot find the encoder for format %d\n",
-			codec);
-		return video_out_uninit(v);
-	}
-
-	v->mtu = 1400;	/* set it early so the encoder can use it */
-
-	/* allocate the input buffer for encoding.
-	 * ffmpeg only supports PIX_FMT_YUV420P for the encoding.
-	 */
-	enc_in = &v->enc_in;
-	enc_in->pix_fmt = PIX_FMT_YUV420P;
-	enc_in->size = (enc_in->w * enc_in->h * 3)/2;
-	enc_in->data = ast_calloc(1, enc_in->size);
-	if (!enc_in->data) {
-		ast_log(LOG_WARNING, "Cannot allocate encoder input buffer\n");
-		return video_out_uninit(v);
-	}
-	v->frame = avcodec_alloc_frame();
-	if (!v->frame) {
-		ast_log(LOG_WARNING, "Unable to allocate the encoding video frame\n");
-		return video_out_uninit(v);
-	}
-
-	/* Here we assume that the encoder has some 411 format */
-	size = enc_in->w * enc_in->h;
-	v->frame->data[0] = enc_in->data;
-	v->frame->data[1] = v->frame->data[0] + size;
-	v->frame->data[2] = v->frame->data[1] + size/4;
-	v->frame->linesize[0] = enc_in->w;
-	v->frame->linesize[1] = enc_in->w/2;
-	v->frame->linesize[2] = enc_in->w/2;
-
-	/* now setup the parameters for the encoder */
-	v->enc_ctx = avcodec_alloc_context();
-	v->enc_ctx->pix_fmt = enc_in->pix_fmt;
-	v->enc_ctx->width = enc_in->w;
-	v->enc_ctx->height = enc_in->h;
-	/* XXX rtp_callback ?
-	 * rtp_mode so ffmpeg inserts as many start codes as possible.
-	 */
-	v->enc_ctx->rtp_mode = 1;
-	v->enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
-	v->enc_ctx->bit_rate_tolerance = v->enc_ctx->bit_rate/2;
-
-	/* now set codec-specific parameters, which differ for
-	 * the various video codecs in use.
-	 * At the moment we only support h263p, but presumably we
-	 * need to deal with this in some external function.
-	 */
-	if (0) {	/* normal h263 */
-	} else {
-		/* modes supported are
-		- Unrestricted Motion Vector (annex D)
-		- Advanced Prediction (annex F)
-		- Advanced Intra Coding (annex I)
-		- Deblocking Filter (annex J)
-		- Slice Structure (annex K)
-		- Alternative Inter VLC (annex S)
-		- Modified Quantization (annex T)
-		*/
-		v->enc_ctx->flags |=CODEC_FLAG_H263P_UMV; /* annex D */
-		v->enc_ctx->flags |=CODEC_FLAG_AC_PRED; /* annex f ? */
-		v->enc_ctx->flags |=CODEC_FLAG_H263P_SLICE_STRUCT; /* annex k */
-		v->enc_ctx->flags |= CODEC_FLAG_H263P_AIC; /* annex I */
-	}
+	v->enc_ctx->flags |=CODEC_FLAG_H263P_UMV; /* annex D */
+	v->enc_ctx->flags |=CODEC_FLAG_AC_PRED; /* annex f ? */
+	v->enc_ctx->flags |=CODEC_FLAG_H263P_SLICE_STRUCT; /* annex k */
+	v->enc_ctx->flags |= CODEC_FLAG_H263P_AIC; /* annex I */
+
 	v->enc_ctx->bit_rate = v->bitrate;
 	v->enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds
 	v->enc_ctx->qmin = 3;	/* should be configured */
- 
-	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};
-	if (avcodec_open(v->enc_ctx, v->codec) < 0) {
-		ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n",
-			codec);
-		av_free(v->enc_ctx);
-		v->enc_ctx = NULL;
-		return video_out_uninit(v);
-	}
-
-	/*
-	 * Allocate enough for the encoded bitstream. As we are compressing,
-	 * we hope that the output is never larger than the input size.
-	 */
-	v->enc_out.data = ast_calloc(1, enc_in->size);
-	v->enc_out.size = enc_in->size;
-	v->enc_out.used = 0;
-
-
 	return 0;
 }
 
-/*! \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_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 */
-		bzero(env, sizeof(struct video_desc));
-		/* restore fields... */
-		bcopy(x.videodevice, env->videodevice, sizeof(env->videodevice));
-		env->w = x.w;
-		env->h = x.h;
-		env->fps = x.fps;
-		env->bitrate = x.bitrate;
-	}
-}
-
-#define MAKE_MASK(bits)                ( (1<<(bits)) -1 )
-
-/*
- * Get the P flag from the H.263+ header from the RTP payload (see RFC 2429).
- */
-static inline unsigned int rfc2429_get_P(const uint8_t *header){
-	return (header[0]>>2) & 0x1;
-}
-
-/*
- * Get the PLEN variable from the H.263+ header from the RTP payload (see RFC 2429).
- */
-static inline unsigned int rfc2429_get_PLEN(const uint8_t *header){
-	unsigned short *p=(unsigned short*)header;
-	return (ntohs(p[0])>>3) & MAKE_MASK(6);
-}
-
-/*! \brief extract the bitstreem from the RTP payload.
- * This is format dependent.
- * For h261, the format is defined in RFC 4587
- * and basically has a fixed 4-byte header as follows:
- * 3 bits	SBIT	start bit, how many msbits to ignore in first byte
- * 3 bits	EBIT	end bit, how many lsbits to ignore in last byte
- * 1 bit	I	1 if frame only contain INTRA blocks
- * 1 bit	V	0 if motion vector not used, 1 if may be used
- * 4 bits	GOBN	gob number at start of packet (0 for gob header)
- * 5 bits	MBAP	macroblock address predictor
- * 5 bits	QUANT	quantizer value
- * 5 bits	HMVD	horiz motion vector
- * 5 bits	VMVD	vert. motion vector
- *
- * For h263, the format is defined in RFC 2429
- * and basically has a fixed 2-byte header as follows:
- * 5 bits	RR	reserved, shall be 0
- * 1 bit	P	indicate a start/end condition,
- *			in which case the payload should be prepended
- *			by two zero-valued bytes.
- * 1 bit	V	there is an additional VRC header after this header
- * 6 bits	PLEN	length in bytes of extra picture header
- * 3 bits	PEBIT	how many bits to be ignored in the last byte
- *
- * XXX the code below is not complete.
- */
-static uint8_t *pre_process_data(uint8_t *data, int *len)
-{
-	int PLEN;
-	int P;
-
-	if (*len < 2) {
-		ast_log(LOG_WARNING, "invalid framesize %d\n", *len);
-		*len = 0;
-		return data;
-	}
-	PLEN = rfc2429_get_PLEN(data);
-	P = rfc2429_get_P(data);
-
-	if (PLEN > 0) {
-		data += PLEN;
-		(*len) -= PLEN;
-	}
-	if (P)
-		data[0] = data[1] = 0;
-	else {
-		data += 2;
-		(*len) -= 2;
-	}
-
-	return data;
-}
-
-/*
- * 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, struct fbuf_t *b)
-{
-	uint8_t *src = b->data;
-	int srclen = b->used;
-
-	if (!srclen)
-		return 0;
-	while (srclen) {
-		uint8_t *data;
-		int datalen;
-		int ret = av_parser_parse(v->parser, v->dec_ctx, &data, &datalen, src, srclen, 0, 0);
-		if (datalen) {
-			ret = avcodec_decode_video(v->dec_ctx, v->frame, &(v->completed), data, datalen);
-			if (ret < 0) {
-				ast_log(LOG_NOTICE, "Error decoding\n");
-				return 0;
-			}
-			src += ret;
-			srclen -= ret;
-		}
-	}
-	return 1;
-}
-
-/*! fill an AVPicture from our fbuf info, as it is required by
- * the image conversion routines in ffmpeg.
- * XXX This depends on the format.
- */
-static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p)
-{
-	/* provide defaults for commonly used formats */
-	int l4 = b->w * b->h/4; /* size of U or V frame */
-	int len = b->w;		/* Y linesize, bytes */
-	int luv = b->w/2;	/* U/V linesize, bytes */
-
-	bzero(p, sizeof(*p));
-	switch (b->pix_fmt) {
-	case PIX_FMT_RGB555:
-	case PIX_FMT_RGB565:
-		len *= 2;
-		luv = 0;
-		break;
-	case PIX_FMT_RGBA32:
-		len *= 4;
-		luv = 0;
-		break;
-	}
-	p->data[0] = b->data;
-	p->linesize[0] = len;
-	/* these are only valid for component images */
-	p->data[1] = luv ? b->data + 4*l4 : b->data+len;
-	p->data[2] = luv ? b->data + 5*l4 : b->data+len;
-	p->linesize[1] = luv;
-	p->linesize[2] = luv;
-	return p;
-}
-
-/*! convert/scale between an input and an output format.
- * Old version of ffmpeg only have img_convert, which does not rescale.
- * New versions use sws_scale which does both.
- */
-static void my_scale(struct fbuf_t *in, AVPicture *p_in,
-	struct fbuf_t *out, AVPicture *p_out)
-{
-	AVPicture my_p_in, my_p_out;
-
-	if (p_in == NULL)
-		p_in = fill_pict(in, &my_p_in);
-	if (p_out == NULL)
-		p_out = fill_pict(out, &my_p_out);
-
-#ifdef OLD_FFMPEG
-	/* XXX img_convert is deprecated, and does not do rescaling */
-	img_convert(p_out, out->pix_fmt,
-		p_in, in->pix_fmt, in->w, in->h);
-#else /* XXX replacement */
-    {
-	struct SwsContext *convert_ctx;
-
-	convert_ctx = sws_getContext(in->w, in->h, in->pix_fmt,
-		out->w, out->h, out->pix_fmt,
-		SWS_BICUBIC, NULL, NULL, NULL);
-	if (convert_ctx == NULL) {
-		ast_log(LOG_ERROR, "FFMPEG::convert_cmodel : swscale context initialization failed");
-		return;
-	}
-	if (0)
-		ast_log(LOG_WARNING, "in %d %dx%d out %d %dx%d\n",
-			in->pix_fmt, in->w, in->h, out->pix_fmt, out->w, out->h);
-	sws_scale(convert_ctx,
-		p_in->data, p_in->linesize,
-		in->w, in->h, /* src slice */
-		p_out->data, p_out->linesize);
-
-	sws_freeContext(convert_ctx);
-    }
-#endif /* XXX replacement */
-}
-
-/*
- * 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 the frame into it;
- * - After the frame is copied into the overlay, display it
- *
- * The size is taken from the configuration.
- *
- * 'out' is 0 for received data, 1 for the local video, 2 on init (debug)
- */
-static void show_frame(struct video_desc *env, int out)
-{
-	AVPicture *p_in, p_out;
-	struct fbuf_t *b_in, *b_out;
-	SDL_Overlay *bmp;
-
-	if (!env->sdl_ok)
-		return;
-
-	if (out) {	/* webcam/x11 to sdl */
-		b_in = &env->out.enc_in;
-		b_out = &env->out.loc_dpy;
-		p_in = NULL;
-	} else {
-		/* copy input format from the decoding context */
-		AVCodecContext *c = env->in.dec_ctx;
-		b_in = &env->in.dec_out;
-                b_in->pix_fmt = c->pix_fmt;
-                b_in->w = c->width;
-                b_in->h = c->height;
-
-		b_out = &env->in.rem_dpy;
-		p_in = (AVPicture *)env->in.frame;
-	}
-	bmp = env->bmp[out];
-	SDL_LockYUVOverlay(bmp);
-	/* output picture info - this is sdl, YUV420P */
-	bzero(&p_out, sizeof(p_out));
-	p_out.data[0] = bmp->pixels[0];
-	p_out.data[1] = bmp->pixels[1];
-	p_out.data[2] = bmp->pixels[2];
-	p_out.linesize[0] = bmp->pitches[0];
-	p_out.linesize[1] = bmp->pitches[1];
-	p_out.linesize[2] = bmp->pitches[2];
-
-	my_scale(b_in, p_in, b_out, &p_out);
-
-	/* lock to protect access to Xlib by different threads. */
-	ast_mutex_lock(&env->sdl_lock);
-	SDL_DisplayYUVOverlay(bmp, &env->rect[out]);
-	ast_mutex_unlock(&env->sdl_lock);
-	SDL_UnlockYUVOverlay(bmp);
-}
-
-static struct video_desc *get_video_desc(struct ast_channel *c);
-
-/*
- * This function is called (by asterisk) for each video packet
- * coming from the network (the 'in' path) that needs to be processed.
- * We need to reconstruct the entire video frame before we can decode it.
- * After a video packet is received we have to:
- * - extract the bitstream with pre_process_data()
- * - append the bitstream to a buffer
- * - if the fragment is the last (RTP Marker) we decode it with decode_video()
- * - after the decoding is completed we display the decoded frame with show_frame()
- */
-static int console_write_video(struct ast_channel *chan, struct ast_frame *f)
-{
-	uint8_t *data;
-	int len, need;
-	struct video_desc *env = get_video_desc(chan);
-	struct video_in_desc *v = &env->in;
-
-	if (v->dec_ctx == NULL) {
-		ast_log(LOG_WARNING, "cannot decode, dropping frame\n");
-		return 0;	/* error */
-	}
-
-#if defined(DROP_PACKETS) && DROP_PACKETS > 0
-	/*
-	 * Fragment of code to simulate lost/delayed packets
-	 */
-	if((random() % 10000) <= 100*DROP_PACKETS) {
-		ast_log(LOG_NOTICE, "Packet lost [%d]\n", f->seqno);
-		return 0;
-	}
-#endif
-	if (v->discard) {
-		ast_log(LOG_WARNING, "discard mode, drop frame %d\n", f->seqno);
-		/*
-		 * In discard mode, drop packets until we find one with
-		 * the RTP marker set (which is the end of frame).
-		 * XXX note that the RTP marker flag is sent as the LSB of the
-		 * subclass. This is slightly annoying as it goes to overwrite
-		 * the payload type entry.
-		 */
-		if (f->subclass & 0x01) {
-			v->dec_in.used = 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);
-		}
-		return 0;
-	}
-
-	/*
-	 * Only in-order fragments will be accepted. Remember seqno
-	 * has 16 bit so there is wraparound. Also, ideally we could
-	 * accept a bit of reordering, but at the moment wr don't.
-	 */
-	if (v->next_seq != f->seqno) {
-		ast_log(LOG_WARNING, "discarding frame out of order, %d %d\n",
-			v->next_seq, f->seqno);
-		v->discard = 1;
-		return 0;
-	}
-	v->next_seq++;
-
-	if (f->data == NULL || f->datalen < 2) {
-		ast_log(LOG_WARNING, "empty video frame, discard\n");
-		return 0;
-	}
-	len = f->datalen;
-	data = pre_process_data(f->data, &len);
-	if (len < 1 || len > 128*1024) {
-		ast_log(LOG_WARNING, "--- huge frame %d\n", len);
-		v->discard = 1;
-		return 0;
-	}
-
-	/*
-	 * 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;
-	if (v->dec_in.data == NULL) {
-		v->dec_in.size = need;
-		v->dec_in.used = 0;
-		v->dec_in.data = ast_malloc(v->dec_in.size);
-	} else if (v->dec_in.used + need > v->dec_in.size) {
-		v->dec_in.size = v->dec_in.used + need;
-		v->dec_in.data = ast_realloc(v->dec_in.data, v->dec_in.size);
-	}
-	if (v->dec_in.data == NULL) {
-		ast_log(LOG_WARNING, "alloc failure for %d, discard\n",
-			v->dec_in.size);
-		v->discard = 1;
-		return 0;
-	}
-	memcpy(v->dec_in.data + v->dec_in.used, data, len);
-	v->dec_in.used += len;
-	v->dec_in.data[v->dec_in.used] = '\0';
-	if (f->subclass & 0x01) {	// RTP Marker
-		if (decode_video(v, &v->dec_in)) {
-			show_frame(env, 0);
-			v->completed = 0;
-			v->dec_in.used = 0;
-		}
-	}
-	return 0;
-}
-
- 
-#ifndef MIN
-#define MIN(a, b) (a) < (b) ? (a) : (b)
-#endif
 
 /*
  * Create RTP/H.263 fragmets to avoid IP fragmentation
  */
-static struct ast_frame *split_frame(struct video_out_desc *out, int len, struct ast_frame **tail)
+static struct ast_frame *h263p_encap(struct video_out_desc *out,
+	int len, struct ast_frame **tail)
 {
 	struct ast_frame *cur = NULL, *first = NULL;
 	uint8_t *d = out->enc_out.data;
@@ -1173,6 +424,798 @@
 	return first;
 }
 
+#define MAKE_MASK(bits)                ( (1<<(bits)) -1 )
+
+/*
+ * Get the P flag from the H.263+ header from the RTP payload (see RFC 2429).
+ */
+static inline unsigned int rfc2429_get_P(const uint8_t *header){
+	return (header[0]>>2) & 0x1;
+}
+
+/*
+ * Get the PLEN variable from the H.263+ header from the RTP payload (see RFC 2429).
+ */
+static inline unsigned int rfc2429_get_PLEN(const uint8_t *header){
+	unsigned short *p=(unsigned short*)header;
+	return (ntohs(p[0])>>3) & MAKE_MASK(6);
+}
+
+/*! \brief extract the bitstreem from the RTP payload.
+ * This is format dependent.
+ * For h261, the format is defined in RFC 4587
+ * and basically has a fixed 4-byte header as follows:
+ * 3 bits	SBIT	start bit, how many msbits to ignore in first byte
+ * 3 bits	EBIT	end bit, how many lsbits to ignore in last byte
+ * 1 bit	I	1 if frame only contain INTRA blocks
+ * 1 bit	V	0 if motion vector not used, 1 if may be used
+ * 4 bits	GOBN	gob number at start of packet (0 for gob header)
+ * 5 bits	MBAP	macroblock address predictor
+ * 5 bits	QUANT	quantizer value
+ * 5 bits	HMVD	horiz motion vector
+ * 5 bits	VMVD	vert. motion vector
+ *
+ * For h263, the format is defined in RFC 2429
+ * and basically has a fixed 2-byte header as follows:
+ * 5 bits	RR	reserved, shall be 0
+ * 1 bit	P	indicate a start/end condition,
+ *			in which case the payload should be prepended
+ *			by two zero-valued bytes.
+ * 1 bit	V	there is an additional VRC header after this header
+ * 6 bits	PLEN	length in bytes of extra picture header
+ * 3 bits	PEBIT	how many bits to be ignored in the last byte
+ *
+ * XXX the code below is not complete.
+ */
+static uint8_t *h263p_decap(uint8_t *data, int *len)
+{
+	int PLEN;
+	int P;
+
+	if (*len < 2) {
+		ast_log(LOG_WARNING, "invalid framesize %d\n", *len);
+		*len = 0;
+		return data;
+	}
+	PLEN = rfc2429_get_PLEN(data);
+	P = rfc2429_get_P(data);
+
+	if (PLEN > 0) {
+		data += PLEN;
+		(*len) -= PLEN;
+	}
+	if (P)
+		data[0] = data[1] = 0;
+	else {
+		data += 2;
+		(*len) -= 2;
+	}
+
+	return data;
+}
+
+/*
+ * 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 h263p_decode(struct video_in_desc *v, struct fbuf_t *b)
+{
+	uint8_t *src = b->data;
+	int srclen = b->used;
+
+	if (!srclen)
+		return 0;
+	while (srclen) {
+		uint8_t *data;
+		int datalen;
+		int ret = av_parser_parse(v->parser, v->dec_ctx, &data, &datalen, src, srclen, 0, 0);
+		if (datalen) {
+			ret = avcodec_decode_video(v->dec_ctx, v->frame, &(v->completed), data, datalen);
+			if (ret < 0) {
+				ast_log(LOG_NOTICE, "Error decoding\n");
+				return 0;
+			}
+			src += ret;
+			srclen -= ret;
+		}
+	}
+	return 1;
+}
+
+/*------ end codec specific code -----*/
+
+
+/* Video4Linux stuff is only used in video_open() */
+#if HAVE_V4L > 0
+#include <linux/videodev.h>
+#endif
+
+/*!
+ * Open the local video source and allocate a buffer
+ * for storing the image. Return 0 on success, -1 on error
+ */
+static int video_open(struct video_out_desc *v)
+{
+	struct fbuf_t *b = &v->loc_src;
+	if (b->data)	/* buffer allocated means device already open */
+		return v->fd;
+	v->fd = -1;
+	/*
+	 * if the device is "X11", then open the x11 grabber
+	 */
+    if (!strcasecmp(v->device, "X11")) {
+	int x_ofs = 0;
+	int y_ofs = 0;
+	XImage *im;
+
+	v->dpy = XOpenDisplay(NULL);
+	if (v->dpy == NULL) {
+		ast_log(LOG_WARNING, "error opening display\n");
+		goto error;
+	}
+	v->image = im = XGetImage(v->dpy,
+		RootWindow(v->dpy, DefaultScreen(v->dpy)),
+		x_ofs, y_ofs, b->w, b->h, AllPlanes, ZPixmap);
+	if (v->image == NULL) {
+		ast_log(LOG_WARNING, "error creating Ximage\n");
+		goto error;
+	}
+	switch (im->bits_per_pixel) {
+	case 32:
+		b->pix_fmt = PIX_FMT_RGBA32;
+		break;
+	case 16:
+		b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555;
+		break;
+	}
+	ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n",
+		im->data,
+		im->bits_per_pixel,
+		b->pix_fmt,
+		im->red_mask, im->green_mask, im->blue_mask);
+	/* set the pointer but not the size as this is not malloc'ed */
+	b->data = (uint8_t *)im->data;
+	v->fd = -2;
+    }
+#if HAVE_V4L > 0
+    else {
+	/* V4L specific */
+	struct video_window vw = { 0 };	/* camera attributes */
+	struct video_picture vp;
+	int i;
+
+	v->fd = open(v->device, O_RDONLY | O_NONBLOCK);
+	if (v->fd < 0) {
+		ast_log(LOG_WARNING, "error opening camera %s\n", v->device);
+		return v->fd;
+	}
+
+	i = fcntl(v->fd, F_GETFL);
+	if (-1 == fcntl(v->fd, F_SETFL, i | O_NONBLOCK)) {
+		/* non fatal, just emit a warning */
+		ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n",
+			v->device, strerror(errno));
+	}
+	/* set format for the camera.
+	 * In principle we could retry with a different format if the
+	 * one we are asking for is not supported.
+	 */
+	vw.width = v->loc_src.w;
+	vw.height = v->loc_src.h;
+	vw.flags = v->fps << 16;
+	if (ioctl(v->fd, VIDIOCSWIN, &vw) == -1) {
+		ast_log(LOG_WARNING, "error setting format for %s [%s]\n",
+			v->device, strerror(errno));
+		goto error;
+	}
+	if (ioctl(v->fd, VIDIOCGPICT, &vp) == -1) {
+		ast_log(LOG_WARNING, "error reading picture info\n");
+		goto error;
+	}
+	ast_log(LOG_WARNING,
+		"contrast %d bright %d colour %d hue %d white %d palette %d\n",
+		vp.contrast, vp.brightness,
+		vp.colour, vp.hue,
+		vp.whiteness, vp.palette);
+	/* set the video format. Here again, we don't necessary have to
+	 * fail if the required format is not supported, but try to use
+	 * what the camera gives us.
+	 */
+	b->pix_fmt = vp.palette;
+	vp.palette = VIDEO_PALETTE_YUV420P;
+	if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) {
+		ast_log(LOG_WARNING, "error setting palette, using %d\n",
+			b->pix_fmt);
+	} else
+		b->pix_fmt = vp.palette;
+	/* allocate the source buffer.
+	 * XXX, the code here only handles yuv411, for other formats
+	 * we need to look at pix_fmt and set size accordingly
+	 */
+	b->size = (b->w * b->h * 3)/2;	/* yuv411 */
+	ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n",
+		v->device, b->w, b->h, b->size);
+	v->loc_src.data = ast_calloc(1, b->size);
+	if (!b->data) {
+		ast_log(LOG_WARNING, "error allocating buffer %d bytes\n",
+			b->size);
+		goto error;
+	}
+	ast_log(LOG_WARNING, "success opening camera\n");
+    }
+#endif /* HAVE_V4L */
+
+	if (v->image == NULL && v->fd < 0)
+		goto error;
+	b->used = 0;
+	return 0;
+
+error:
+	ast_log(LOG_WARNING, "fd %d dpy %p img %p data %p\n",
+		v->fd, v->dpy, v->image, v->loc_src.data);
+	if (v->dpy)
+		XCloseDisplay(v->dpy);
+	v->dpy = NULL;
+	if (v->fd >= 0)
+		close(v->fd);
+	v->fd = -1;
+	free_fbuf(&v->loc_src);
+	return -1;
+}
+
+/*! \brief complete a buffer from the local video source.
+ * Called by get_video_frames(), in turn called by the video thread.
+ */
+static int video_read(struct video_out_desc *v)
+{
+	struct timeval now = ast_tvnow();
+	struct fbuf_t *b = &v->loc_src;
+
+	if (b->data == NULL)	/* not initialized */
+		return 0;
+
+	/* check if it is time to read */
+	if (ast_tvzero(v->last_frame))
+		v->last_frame = now;
+	if (ast_tvdiff_ms(now, v->last_frame) < 1000/v->fps)
+		return 0;	/* too early */
+	v->last_frame = now; /* XXX actually, should correct for drift */
+
+	if (v->image) {
+		/* read frame from X11 */
+		AVPicture p;
+		XGetSubImage(v->dpy,
+		    RootWindow(v->dpy, DefaultScreen(v->dpy)),
+		    0, 0, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0);
+
+		b->data = (uint8_t *)v->image->data;
+		fill_pict(b, &p);
+		return p.linesize[0] * b->h;
+	}
+	if (v->fd < 0)			/* no other source */
+		return 0;
+	for (;;) {
+		int r, l = v->loc_src.size - v->loc_src.used;
+		r = read(v->fd, v->loc_src.data + v->loc_src.used, 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;
+		v->loc_src.used += r;
+		if (r == l) {
+			v->loc_src.used = 0; /* prepare for next frame */
+			return v->loc_src.size;
+		}
+	}
+}
+
+/* Helper function to process incoming video.
+ * For each incoming video call invoke ffmpeg_init() to intialize
+ * the decoding structure then incoming video frames are processed
+ * by write_video() which in turn calls pre_process_data(), to extract
+ * the bitstream; accumulates data into a buffer within video_desc. When
+ * a frame is complete (determined by the marker bit in the RTP header)
+ * call decode_video() to decoding and if it successful call show_frame()
+ * to display the frame.
+ */
+
+/*
+ * Table of translation between asterisk and ffmpeg formats.
+ * We need also a field for read and write (encoding and decoding), because
+ * e.g. H263+ uses different codec IDs in ffmpeg when encoding or decoding.
+ */
+struct _cm {	/* map ffmpeg codec types to asterisk formats */
+	uint32_t	ast_format;	/* 0 is a terminator */
+	enum CodecID	codec;
+	enum { CM_RD = 1, CM_WR = 2, CM_RDWD = 3 } rw;	/* read or write or both ? */
+	struct video_codec_desc *codec_desc;
+};
+
+static struct _cm video_formats[] = {
+	{ AST_FORMAT_H263_PLUS,	CODEC_ID_H263, CM_RD }, /* incoming H263P ? */
+	{ 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 },
+	{ 0,			0, 0 },
+};
+
+
+/*! \brief map an asterisk format into an ffmpeg one */
+static enum CodecID map_video_format(uint32_t ast_format, int rw)
+{
+	struct _cm *i;
+
+	for (i = video_formats; i->ast_format != 0; i++)
+		if (ast_format & i->ast_format && rw & i->rw && rw & i->rw)
+			return i->codec;
+	return CODEC_ID_NONE;
+}
+
+/*! \brief uninitialize the descriptor for remote video stream */
+static int video_in_uninit(struct video_in_desc *v)
+{
+	if (v->dec_ctx) {
+		avcodec_close(v->dec_ctx);
+		av_free(v->dec_ctx);
+	}
+	if (v->frame)
+		av_free(v->frame);
+	free_fbuf(&v->dec_in);
+	free_fbuf(&v->dec_out);
+	free_fbuf(&v->rem_dpy);
+	bzero(v, sizeof(*v));	/* XXX too much, we are losing config info */
+	return -1;	/* error, in case someone cares */
+}
+
+/*
+ * initialize ffmpeg resources used for decoding frames from the network.
+ */
+static int video_in_init(struct video_in_desc *v, uint32_t format)
+{
+	enum CodecID codec;
+
+	v->codec = NULL;
+	v->dec_ctx = NULL;
+	v->frame = NULL;
+	v->parser = NULL;
+	v->completed = 0;
+	v->discard = 1;
+
+	codec = map_video_format(format, CM_RD);
+
+	v->codec = avcodec_find_decoder(codec);
+	if (!v->codec) {
+		ast_log(LOG_WARNING, "Unable to find the decoder for format %d\n", codec);
+		return video_in_uninit(v);
+	}
+	/*
+	* Initialize the codec context.
+	*/
+	v->dec_ctx = avcodec_alloc_context();
+	if (avcodec_open(v->dec_ctx, v->codec) < 0) {
+		ast_log(LOG_WARNING, "Cannot open the codec context\n");
+		av_free(v->dec_ctx);
+		v->dec_ctx = NULL;
+		return video_in_uninit(v);
+	}
+
+	v->parser = av_parser_init(codec);
+	if (!v->parser) {
+		ast_log(LOG_WARNING, "Cannot initialize the decoder parser\n");
+		return video_in_uninit(v);
+	}
+
+	v->frame = avcodec_alloc_frame();
+	if (!v->frame) {
+		ast_log(LOG_WARNING, "Cannot allocate decoding video frame\n");
+		return video_in_uninit(v);
+	}
+	return 0;	/* ok */
+}
+
+/*! \brief uninitialize the descriptor for local video stream */
+static int video_out_uninit(struct video_out_desc *v)
+{
+	if (v->enc_ctx) {
+		avcodec_close(v->enc_ctx);
+		av_free(v->enc_ctx);
+	}
+
+	if (v->frame) 
+		av_free(v->frame);
+	free_fbuf(&v->loc_src);
+	free_fbuf(&v->enc_in);
+	free_fbuf(&v->enc_out);
+	free_fbuf(&v->loc_dpy);
+	if (v->image) {	/* X11 grabber */
+		XCloseDisplay(v->dpy);
+		v->dpy = NULL;
+		v->image = NULL;
+	}
+	if (v->fd >= 0) 
+		close(v->fd);
+	bzero(v, sizeof(*v));
+	v->fd = -1;
+	return -1;
+}
+
+/*
+ * 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)
+{
+	int codec;
+	int size;
+	struct fbuf_t *enc_in;
+
+	v->enc_ctx		= NULL;
+	v->codec		= NULL;
+	v->frame		= NULL;
+	v->lasttxframe		= -1;
+	v->enc_out.data		= NULL;
+
+	if (v->loc_src.data == NULL) {
+		ast_log(LOG_WARNING, "No local source active\n");
+		return video_out_uninit(v);
+	}
+	codec = map_video_format(format, CM_WR);

[... 364 lines stripped ...]



More information about the asterisk-commits mailing list