[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