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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Oct 10 08:49:06 CDT 2007


Author: rizzo
Date: Wed Oct 10 08:49:06 2007
New Revision: 85235

URL: http://svn.digium.com/view/asterisk?view=rev&rev=85235
Log:
move a common part of video decoding to a function.
Start adding proper h261 decapsulation


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=85235&r1=85234&r2=85235
==============================================================================
--- team/rizzo/video_v2/channels/console_video.c (original)
+++ team/rizzo/video_v2/channels/console_video.c Wed Oct 10 08:49:06 2007
@@ -165,6 +165,7 @@
 			 * otherwise */
 	int	size;	/* total size in bytes */
 	int	used;	/* space used so far */
+	int	ebit;	/* bits to ignore at the end */
 	int	w;
 	int	h;
 	int	pix_fmt;
@@ -307,6 +308,49 @@
 	b->w = x.w;
 	b->h = x.h;
 	b->pix_fmt = x.pix_fmt;
+}
+
+/*
+ * Append a chunk of data to a buffer taking care of unaligments.
+ * Return 0 on success, != 0 on failure
+ */
+static int fbuf_append(struct fbuf_t *b, uint8_t *src, int len,
+	int ebit, int sbit)
+{
+	/*
+	 * 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;
+
+	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;
+	}
+	i = b->ebit + sbit;	/* bits to ignore around */
+	if (i == 0) {	/* easy case, no copy to do */
+		memcpy(b->data + b->used, src, len);
+		b->used += len;
+		b->data[b->used] = '\0';
+	} else if (i == 8) { /* almost easy, just handle the overlap */
+		ast_log(LOG_WARNING, "must handle unaligned %d %d\n",
+			b->ebit, sbit);
+	} else {	/* must shift the new block */
+		ast_log(LOG_WARNING, "must handle shift %d %d\n",
+			b->ebit, sbit);
+	}
+	return 0;
 }
 
 /*!
@@ -762,37 +806,91 @@
 	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.
+ */
 static struct ast_frame *h261_encap(struct video_out_desc *out,
 		struct ast_frame **tail)
 {
+	uint8_t *d = out->enc_out.data;
+	int start = 0, i, len = out->enc_out.used;
 	struct ast_frame *f, *cur = NULL, *first = NULL;
-	uint8_t *d = out->enc_out.data;
-	int len = out->enc_out.used;
-	uint8_t *end = d+len;
-
-	while (d < end) {
-		uint8_t *iter;
-		uint8_t *data;
-		for (iter = d+2; iter < end-2; iter++)
-			if (iter[0] == 0x00 && iter[1] == 0x01)
+	const int pheader_len = 4;
+	uint8_t h261_hdr[4];
+	uint8_t *h = h261_hdr;	/* shorthand */
+
+#define H261_MIN_LEN 4
+	if (len < H261_MIN_LEN)	/* unreasonably small */
+		return NULL;
+
+	bzero(h261_hdr, sizeof(h261_hdr));
+	h[0] = 0x01;	/* sbit = ebit = 0, i=0, v=1, all others 0 */
+
+	for (i = H261_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;
+			if (d[i] != 0)		/* cannot be in a GBSC */
+				continue;
+			if (i > len - 1)
 				break;
-
-		if (iter == end-2)
-			iter = end;
-		f = create_video_frame(d, iter, AST_FORMAT_H261, 4, cur);
-		d = iter;
+			x = d[i+1];
+			if (x == 0)	/* next is equally good */
+				continue;
+			/* see if around us we can make 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; rpos; 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
+			 */
+			if (rpos == 0x80) {	/* lucky case */
+				i = i - 1;
+			} else {	/* XXX to be completed */
+				ast_log(LOG_WARNING, "unaligned GBSC 0x%x\n",
+					rpos);
+			}
+			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_H261,
+				pheader_len, cur);
+
 		if (!f)
 			break;
-
-		data = f->data;
-		data[0] = 0x03;
-
+		bcopy(h, f->data, 4);	/* copy the h263 header */
+		/* 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
 
@@ -800,6 +898,9 @@
 	return first;
 }
 
+/*
+ * Pieces might be unaligned so we really need to put them together.
+ */
 static uint8_t *h261_decap(uint8_t *data, int *len)
 {
 	if (*len < 4) {
@@ -1463,7 +1564,7 @@
 static int console_write_video(struct ast_channel *chan, struct ast_frame *f)
 {
 	uint8_t *data;
-	int len, need;
+	int len;
 	struct video_desc *env = get_video_desc(chan);
 	struct video_in_desc *v = &env->in;
 
@@ -1524,28 +1625,7 @@
 		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_calloc(1, 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';
+	fbuf_append(&v->dec_in, data, len, 0, 0);
 	if (f->subclass & 0x01) {	// RTP Marker
 		if (env->current_codec->dec_run(v, &v->dec_in)) {
 			show_frame(env, 0);




More information about the asterisk-commits mailing list