| 
									
										
										
										
											2007-12-29 02:02:03 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2008-01-01 23:54:40 +00:00
										 |  |  |  * Copyright 2007-2008, Sergio Fadda, Luigi Rizzo | 
					
						
							| 
									
										
										
										
											2007-12-29 02:02:03 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Video codecs support for console_video.c | 
					
						
							|  |  |  |  * $Revision$ | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-26 20:01:16 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | #include "console_video.h"
 | 
					
						
							|  |  |  | #include "asterisk/frame.h"
 | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | #include "asterisk/utils.h"	/* ast_calloc() */
 | 
					
						
							| 
									
										
										
										
											2007-12-26 20:01:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct video_out_desc; | 
					
						
							| 
									
										
										
										
											2007-12-28 22:37:40 +00:00
										 |  |  | struct video_dec_desc; | 
					
						
							| 
									
										
										
										
											2007-12-26 20:01:16 +00:00
										 |  |  | struct fbuf_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Each codec is defined by a number of callbacks | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /*! \brief initialize the encoder */ | 
					
						
							|  |  |  | typedef int (*encoder_init_f)(AVCodecContext *v); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief actually call the encoder */ | 
					
						
							|  |  |  | typedef int (*encoder_encode_f)(struct video_out_desc *v); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief encapsulate the bistream in RTP frames */ | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | typedef struct ast_frame *(*encoder_encap_f)(struct fbuf_t *, int mtu, | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		struct ast_frame **tail); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief inizialize the decoder */ | 
					
						
							|  |  |  | typedef int (*decoder_init_f)(AVCodecContext *enc_ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief extract the bitstream from RTP frames and store in the fbuf.
 | 
					
						
							|  |  |  |  * return 0 if ok, 1 on error | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | typedef int (*decoder_decap_f)(struct fbuf_t *b, uint8_t *data, int len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief actually call the decoder */ | 
					
						
							| 
									
										
										
										
											2007-12-28 22:37:40 +00:00
										 |  |  | typedef int (*decoder_decode_f)(struct video_dec_desc *v, struct fbuf_t *b); | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct video_codec_desc { | 
					
						
							|  |  |  | 	const char		*name;		/* format name */ | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-28 22:37:40 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Descriptor for the incoming stream, with multiple buffers for the bitstream | 
					
						
							|  |  |  |  * extracted from the RTP packets, RTP reassembly info, and a frame buffer | 
					
						
							|  |  |  |  * for the decoded frame (buf). | 
					
						
							|  |  |  |  * The descriptor is allocated as the first frame comes in. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Incoming payload is stored in one of the dec_in[] buffers, which are | 
					
						
							|  |  |  |  * emptied by the video thread. These buffers are organized in a circular | 
					
						
							|  |  |  |  * queue, with dec_in_cur being the buffer in use by the incoming stream, | 
					
						
							|  |  |  |  * and dec_in_dpy is the one being displayed. When the pointers need to | 
					
						
							|  |  |  |  * be changed, we synchronize the access to them with dec_lock. | 
					
						
							|  |  |  |  * When the list is full dec_in_cur = NULL (we cannot store new data), | 
					
						
							|  |  |  |  * when the list is empty dec_in_dpy = NULL (we cannot display frames). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct video_dec_desc { | 
					
						
							|  |  |  | 	struct video_codec_desc *d_callbacks;	/* decoder callbacks */ | 
					
						
							|  |  |  | 	AVCodecContext          *dec_ctx;	/* information about the codec in the stream */ | 
					
						
							|  |  |  | 	AVCodec                 *codec;		/* reference to the codec */ | 
					
						
							|  |  |  | 	AVFrame                 *d_frame;	/* place to store the decoded frame */ | 
					
						
							|  |  |  | 	AVCodecParserContext    *parser; | 
					
						
							|  |  |  | 	uint16_t 		next_seq;	/* must be 16 bit */ | 
					
						
							|  |  |  | 	int                     discard;	/* flag for discard status */ | 
					
						
							|  |  |  | #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 */ | 
					
						
							|  |  |  | 	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) */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | #ifdef debugging_only
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* some debugging code to check the bitstream:
 | 
					
						
							|  |  |  |  * declare a bit buffer, initialize it, and fetch data from it. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct bitbuf { | 
					
						
							|  |  |  | 	const uint8_t *base; | 
					
						
							|  |  |  | 	int	bitsize;	/* total size in bits */ | 
					
						
							|  |  |  | 	int	ofs;	/* next bit to read */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct bitbuf bitbuf_init(const uint8_t *base, int bitsize, int start_ofs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct bitbuf a; | 
					
						
							|  |  |  | 	a.base = base; | 
					
						
							|  |  |  | 	a.bitsize = bitsize; | 
					
						
							|  |  |  | 	a.ofs = start_ofs; | 
					
						
							|  |  |  | 	return a; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int bitbuf_left(struct bitbuf *b) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return b->bitsize - b->ofs; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint32_t getbits(struct bitbuf *b, int n) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i, ofs; | 
					
						
							|  |  |  | 	const uint8_t *d; | 
					
						
							|  |  |  | 	uint8_t mask; | 
					
						
							|  |  |  | 	uint32_t retval = 0; | 
					
						
							|  |  |  | 	if (n> 31) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "too many bits %d, max 32\n", n); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (n + b->ofs > b->bitsize) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "bitbuf overflow %d of %d\n", n + b->ofs, b->bitsize); | 
					
						
							|  |  |  | 		n = b->bitsize - b->ofs; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ofs = 7 - b->ofs % 8;	/* start from msb */ | 
					
						
							|  |  |  | 	mask = 1 << ofs; | 
					
						
							|  |  |  | 	d = b->base + b->ofs / 8;	/* current byte */ | 
					
						
							|  |  |  | 	for (i=0 ; i < n; i++) { | 
					
						
							|  |  |  | 		retval += retval + (*d & mask ? 1 : 0);	/* shift in new byte */ | 
					
						
							|  |  |  | 		b->ofs++; | 
					
						
							|  |  |  | 		mask >>= 1; | 
					
						
							|  |  |  | 		if (mask == 0) { | 
					
						
							|  |  |  | 			d++; | 
					
						
							|  |  |  | 			mask = 0x80; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return retval; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void check_h261(struct fbuf_t *b) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct bitbuf a = bitbuf_init(b->data, b->used * 8, 0); | 
					
						
							|  |  |  | 	uint32_t x, y; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	x = getbits(&a, 20);	/* PSC, 0000 0000 0000 0001 0000 */ | 
					
						
							|  |  |  | 	if (x != 0x10) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "bad PSC 0x%x\n", x); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	x = getbits(&a, 5);	/* temporal reference */ | 
					
						
							|  |  |  | 	y = getbits(&a, 6);	/* ptype */ | 
					
						
							|  |  |  | 	if (0) | 
					
						
							|  |  |  | 	ast_log(LOG_WARNING, "size %d TR %d PTY spl %d doc %d freeze %d %sCIF hi %d\n", | 
					
						
							|  |  |  | 		b->used, | 
					
						
							|  |  |  | 		x, | 
					
						
							|  |  |  | 		(y & 0x20) ? 1 : 0, | 
					
						
							|  |  |  | 		(y & 0x10) ? 1 : 0, | 
					
						
							|  |  |  | 		(y & 0x8) ? 1 : 0, | 
					
						
							|  |  |  | 		(y & 0x4) ? "" : "Q", | 
					
						
							|  |  |  | 		(y & 0x2) ? 1:0); | 
					
						
							|  |  |  | 	while ( (x = getbits(&a, 1)) == 1) | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "PSPARE 0x%x\n", getbits(&a, 8)); | 
					
						
							|  |  |  | 	// ast_log(LOG_WARNING, "PSPARE 0 - start GOB LAYER\n");
 | 
					
						
							|  |  |  | 	while ( (x = bitbuf_left(&a)) > 0) { | 
					
						
							|  |  |  | 		// ast_log(LOG_WARNING, "GBSC %d bits left\n", x);
 | 
					
						
							|  |  |  | 		x = getbits(&a, 16); /* GBSC 0000 0000 0000 0001 */ | 
					
						
							|  |  |  | 		if (x != 0x1) { | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "bad GBSC 0x%x\n", x); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		x = getbits(&a, 4);	/* group number */ | 
					
						
							|  |  |  | 		y = getbits(&a, 5);	/* gquant */ | 
					
						
							|  |  |  | 		if (x == 0) { | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "  bad GN %d\n", x); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		while ( (x = getbits(&a, 1)) == 1) | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "GSPARE 0x%x\n", getbits(&a, 8)); | 
					
						
							|  |  |  | 		while ( (x = bitbuf_left(&a)) > 0) { /* MB layer */ | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void dump_buf(struct fbuf_t *b); | 
					
						
							|  |  |  | void dump_buf(struct fbuf_t *b) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i, x, last2lines; | 
					
						
							|  |  |  | 	char buf[80]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	last2lines = (b->used - 16) & ~0xf; | 
					
						
							|  |  |  | 	ast_log(LOG_WARNING, "buf size %d of %d\n", b->used, b->size); | 
					
						
							|  |  |  | 	for (i = 0; i < b->used; i++) { | 
					
						
							|  |  |  | 		x = i & 0xf; | 
					
						
							|  |  |  | 		if ( x == 0) {	/* new line */ | 
					
						
							|  |  |  | 			if (i != 0) | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "%s\n", buf); | 
					
						
							| 
									
										
										
										
											2008-10-09 14:17:33 +00:00
										 |  |  | 			memset(buf, '\0', sizeof(buf)); | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 			sprintf(buf, "%04x: ", i); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		sprintf(buf + 6 + x*3, "%02x ", b->data[i]); | 
					
						
							|  |  |  | 		if (i > 31 && i < last2lines) | 
					
						
							|  |  |  | 			i = last2lines - 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (buf[0]) | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "%s\n", buf); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif /* debugging_only */
 | 
					
						
							| 
									
										
										
										
											2007-12-28 22:37:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * 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); | 
					
						
							| 
									
										
										
										
											2008-06-29 12:45:59 +00:00
										 |  |  | 	f->data.ptr = data; | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 	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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Append a chunk of data to a buffer taking care of bit alignment | 
					
						
							|  |  |  |  * Return 0 on success, != 0 on failure | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int fbuf_append(struct fbuf_t *b, uint8_t *src, int len, | 
					
						
							|  |  |  | 	int sbit, int ebit) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Allocate buffer. ffmpeg wants an extra FF_INPUT_BUFFER_PADDING_SIZE, | 
					
						
							|  |  |  | 	 * and also wants 0 as a buffer terminator to prevent trouble. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	int need = len + FF_INPUT_BUFFER_PADDING_SIZE; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	uint8_t *dst, mask; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (b->data == NULL) { | 
					
						
							|  |  |  | 		b->size = need; | 
					
						
							|  |  |  | 		b->used = 0; | 
					
						
							|  |  |  | 		b->ebit = 0; | 
					
						
							|  |  |  | 		b->data = ast_calloc(1, b->size); | 
					
						
							|  |  |  | 	} else if (b->used + need > b->size) { | 
					
						
							|  |  |  | 		b->size = b->used + need; | 
					
						
							|  |  |  | 		b->data = ast_realloc(b->data, b->size); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (b->data == NULL) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "alloc failure for %d, discard\n", | 
					
						
							|  |  |  | 			b->size); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (b->used == 0 && b->ebit != 0) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "ebit not reset at start\n"); | 
					
						
							|  |  |  | 		b->ebit = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dst = b->data + b->used; | 
					
						
							|  |  |  | 	i = b->ebit + sbit;	/* bits to ignore around */ | 
					
						
							|  |  |  | 	if (i == 0) {	/* easy case, just append */ | 
					
						
							|  |  |  | 		/* do everything in the common block */ | 
					
						
							|  |  |  | 	} else if (i == 8) { /* easy too, just handle the overlap byte */ | 
					
						
							|  |  |  | 		mask = (1 << b->ebit) - 1; | 
					
						
							|  |  |  | 		/* update the last byte in the buffer */ | 
					
						
							|  |  |  | 		dst[-1] &= ~mask;	/* clear bits to ignore */ | 
					
						
							|  |  |  | 		dst[-1] |= (*src & mask);	/* append new bits */ | 
					
						
							|  |  |  | 		src += 1;	/* skip and prepare for common block */ | 
					
						
							|  |  |  | 		len --; | 
					
						
							|  |  |  | 	} else {	/* must shift the new block, not done yet */ | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "must handle shift %d %d at %d\n", | 
					
						
							|  |  |  | 			b->ebit, sbit, b->used); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	memcpy(dst, src, len); | 
					
						
							|  |  |  | 	b->used += len; | 
					
						
							|  |  |  | 	b->ebit = ebit; | 
					
						
							|  |  |  | 	b->data[b->used] = 0;	/* padding */ | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-12-28 22:37:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Here starts the glue code for the various supported video codecs. | 
					
						
							|  |  |  |  * For each of them, we need to provide routines for initialization, | 
					
						
							|  |  |  |  * calling the encoder, encapsulating the bitstream in ast_frames, | 
					
						
							|  |  |  |  * extracting payload from ast_frames, and calling the decoder. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*--- h263+ support --- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief initialization of h263p */ | 
					
						
							|  |  |  | static int h263p_enc_init(AVCodecContext *enc_ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* 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) | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	enc_ctx->flags |=CODEC_FLAG_H263P_UMV; /* annex D */ | 
					
						
							|  |  |  | 	enc_ctx->flags |=CODEC_FLAG_AC_PRED; /* annex f ? */ | 
					
						
							|  |  |  | 	enc_ctx->flags |=CODEC_FLAG_H263P_SLICE_STRUCT; /* annex k */ | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_H263P_AIC; /* annex I */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Create RTP/H.263 fragments to avoid IP fragmentation. We fragment on a | 
					
						
							|  |  |  |  * PSC or a GBSC, but if we don't find a suitable place just break somewhere. | 
					
						
							|  |  |  |  * Everything is byte-aligned. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | static struct ast_frame *h263p_encap(struct fbuf_t *b, int mtu, | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	struct ast_frame **tail) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_frame *cur = NULL, *first = NULL; | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 	uint8_t *d = b->data; | 
					
						
							|  |  |  | 	int len = b->used; | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	int l = len; /* size of the current fragment. If 0, must look for a psc */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (;len > 0; len -= l, d += l) { | 
					
						
							|  |  |  | 		uint8_t *data; | 
					
						
							|  |  |  | 		struct ast_frame *f; | 
					
						
							|  |  |  | 		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. */ | 
					
						
							|  |  |  | 			for (i = 3; i < len - 3; i++) { | 
					
						
							|  |  |  | 				if (d[i] == 0 && d[i+1] == 0 && d[i+2] >= 0x80) { | 
					
						
							|  |  |  | 					l = i; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 		if (l > mtu || l > len) { /* psc not found, split */ | 
					
						
							|  |  |  | 			l = MIN(len, mtu); | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 		if (l < 1 || l > mtu) { | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 			ast_log(LOG_WARNING, "--- frame error l %d\n", l); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-29 12:45:59 +00:00
										 |  |  | 		data = f->data.ptr; | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		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
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!cur) | 
					
						
							|  |  |  | 			first = f; | 
					
						
							|  |  |  | 		cur = f; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cur) | 
					
						
							|  |  |  | 		cur->subclass |= 1; // RTP Marker
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*tail = cur;	/* end of the list */ | 
					
						
							|  |  |  | 	return first; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief extract the bitstreem from the RTP payload.
 | 
					
						
							|  |  |  |  * This is format dependent. | 
					
						
							|  |  |  |  * 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 int h263p_decap(struct fbuf_t *b, uint8_t *data, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int PLEN; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (len < 2) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "invalid framesize %d\n", len); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	PLEN = ( (data[0] & 1) << 5 ) | ( (data[1] & 0xf8) >> 3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (PLEN > 0) { | 
					
						
							|  |  |  | 		data += PLEN; | 
					
						
							|  |  |  | 		len -= PLEN; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (data[0] & 4)	/* bit P */ | 
					
						
							|  |  |  | 		data[0] = data[1] = 0; | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		data += 2; | 
					
						
							|  |  |  | 		len -= 2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return fbuf_append(b, data, len, 0, 0);	/* ignore trail bits */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * generic encoder, used by the various protocols supported here. | 
					
						
							|  |  |  |  * We assume that the buffer is empty at the beginning. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int ffmpeg_encode(struct video_out_desc *v) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fbuf_t *b = &v->enc_out; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b->used = avcodec_encode_video(v->enc_ctx, b->data, b->size, v->enc_in_frame); | 
					
						
							|  |  |  | 	i = avcodec_encode_video(v->enc_ctx, b->data + b->used, b->size - b->used, NULL); /* delayed frames ? */ | 
					
						
							|  |  |  | 	if (i > 0) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "have %d more bytes\n", i); | 
					
						
							|  |  |  | 		b->used += i; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-28 22:37:40 +00:00
										 |  |  | static int ffmpeg_decode(struct video_dec_desc *v, struct fbuf_t *b) | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	uint8_t *src = b->data; | 
					
						
							|  |  |  | 	int srclen = b->used; | 
					
						
							|  |  |  | 	int full_frame = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srclen == 0)	/* no data */ | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	while (srclen) { | 
					
						
							|  |  |  | 		uint8_t *data; | 
					
						
							|  |  |  | 		int datalen, ret; | 
					
						
							|  |  |  | 		int len = av_parser_parse(v->parser, v->dec_ctx, &data, &datalen, src, srclen, 0, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		src += len; | 
					
						
							|  |  |  | 		srclen -= len; | 
					
						
							|  |  |  | 		/* The parser might return something it cannot decode, so it skips
 | 
					
						
							|  |  |  | 		 * the block returning no data | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if (data == NULL || datalen == 0) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		ret = avcodec_decode_video(v->dec_ctx, v->d_frame, &full_frame, data, datalen); | 
					
						
							|  |  |  | 		if (full_frame == 1)	/* full frame */ | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		if (ret < 0) { | 
					
						
							|  |  |  | 			ast_log(LOG_NOTICE, "Error decoding\n"); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (srclen != 0)	/* update b with leftover data */ | 
					
						
							| 
									
										
										
										
											2008-10-09 14:17:33 +00:00
										 |  |  | 		memmove(b->data, src, srclen); | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	b->used = srclen; | 
					
						
							|  |  |  | 	b->ebit = 0; | 
					
						
							|  |  |  | 	return full_frame; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct video_codec_desc h263p_codec = { | 
					
						
							|  |  |  | 	.name = "h263p", | 
					
						
							|  |  |  | 	.format = AST_FORMAT_H263_PLUS, | 
					
						
							|  |  |  | 	.enc_init = h263p_enc_init, | 
					
						
							|  |  |  | 	.enc_encap = h263p_encap, | 
					
						
							|  |  |  | 	.enc_run = ffmpeg_encode, | 
					
						
							|  |  |  | 	.dec_init = NULL, | 
					
						
							|  |  |  | 	.dec_decap = h263p_decap, | 
					
						
							|  |  |  | 	.dec_run = ffmpeg_decode | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*--- Plain h263 support --------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int h263_enc_init(AVCodecContext *enc_ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* XXX check whether these are supported */ | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_H263P_UMV; | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_H263P_AIC; | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_H263P_SLICE_STRUCT; | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_AC_PRED; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * An RTP frame can start with a PSC 0000 0000 0000 0000 1000 0 | 
					
						
							|  |  |  |  * or with a GBSC, which also has the first 17 bits as a PSC. | 
					
						
							|  |  |  |  * Note - PSC are byte-aligned, GOB not necessarily. PSC 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)  | 
					
						
							|  |  |  |  *  | 
					
						
							|  |  |  |  * The assumption below is that we start with a PSC. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | static struct ast_frame *h263_encap(struct fbuf_t *b, int mtu, | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		struct ast_frame **tail) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 	uint8_t *d = b->data; | 
					
						
							|  |  |  | 	int start = 0, i, len = b->used; | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	struct ast_frame *f, *cur = NULL, *first = NULL; | 
					
						
							|  |  |  | 	const int pheader_len = 4;	/* Use RFC-2190 Mode A */ | 
					
						
							|  |  |  | 	uint8_t h263_hdr[12];	/* worst case, room for a type c header */ | 
					
						
							|  |  |  | 	uint8_t *h = h263_hdr;	/* shorthand */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define H263_MIN_LEN	6
 | 
					
						
							|  |  |  | 	if (len < H263_MIN_LEN)	/* unreasonably small */ | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-09 14:17:33 +00:00
										 |  |  | 	memset(h263_hdr, '\0', sizeof(h263_hdr)); | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	/* Now set the header bytes. Only type A by now,
 | 
					
						
							|  |  |  | 	 * and h[0] = h[2] = h[3] = 0 by default. | 
					
						
							|  |  |  | 	 * PTYPE starts 30 bits in the picture, 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 | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	h[1] = ( (d[4] & 0x1f) << 3 ) |	/* SRC, I, U */ | 
					
						
							|  |  |  | 		( (d[5] & 0xc0) >> 5 );		/* S, A, R */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* now look for the next PSC or GOB header. First try to hit
 | 
					
						
							|  |  |  | 	 * a '0' byte then look around for the 0000 0000 0000 0000 1 pattern | 
					
						
							|  |  |  | 	 * which is both in the PSC and the GBSC. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	for (i = H263_MIN_LEN, start = 0; start < len; start = i, i += 3) { | 
					
						
							|  |  |  | 		//ast_log(LOG_WARNING, "search at %d of %d/%d\n", i, start, len);
 | 
					
						
							|  |  |  | 		for (; i < len ; i++) { | 
					
						
							|  |  |  | 			uint8_t x, rpos, lpos; | 
					
						
							|  |  |  | 			int rpos_i;	/* index corresponding to rpos */ | 
					
						
							|  |  |  | 			if (d[i] != 0)		/* cannot be in a GBSC */ | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			if (i > len - 1) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			x = d[i+1]; | 
					
						
							|  |  |  | 			if (x == 0)	/* next is equally good */ | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			/* see if around us we can make 16 '0' bits for the GBSC.
 | 
					
						
							|  |  |  | 			 * Look for the first bit set on the right, and then | 
					
						
							|  |  |  | 			 * see if we have enough 0 on the left. | 
					
						
							|  |  |  | 			 * We are guaranteed to end before rpos == 0 | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			for (rpos = 0x80, rpos_i = 8; rpos; rpos >>= 1, rpos_i--) | 
					
						
							|  |  |  | 				if (x & rpos)	/* found the '1' bit in GBSC */ | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 			x = d[i-1];		/* now look behind */ | 
					
						
							|  |  |  | 			for (lpos = rpos; lpos ; lpos >>= 1) | 
					
						
							|  |  |  | 				if (x & lpos)	/* too early, not a GBSC */ | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 			if (lpos)		/* as i said... */ | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			/* now we have a GBSC starting somewhere in d[i-1],
 | 
					
						
							|  |  |  | 			 * but it might be not byte-aligned | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			if (rpos == 0x80) {	/* lucky case */ | 
					
						
							|  |  |  | 				i = i - 1; | 
					
						
							|  |  |  | 			} else {	/* XXX to be completed */ | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "unaligned GBSC 0x%x %d\n", | 
					
						
							|  |  |  | 					rpos, rpos_i); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/* This frame is up to offset i (not inclusive).
 | 
					
						
							|  |  |  | 		 * We do not split it yet even if larger than MTU. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		f = create_video_frame(d + start, d+i, AST_FORMAT_H263, | 
					
						
							|  |  |  | 				pheader_len, cur); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!f) | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2008-10-09 14:17:33 +00:00
										 |  |  | 		memmove(f->data.ptr, h, 4);	/* copy the h263 header */ | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		/* XXX to do: if not aligned, fix sbit and ebit,
 | 
					
						
							|  |  |  | 		 * then move i back by 1 for the next frame | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		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 int h263_decap(struct fbuf_t *b, uint8_t *data, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (len < 4) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "invalid framesize %d\n", len); | 
					
						
							|  |  |  | 		return 1;	/* error */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ( (data[0] & 0x80) == 0) { | 
					
						
							|  |  |  | 		len -= 4; | 
					
						
							|  |  |  | 		data += 4; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "unsupported mode 0x%x\n", | 
					
						
							|  |  |  | 			data[0]); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return fbuf_append(b, data, len, 0, 0);	/* XXX no bit alignment support yet */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct video_codec_desc h263_codec = { | 
					
						
							|  |  |  | 	.name = "h263", | 
					
						
							|  |  |  | 	.format = AST_FORMAT_H263, | 
					
						
							|  |  |  | 	.enc_init = h263_enc_init, | 
					
						
							|  |  |  | 	.enc_encap = h263_encap, | 
					
						
							|  |  |  | 	.enc_run = ffmpeg_encode, | 
					
						
							|  |  |  | 	.dec_init = NULL, | 
					
						
							|  |  |  | 	.dec_decap = h263_decap, | 
					
						
							|  |  |  | 	.dec_run = ffmpeg_decode | 
					
						
							|  |  |  | 						 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*---- h261 support -----*/ | 
					
						
							|  |  |  | static int h261_enc_init(AVCodecContext *enc_ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* It is important to set rtp_payload_size = 0, otherwise
 | 
					
						
							|  |  |  | 	 * ffmpeg in h261 mode will produce output that it cannot parse. | 
					
						
							|  |  |  | 	 * Also try to send I frames more frequently than with other codecs. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	enc_ctx->rtp_payload_size = 0; /* important - ffmpeg fails otherwise */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The encapsulation of H261 is defined in RFC4587 which obsoletes RFC2032 | 
					
						
							|  |  |  |  * The bitstream is preceded by a 32-bit header word: | 
					
						
							|  |  |  |  *  SBIT:3 EBIT:3 I:1 V:1 GOBN:4 MBAP:5 QUANT:5 HMVD:5 VMVD:5 | 
					
						
							|  |  |  |  * SBIT and EBIT are the bits to be ignored at beginning and end, | 
					
						
							|  |  |  |  * I=1 if the stream has only INTRA frames - cannot change during the stream. | 
					
						
							|  |  |  |  * V=0 if motion vector is not used. Cannot change. | 
					
						
							|  |  |  |  * GOBN is the GOB number in effect at the start of packet, 0 if we | 
					
						
							|  |  |  |  *	start with a GOB header | 
					
						
							|  |  |  |  * QUANT is the quantizer in effect, 0 if we start with GOB header | 
					
						
							|  |  |  |  * HMVD  reference horizontal motion vector. 10000 is forbidden | 
					
						
							|  |  |  |  * VMVD  reference vertical motion vector, as above. | 
					
						
							|  |  |  |  * Packetization should occur at GOB boundaries, and if not possible | 
					
						
							|  |  |  |  * with MacroBlock fragmentation. However it is likely that blocks | 
					
						
							|  |  |  |  * are not bit-aligned so we must take care of this. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | static struct ast_frame *h261_encap(struct fbuf_t *b, int mtu, | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		struct ast_frame **tail) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 	uint8_t *d = b->data; | 
					
						
							|  |  |  | 	int start = 0, i, len = b->used; | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	struct ast_frame *f, *cur = NULL, *first = NULL; | 
					
						
							|  |  |  | 	const int pheader_len = 4; | 
					
						
							|  |  |  | 	uint8_t h261_hdr[4]; | 
					
						
							|  |  |  | 	uint8_t *h = h261_hdr;	/* shorthand */ | 
					
						
							|  |  |  | 	int sbit = 0, ebit = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define H261_MIN_LEN 10
 | 
					
						
							|  |  |  | 	if (len < H261_MIN_LEN)	/* unreasonably small */ | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-09 14:17:33 +00:00
										 |  |  | 	memset(h261_hdr, '\0', sizeof(h261_hdr)); | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Similar to the code in h263_encap, but the marker there is longer.
 | 
					
						
							|  |  |  | 	 * Start a few bytes within the bitstream to avoid hitting the marker | 
					
						
							|  |  |  | 	 * twice. Note we might access the buffer at len, but this is ok because | 
					
						
							|  |  |  | 	 * the caller has it oversized. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	for (i = H261_MIN_LEN, start = 0; start < len - 1; start = i, i += 4) { | 
					
						
							|  |  |  | #if 0	/* test - disable packetization */
 | 
					
						
							|  |  |  | 		i = len;	/* wrong... */ | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 		int found = 0, found_ebit = 0;	/* last GBSC position found */ | 
					
						
							|  |  |  | 		for (; i < len ; i++) { | 
					
						
							|  |  |  | 			uint8_t x, rpos, lpos; | 
					
						
							|  |  |  | 			if (d[i] != 0)		/* cannot be in a GBSC */ | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			x = d[i+1]; | 
					
						
							|  |  |  | 			if (x == 0)	/* next is equally good */ | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			/* See if around us we find 15 '0' bits for the GBSC.
 | 
					
						
							|  |  |  | 			 * Look for the first bit set on the right, and then | 
					
						
							|  |  |  | 			 * see if we have enough 0 on the left. | 
					
						
							|  |  |  | 			 * We are guaranteed to end before rpos == 0 | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			for (rpos = 0x80, ebit = 7; rpos; ebit--, rpos >>= 1) | 
					
						
							|  |  |  | 				if (x & rpos)	/* found the '1' bit in GBSC */ | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 			x = d[i-1];		/* now look behind */ | 
					
						
							|  |  |  | 			for (lpos = (rpos >> 1); lpos ; lpos >>= 1) | 
					
						
							|  |  |  | 				if (x & lpos)	/* too early, not a GBSC */ | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 			if (lpos)		/* as i said... */ | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			/* now we have a GBSC starting somewhere in d[i-1],
 | 
					
						
							|  |  |  | 			 * but it might be not byte-aligned. Just remember it. | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 			if (i - start > mtu) /* too large, stop now */ | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			found_ebit = ebit; | 
					
						
							|  |  |  | 			found = i; | 
					
						
							|  |  |  | 			i += 4;	/* continue forward */ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (i >= len) {	/* trim if we went too forward */ | 
					
						
							|  |  |  | 			i = len; | 
					
						
							|  |  |  | 			ebit = 0;	/* hopefully... should ask the bitstream ? */ | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 		if (i - start > mtu && found) { | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 			/* use the previous GBSC, hope is within the mtu */ | 
					
						
							|  |  |  | 			i = found; | 
					
						
							|  |  |  | 			ebit = found_ebit; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | #endif /* test */
 | 
					
						
							|  |  |  | 		if (i - start < 4)	/* XXX too short ? */ | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		/* This frame is up to offset i (not inclusive).
 | 
					
						
							|  |  |  | 		 * We do not split it yet even if larger than MTU. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		f = create_video_frame(d + start, d+i, AST_FORMAT_H261, | 
					
						
							|  |  |  | 				pheader_len, cur); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!f) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		/* recompute header with I=0, V=1 */ | 
					
						
							|  |  |  | 		h[0] = ( (sbit & 7) << 5 ) | ( (ebit & 7) << 2 ) | 1; | 
					
						
							| 
									
										
										
										
											2008-10-09 14:17:33 +00:00
										 |  |  | 		memmove(f->data.ptr, h, 4);	/* copy the h261 header */ | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		if (ebit)	/* not aligned, restart from previous byte */ | 
					
						
							|  |  |  | 			i--; | 
					
						
							|  |  |  | 		sbit = (8 - ebit) & 7; | 
					
						
							|  |  |  | 		ebit = 0; | 
					
						
							|  |  |  | 		if (!cur) | 
					
						
							|  |  |  | 			first = f; | 
					
						
							|  |  |  | 		cur = f; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (cur) | 
					
						
							|  |  |  | 		cur->subclass |= 1;	// RTP Marker
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*tail = cur; | 
					
						
							|  |  |  | 	return first; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Pieces might be unaligned so we really need to put them together. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int h261_decap(struct fbuf_t *b, uint8_t *data, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ebit, sbit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (len < 8) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "invalid framesize %d\n", len); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sbit = (data[0] >> 5) & 7; | 
					
						
							|  |  |  | 	ebit = (data[0] >> 2) & 7; | 
					
						
							|  |  |  | 	len -= 4; | 
					
						
							|  |  |  | 	data += 4; | 
					
						
							|  |  |  | 	return fbuf_append(b, data, len, sbit, ebit); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct video_codec_desc h261_codec = { | 
					
						
							|  |  |  | 	.name = "h261", | 
					
						
							|  |  |  | 	.format = AST_FORMAT_H261, | 
					
						
							|  |  |  | 	.enc_init = h261_enc_init, | 
					
						
							|  |  |  | 	.enc_encap = h261_encap, | 
					
						
							|  |  |  | 	.enc_run = ffmpeg_encode, | 
					
						
							|  |  |  | 	.dec_init = NULL, | 
					
						
							|  |  |  | 	.dec_decap = h261_decap, | 
					
						
							|  |  |  | 	.dec_run = ffmpeg_decode | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* mpeg4 support */ | 
					
						
							|  |  |  | static int mpeg4_enc_init(AVCodecContext *enc_ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  | 	//enc_ctx->flags |= CODEC_FLAG_LOW_DELAY; /*don't use b frames ?*/
 | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_AC_PRED; | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_H263P_UMV; | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_QPEL; | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_4MV; | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_GMC; | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_LOOP_FILTER; | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_H263P_SLICE_STRUCT; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	enc_ctx->rtp_payload_size = 0; /* important - ffmpeg fails otherwise */ | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* simplistic encapsulation - just split frames in mtu-size units */ | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | static struct ast_frame *mpeg4_encap(struct fbuf_t *b, int mtu, | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	struct ast_frame **tail) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_frame *f, *cur = NULL, *first = NULL; | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 	uint8_t *d = b->data; | 
					
						
							|  |  |  | 	uint8_t *end = d + b->used; | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	int len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (;d < end; d += len, cur = f) { | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 		len = MIN(mtu, end - d); | 
					
						
							|  |  |  | 		f = create_video_frame(d, d + len, AST_FORMAT_MP4_VIDEO, 0, cur); | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		if (!f) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		if (!first) | 
					
						
							|  |  |  | 			first = f; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (cur) | 
					
						
							|  |  |  | 		cur->subclass |= 1; | 
					
						
							|  |  |  | 	*tail = cur; | 
					
						
							|  |  |  | 	return first; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int mpeg4_decap(struct fbuf_t *b, uint8_t *data, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return fbuf_append(b, data, len, 0, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-28 22:37:40 +00:00
										 |  |  | static int mpeg4_decode(struct video_dec_desc *v, struct fbuf_t *b) | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	int full_frame = 0, datalen = b->used; | 
					
						
							|  |  |  | 	int ret = avcodec_decode_video(v->dec_ctx, v->d_frame, &full_frame, | 
					
						
							|  |  |  | 		b->data, datalen); | 
					
						
							|  |  |  | 	if (ret < 0) { | 
					
						
							|  |  |  | 		ast_log(LOG_NOTICE, "Error decoding\n"); | 
					
						
							|  |  |  | 		ret = datalen; /* assume we used everything. */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	datalen -= ret; | 
					
						
							|  |  |  | 	if (datalen > 0)	/* update b with leftover bytes */ | 
					
						
							| 
									
										
										
										
											2008-10-09 14:17:33 +00:00
										 |  |  | 		memmove(b->data, b->data + ret, datalen); | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	b->used = datalen; | 
					
						
							|  |  |  | 	b->ebit = 0; | 
					
						
							|  |  |  | 	return full_frame; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct video_codec_desc mpeg4_codec = { | 
					
						
							|  |  |  | 	.name = "mpeg4", | 
					
						
							|  |  |  | 	.format = AST_FORMAT_MP4_VIDEO, | 
					
						
							|  |  |  | 	.enc_init = mpeg4_enc_init, | 
					
						
							|  |  |  | 	.enc_encap = mpeg4_encap, | 
					
						
							|  |  |  | 	.enc_run = ffmpeg_encode, | 
					
						
							|  |  |  | 	.dec_init = NULL, | 
					
						
							|  |  |  | 	.dec_decap = mpeg4_decap, | 
					
						
							|  |  |  | 	.dec_run = mpeg4_decode | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int h264_enc_init(AVCodecContext *enc_ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	enc_ctx->flags |= CODEC_FLAG_TRUNCATED; | 
					
						
							|  |  |  | 	//enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
 | 
					
						
							|  |  |  | 	//enc_ctx->flags2 |= CODEC_FLAG2_FASTPSKIP;
 | 
					
						
							|  |  |  | 	/* TODO: Maybe we need to add some other flags */ | 
					
						
							|  |  |  | 	enc_ctx->rtp_mode = 0; | 
					
						
							|  |  |  | 	enc_ctx->rtp_payload_size = 0; | 
					
						
							|  |  |  | 	enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int h264_dec_init(AVCodecContext *dec_ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	dec_ctx->flags |= CODEC_FLAG_TRUNCATED; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The structure of a generic H.264 stream is: | 
					
						
							|  |  |  |  * - 0..n 0-byte(s), unused, optional. one zero-byte is always present | 
					
						
							|  |  |  |  *   in the first NAL before the start code prefix. | 
					
						
							|  |  |  |  * - start code prefix (3 bytes): 0x000001 | 
					
						
							|  |  |  |  *   (the first bytestream has a  | 
					
						
							|  |  |  |  *   like these 0x00000001!) | 
					
						
							|  |  |  |  * - NAL header byte ( F[1] | NRI[2] | Type[5] ) where type != 0 | 
					
						
							|  |  |  |  * - byte-stream | 
					
						
							|  |  |  |  * - 0..n 0-byte(s) (padding, unused). | 
					
						
							|  |  |  |  * Segmentation in RTP only needs to be done on start code prefixes. | 
					
						
							|  |  |  |  * If fragments are too long... we don't support it yet. | 
					
						
							|  |  |  |  * - encapsulate (or fragment) the byte-stream (with NAL header included) | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | static struct ast_frame *h264_encap(struct fbuf_t *b, int mtu, | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	struct ast_frame **tail) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_frame *f = NULL, *cur = NULL, *first = NULL; | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 	uint8_t *d, *start = b->data; | 
					
						
							|  |  |  | 	uint8_t *end = start + b->used; | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Search the first start code prefix - ITU-T H.264 sec. B.2,
 | 
					
						
							|  |  |  | 	 * and move start right after that, on the NAL header byte. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | #define HAVE_NAL(x) (x[-4] == 0 && x[-3] == 0 && x[-2] == 0 && x[-1] == 1)
 | 
					
						
							|  |  |  | 	for (start += 4; start < end; start++) { | 
					
						
							|  |  |  | 		int ty = start[0] & 0x1f; | 
					
						
							|  |  |  | 		if (HAVE_NAL(start) && ty != 0 && ty != 31) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* if not found, or too short, we just skip the next loop and are done. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Here follows the main loop to create frames. Search subsequent start
 | 
					
						
							|  |  |  | 	 * codes, and then possibly fragment the unit into smaller fragments. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  |    for (;start < end - 4; start = d) { | 
					
						
							|  |  |  | 	int size;		/* size of current block */ | 
					
						
							|  |  |  | 	uint8_t hdr[2];		/* add-on header when fragmenting */ | 
					
						
							|  |  |  | 	int ty = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* now search next nal */ | 
					
						
							|  |  |  | 	for (d = start + 4; d < end; d++) { | 
					
						
							|  |  |  | 		ty = d[0] & 0x1f; | 
					
						
							|  |  |  | 		if (HAVE_NAL(d)) | 
					
						
							|  |  |  | 			break;	/* found NAL */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* have a block to send. d past the start code unless we overflow */ | 
					
						
							|  |  |  | 	if (d >= end) {	/* NAL not found */ | 
					
						
							|  |  |  | 		d = end + 4; | 
					
						
							|  |  |  | 	} else if (ty == 0 || ty == 31) { /* found but invalid type, skip */ | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "skip invalid nal type %d at %d of %d\n", | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 			ty, d - (uint8_t *)b->data, b->used); | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		continue; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	size = d - start - 4;	/* don't count the end */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 	if (size < mtu) {	// test - don't fragment
 | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		// Single NAL Unit
 | 
					
						
							|  |  |  | 		f = create_video_frame(start, d - 4, AST_FORMAT_H264, 0, cur); | 
					
						
							|  |  |  | 		if (!f) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		if (!first) | 
					
						
							|  |  |  | 			first = f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cur = f; | 
					
						
							|  |  |  | 		continue; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Fragmented Unit (Mode A: no DON, very weak)
 | 
					
						
							|  |  |  | 	hdr[0] = (*start & 0xe0) | 28;	/* mark as a fragmentation unit */ | 
					
						
							|  |  |  | 	hdr[1] = (*start++ & 0x1f) | 0x80 ;	/* keep type and set START bit */ | 
					
						
							|  |  |  | 	size--;		/* skip the NAL header */ | 
					
						
							|  |  |  | 	while (size) { | 
					
						
							|  |  |  | 		uint8_t *data; | 
					
						
							| 
									
										
										
										
											2007-12-28 23:04:04 +00:00
										 |  |  | 		int frag_size = MIN(size, mtu); | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		f = create_video_frame(start, start+frag_size, AST_FORMAT_H264, 2, cur); | 
					
						
							|  |  |  | 		if (!f) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		size -= frag_size;	/* skip this data block */ | 
					
						
							|  |  |  | 		start += frag_size; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-29 12:45:59 +00:00
										 |  |  | 		data = f->data.ptr; | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 		data[0] = hdr[0]; | 
					
						
							|  |  |  | 		data[1] = hdr[1] | (size == 0 ? 0x40 : 0);	/* end bit if we are done */ | 
					
						
							|  |  |  | 		hdr[1] &= ~0x80;	/* clear start bit for subsequent frames */ | 
					
						
							|  |  |  | 		if (!first) | 
					
						
							|  |  |  | 			first = f; | 
					
						
							|  |  |  | 		cur = f; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cur) | 
					
						
							|  |  |  | 		cur->subclass |= 1;     // RTP Marker
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*tail = cur; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return first; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int h264_decap(struct fbuf_t *b, uint8_t *data, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* Start Code Prefix (Annex B in specification) */ | 
					
						
							|  |  |  | 	uint8_t scp[] = { 0x00, 0x00, 0x00, 0x01 }; | 
					
						
							|  |  |  | 	int retval = 0; | 
					
						
							|  |  |  | 	int type, ofs = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (len < 2) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "--- invalid len %d\n", len); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* first of all, check if the packet has F == 0 */ | 
					
						
							|  |  |  | 	if (data[0] & 0x80) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "--- forbidden packet; nal: %02x\n", | 
					
						
							|  |  |  | 			data[0]); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	type = data[0] & 0x1f; | 
					
						
							|  |  |  | 	switch (type) { | 
					
						
							|  |  |  | 	case 0: | 
					
						
							|  |  |  | 	case 31: | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "--- invalid type: %d\n", type); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	case 24: | 
					
						
							|  |  |  | 	case 25: | 
					
						
							|  |  |  | 	case 26: | 
					
						
							|  |  |  | 	case 27: | 
					
						
							|  |  |  | 	case 29: | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "--- encapsulation not supported : %d\n", type); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	case 28:	/* FU-A Unit */ | 
					
						
							|  |  |  | 		if (data[1] & 0x80) { // S == 1, import F and NRI from next
 | 
					
						
							|  |  |  | 			data[1] &= 0x1f;	/* preserve type */ | 
					
						
							|  |  |  | 			data[1] |= (data[0] & 0xe0);	/* import F & NRI */ | 
					
						
							|  |  |  | 			retval = fbuf_append(b, scp, sizeof(scp), 0, 0); | 
					
						
							|  |  |  | 			ofs = 1; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ofs = 2; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default:	/* From 1 to 23 (Single NAL Unit) */ | 
					
						
							|  |  |  | 		retval = fbuf_append(b, scp, sizeof(scp), 0, 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!retval) | 
					
						
							|  |  |  | 		retval = fbuf_append(b, data + ofs, len - ofs, 0, 0); | 
					
						
							|  |  |  | 	if (retval) | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "result %d\n", retval); | 
					
						
							|  |  |  | 	return retval; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct video_codec_desc h264_codec = { | 
					
						
							|  |  |  | 	.name = "h264", | 
					
						
							|  |  |  | 	.format = AST_FORMAT_H264, | 
					
						
							|  |  |  | 	.enc_init = h264_enc_init, | 
					
						
							|  |  |  | 	.enc_encap = h264_encap, | 
					
						
							|  |  |  | 	.enc_run = ffmpeg_encode, | 
					
						
							|  |  |  | 	.dec_init = h264_dec_init, | 
					
						
							|  |  |  | 	.dec_decap = h264_decap, | 
					
						
							|  |  |  | 	.dec_run = ffmpeg_decode | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * 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_RDWR = 3 } rw;  /* read or write or both ? */ | 
					
						
							| 
									
										
										
										
											2007-12-26 20:01:16 +00:00
										 |  |  | 	//struct video_codec_desc *codec_desc;
 | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static const struct _cm video_formats[] = { | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  |         { 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 }, | 
					
						
							|  |  |  |         { AST_FORMAT_H261,      CODEC_ID_H261,  CM_RDWR }, | 
					
						
							|  |  |  |         { AST_FORMAT_H264,      CODEC_ID_H264,  CM_RDWR }, | 
					
						
							|  |  |  |         { AST_FORMAT_MP4_VIDEO, CODEC_ID_MPEG4, CM_RDWR }, | 
					
						
							|  |  |  |         { 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* pointers to supported codecs. We assume the first one to be non null. */ | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static const struct video_codec_desc *supported_codecs[] = { | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | 	&h263p_codec, | 
					
						
							|  |  |  | 	&h264_codec, | 
					
						
							|  |  |  | 	&h263_codec, | 
					
						
							|  |  |  | 	&h261_codec, | 
					
						
							|  |  |  | 	&mpeg4_codec, | 
					
						
							|  |  |  | 	NULL | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Map the AST_FORMAT to the library. If not recognised, fail. | 
					
						
							|  |  |  |  * This is useful in the input path where we get frames. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct video_codec_desc *map_video_codec(int fmt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; supported_codecs[i]; i++) | 
					
						
							|  |  |  | 		if (fmt == supported_codecs[i]->format) { | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "using %s for format 0x%x\n", | 
					
						
							|  |  |  | 				supported_codecs[i]->name, fmt); | 
					
						
							|  |  |  | 			return supported_codecs[i]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-28 22:37:40 +00:00
										 |  |  | /*! \brief uninitialize the descriptor for remote video stream */ | 
					
						
							|  |  |  | static struct video_dec_desc *dec_uninit(struct video_dec_desc *v) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-01 23:54:40 +00:00
										 |  |  | 	if (v == NULL)		/* not initialized yet */ | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2007-12-28 22:37:40 +00:00
										 |  |  | 	if (v->parser) { | 
					
						
							|  |  |  | 		av_parser_close(v->parser); | 
					
						
							|  |  |  | 		v->parser = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (v->dec_ctx) { | 
					
						
							|  |  |  | 		avcodec_close(v->dec_ctx); | 
					
						
							|  |  |  | 		av_free(v->dec_ctx); | 
					
						
							|  |  |  | 		v->dec_ctx = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (v->d_frame) { | 
					
						
							|  |  |  | 		av_free(v->d_frame); | 
					
						
							|  |  |  | 		v->d_frame = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	v->codec = NULL;	/* only a reference */ | 
					
						
							|  |  |  | 	v->d_callbacks = NULL;		/* forget the decoder */ | 
					
						
							|  |  |  | 	v->discard = 1;		/* start in discard mode */ | 
					
						
							|  |  |  | 	for (i = 0; i < N_DEC_IN; i++) | 
					
						
							|  |  |  | 		fbuf_free(&v->dec_in[i]); | 
					
						
							|  |  |  | 	fbuf_free(&v->dec_out); | 
					
						
							|  |  |  | 	ast_free(v); | 
					
						
							|  |  |  | 	return NULL;	/* error, in case someone cares */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * initialize ffmpeg resources used for decoding frames from the network. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct video_dec_desc *dec_init(uint32_t the_ast_format) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	enum CodecID codec; | 
					
						
							|  |  |  | 	struct video_dec_desc *v = ast_calloc(1, sizeof(*v)); | 
					
						
							|  |  |  | 	if (v == NULL) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v->discard = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v->d_callbacks = map_video_codec(the_ast_format); | 
					
						
							|  |  |  | 	if (v->d_callbacks == NULL) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "cannot find video codec, drop input 0x%x\n", the_ast_format); | 
					
						
							|  |  |  | 		return dec_uninit(v); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	codec = map_video_format(v->d_callbacks->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 dec_uninit(v); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Initialize the codec context. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	v->dec_ctx = avcodec_alloc_context(); | 
					
						
							|  |  |  | 	if (!v->dec_ctx) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Cannot allocate the decoder context\n"); | 
					
						
							|  |  |  | 		return dec_uninit(v); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* XXX call dec_init() ? */ | 
					
						
							|  |  |  | 	if (avcodec_open(v->dec_ctx, v->codec) < 0) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Cannot open the decoder context\n"); | 
					
						
							|  |  |  | 		av_free(v->dec_ctx); | 
					
						
							|  |  |  | 		v->dec_ctx = NULL; | 
					
						
							|  |  |  | 		return dec_uninit(v); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v->parser = av_parser_init(codec); | 
					
						
							|  |  |  | 	if (!v->parser) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Cannot initialize the decoder parser\n"); | 
					
						
							|  |  |  | 		return dec_uninit(v); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v->d_frame = avcodec_alloc_frame(); | 
					
						
							|  |  |  | 	if (!v->d_frame) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Cannot allocate decoding video frame\n"); | 
					
						
							|  |  |  | 		return dec_uninit(v); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |         v->dec_in_cur = &v->dec_in[0];	/* buffer for incoming frames */ | 
					
						
							|  |  |  |         v->dec_in_dpy = NULL;      /* nothing to display */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return v;	/* ok */ | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-12-26 10:14:11 +00:00
										 |  |  | /*------ end codec specific code -----*/ |