[4/4] rtpenc: Parse the H263 bitstream to find MB boundaries, for RFC 2190

Message ID 1330005641-19309-4-git-send-email-martin@martin.st
State Superseded
Headers show

Commit Message

Martin Storsjö Feb. 23, 2012, 2 p.m.
Finding the MB boundaries requires parsing the full bitstream.
The packetization scheme also requires providing info about the
motion vector predictor for the next macroblock after the packet
boundary.
---
 libavcodec/Makefile               |    2 +-
 libavformat/rtpenc_h263_rfc2190.c |  375 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 367 insertions(+), 10 deletions(-)

Patch

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index a98ff5b..d32c64f 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -564,7 +564,7 @@  OBJS-$(CONFIG_NUT_MUXER)               += mpegaudiodata.o
 OBJS-$(CONFIG_OGG_DEMUXER)             += flacdec.o flacdata.o flac.o \
                                           dirac.o mpeg12data.o
 OBJS-$(CONFIG_OGG_MUXER)               += xiph.o flacdec.o flacdata.o flac.o
-OBJS-$(CONFIG_RTP_MUXER)               += mpeg4audio.o mpegvideo.o xiph.o
+OBJS-$(CONFIG_RTP_MUXER)               += h263.o mpeg4audio.o mpegvideo.o xiph.o
 OBJS-$(CONFIG_SPDIF_DEMUXER)           += aacadtsdec.o mpeg4audio.o
 OBJS-$(CONFIG_WEBM_MUXER)              += xiph.o mpeg4audio.o \
                                           flacdec.o flacdata.o flac.o \
diff --git a/libavformat/rtpenc_h263_rfc2190.c b/libavformat/rtpenc_h263_rfc2190.c
index 305c1a2..40894dc 100644
--- a/libavformat/rtpenc_h263_rfc2190.c
+++ b/libavformat/rtpenc_h263_rfc2190.c
@@ -1,6 +1,8 @@ 
 /*
  * RTP packetization for H.263 video
  * Copyright (c) 2012 Martin Storsjo
+ * Copyright (c) 2000,2001 Fabrice Bellard
+ * Copyright (c) 2002-2004 Michael Niedermayer
  *
  * This file is part of Libav.
  *
@@ -23,6 +25,27 @@ 
 #include "rtpenc.h"
 #include "libavcodec/put_bits.h"
 #include "libavcodec/get_bits.h"
+#include "libavcodec/h263.h"
+#include "libavcodec/mathops.h"
+
+#define MV_VLC_BITS 9
+
+extern const uint16_t avpriv_inter_vlc[103][2];
+extern const int8_t avpriv_inter_level[102];
+extern const int8_t avpriv_inter_run[102];
+
+struct RTPFormatSpecificContext {
+    VLC_TYPE intra_MCBPC_vlc_table[72][2];
+    VLC_TYPE inter_MCBPC_vlc_table[198][2];
+    VLC_TYPE cbpy_vlc_table[64][2];
+    VLC_TYPE mv_vlc_table[538][2];
+    VLC intra_MCBPC_vlc;
+    VLC inter_MCBPC_vlc;
+    VLC cbpy_vlc;
+    VLC mv_vlc;
+    uint8_t rl_table_store[2][2*MAX_RUN + MAX_LEVEL + 3];
+    RLTable rl_inter;
+};
 
 struct H263Info {
     int src;
@@ -32,10 +55,23 @@  struct H263Info {
     int a;
     int pb;
     int tr;
+    int mb_rows_per_gob;
+    int mb_per_row;
+    int mb_per_gob;
+    int cpm;
+};
+
+struct H263State {
+    int gobn;
+    int mba;
+    int hmv1, vmv1, hmv2, vmv2;
+    int mv[353][2];
+    int quant;
+    int first_row;
 };
 
 static void send_mode_a(AVFormatContext *s1, const struct H263Info *info,
-                        const uint8_t *buf, int len, int m)
+                        const uint8_t *buf, int len, int ebits, int m)
 {
     RTPMuxContext *s = s1->priv_data;
     PutBitContext pb;
@@ -44,7 +80,7 @@  static void send_mode_a(AVFormatContext *s1, const struct H263Info *info,
     put_bits(&pb, 1, 0); /* F - 0, mode A */
     put_bits(&pb, 1, 0); /* P - 0, normal I/P */
     put_bits(&pb, 3, 0); /* SBIT - 0 bits */
-    put_bits(&pb, 3, 0); /* EBIT - 0 bits */
+    put_bits(&pb, 3, ebits); /* EBIT */
     put_bits(&pb, 3, info->src); /* SRC - source format */
     put_bits(&pb, 1, info->i); /* I - inter/intra */
     put_bits(&pb, 1, info->u); /* U - unrestricted motion vector */
@@ -60,15 +96,307 @@  static void send_mode_a(AVFormatContext *s1, const struct H263Info *info,
     ff_rtp_send_data(s1, s->buf, len + 4, m);
 }
 
+static void send_mode_b(AVFormatContext *s1, const struct H263Info *info,
+                        const struct H263State *state, const uint8_t *buf,
+                        int len, int sbits, int ebits, int m)
+{
+    RTPMuxContext *s = s1->priv_data;
+    PutBitContext pb;
+
+    init_put_bits(&pb, s->buf, 64);
+    put_bits(&pb, 1, 1); /* F - 1, mode B */
+    put_bits(&pb, 1, 0); /* P - 0, mode B */
+    put_bits(&pb, 3, sbits); /* SBIT - 0 bits */
+    put_bits(&pb, 3, ebits); /* EBIT - 0 bits */
+    put_bits(&pb, 3, info->src); /* SRC - source format */
+    put_bits(&pb, 5, state->quant); /* QUANT - quantizer for the first MB */
+    put_bits(&pb, 5, state->gobn); /* GOBN - GOB number */
+    put_bits(&pb, 9, state->mba); /* MBA - MB address */
+    put_bits(&pb, 2, 0); /* R - reserved */
+    put_bits(&pb, 1, info->i); /* I - inter/intra */
+    put_bits(&pb, 1, info->u); /* U - unrestricted motion vector */
+    put_bits(&pb, 1, info->s); /* S - syntax-baesd arithmetic coding */
+    put_bits(&pb, 1, info->a); /* A - advanced prediction */
+    put_bits(&pb, 7, state->hmv1); /* HVM1 - horizontal motion vector 1 */
+    put_bits(&pb, 7, state->vmv1); /* VVM1 - vertical motion vector 1 */
+    put_bits(&pb, 7, state->hmv2); /* HVM2 - horizontal motion vector 2 */
+    put_bits(&pb, 7, state->vmv2); /* VVM2 - vertical motion vector 2 */
+    flush_put_bits(&pb);
+    memcpy(s->buf + 8, buf, len);
+
+    ff_rtp_send_data(s1, s->buf, len + 8, m);
+}
+
+static int parse_gob_header(GetBitContext *gb, const struct H263Info *info,
+                            struct H263State *state)
+{
+    int bits = 5 + 2 + 5 + info->cpm ? 2 : 0;
+    int left;
+    skip_bits(gb, 16); /* Zeros */
+    for (left = get_bits_left(gb); left > bits; left--)
+        if (get_bits1(gb))
+            break;
+    if (left <= bits)
+        return -1;
+    state->gobn = get_bits(gb, 5);
+    if (info->cpm)
+        skip_bits(gb, 2); /* GSBI */
+    skip_bits(gb, 2); /* GFID */
+    state->quant = get_bits(gb, 5);
+    state->mba = 0;
+    state->first_row = 1;
+    memset(state->mv, 0, sizeof(state->mv));
+    return 0;
+}
+
+static void parse_dquant(GetBitContext *gb, int *quant)
+{
+    static const int8_t quant_tab[4] = { -1, -2, 1, 2 };
+    *quant += quant_tab[get_bits(gb, 2)];
+    *quant = av_clip(*quant, 1, 31);
+}
+
+static void decode_motion(struct RTPFormatSpecificContext *ctx,
+                          GetBitContext *gb, int *val)
+{
+    int sign;
+    int code = get_vlc2(gb, ctx->mv_vlc.table, MV_VLC_BITS, 2);
+    if (code <= 0)
+        return;
+    sign = get_bits1(gb);
+    if (sign)
+        code = -code;
+    *val = *val + code;
+    *val = sign_extend(*val, 6);
+}
+
+static void decode_motion2(struct RTPFormatSpecificContext *ctx,
+                           GetBitContext *gb, int *x, int *y)
+{
+    decode_motion(ctx, gb, x);
+    decode_motion(ctx, gb, y);
+}
+
+static void calc_mv_predictor(const struct H263Info *info,
+                              const struct H263State *state,
+                              int *pred_x, int *pred_y)
+{
+    int mb_x = state->mba % info->mb_per_row;
+    if (state->first_row) {
+        if (mb_x == 0) {
+            *pred_x = *pred_y = 0;
+        } else {
+            *pred_x = state->mv[mb_x - 1][0];
+            *pred_y = state->mv[mb_x - 1][1];
+        }
+    } else if (mb_x == 0) {
+        *pred_x = mid_pred(0, state->mv[mb_x][0], state->mv[mb_x + 1][0]);
+        *pred_y = mid_pred(0, state->mv[mb_x][1], state->mv[mb_x + 1][1]);
+    } else {
+        *pred_x = mid_pred(state->mv[mb_x - 1][0], state->mv[mb_x][0],
+                           state->mv[mb_x + 1][0]);
+        *pred_y = mid_pred(state->mv[mb_x - 1][1], state->mv[mb_x][1],
+                           state->mv[mb_x + 1][1]);
+    }
+}
+
+static void skip_block(struct RTPFormatSpecificContext *ctx,
+                       const struct H263Info *info, GetBitContext *gb,
+                       int intra, int coded)
+{
+    RLTable *rl = &ctx->rl_inter;
+    if (intra) {
+        skip_bits(gb, 8); /* level */
+    } else {
+    }
+    if (!coded)
+        return;
+    /* The data isn't necessarily zero padded (when checking a subsequence
+     * of the bitstream), so check the number of bits left to avoid
+     * infinte loops. */
+    while (get_bits_left(gb) > 0) {
+        int last = 0;
+        int code = get_vlc2(gb, rl->vlc.table, TEX_VLC_BITS, 2);
+        if (code < 0) {
+            av_log(NULL, AV_LOG_ERROR, "illegal ac vlc code\n");
+            return;
+        }
+        if (code == rl->n) {
+            int level;
+            last = get_bits1(gb);
+            skip_bits(gb, 6);
+            level = get_bits(gb, 8);
+            if (level == -128)
+                skip_bits(gb, 11);
+        } else {
+            last = code >= rl->last;
+            skip_bits(gb, 1);
+        }
+        if (last)
+            break;
+    }
+}
+
+static int parse_mb(struct RTPFormatSpecificContext *ctx, GetBitContext *gb,
+                    const struct H263Info *info, struct H263State *state)
+{
+    int cbpc, cbpy, cbp, dquant = 0, intra = 0;
+    int quant = state->quant;
+    int pred_x, pred_y;
+    int mb_x = state->mba % info->mb_per_row;
+    int i;
+    calc_mv_predictor(info, state, &pred_x, &pred_y);
+    if (get_bits_left(gb) <= 0)
+        return -1;
+    if (info->i) {
+        do {
+            if (get_bits(gb, 1)) {
+                state->mv[mb_x][0] = state->mv[mb_x][1] = 0;
+                return 0;
+            }
+            cbpc = get_vlc2(gb, ctx->inter_MCBPC_vlc.table,
+                            INTER_MCBPC_VLC_BITS, 2);
+            if (cbpc < 0)
+                return -1;
+        } while (cbpc == 20);
+        dquant = cbpc & 8;
+        if (cbpc & 4)
+            goto intra;
+        cbpy = get_vlc2(gb, ctx->cbpy_vlc.table, CBPY_VLC_BITS, 1);
+        cbpy ^= 0xF;
+        cbp = (cbpc & 3) | (cbpy << 2);
+        if (dquant)
+            parse_dquant(gb, &quant);
+        if (!(cbpc & 16)) {
+            decode_motion2(ctx, gb, &pred_x, &pred_y);
+        } else {
+            /* Not implemented */
+            av_log(NULL, AV_LOG_ERROR, "4MV not supported\n");
+        }
+    } else {
+        do {
+            cbpc = get_vlc2(gb, ctx->intra_MCBPC_vlc.table,
+                            INTRA_MCBPC_VLC_BITS, 2);
+            if (cbpc < 0)
+                return -1;
+        } while (cbpc == 8);
+        dquant = cbpc & 4;
+intra:
+        cbpy = get_vlc2(gb, ctx->cbpy_vlc.table, CBPY_VLC_BITS, 1);
+        cbp = (cbpc & 3) | (cbpy << 2);
+        if (dquant)
+            parse_dquant(gb, &quant);
+        pred_x = pred_y = 0;
+        intra = 1;
+    }
+    for (i = 0; i < 6; i++) {
+        skip_block(ctx, info, gb, intra, cbp & 32);
+        cbp += cbp;
+    }
+    if (get_bits_left(gb) > 0) {
+        state->quant = quant;
+        state->mv[mb_x][0] = pred_x;
+        state->mv[mb_x][1] = pred_y;
+    } else {
+        return -1;
+    }
+    return 0;
+}
+
+static void find_mb_boundary(struct RTPFormatSpecificContext *ctx,
+                             const uint8_t *buf, int sbits,
+                             const struct H263Info *info,
+                             struct H263State *state, int *len, int *ebits,
+                             int first)
+{
+    GetBitContext gb;
+    init_get_bits(&gb, buf, (*len)*8);
+    skip_bits(&gb, sbits);
+    if (first) {
+        /* Parse PSC */
+        skip_bits(&gb, 22); /* PSC */
+        skip_bits(&gb, 8); /* TR */
+        skip_bits(&gb, 2 + 3 + 3 + 5); /* PTYPE */
+        skip_bits(&gb, 5); /* PQUANT */
+        skip_bits(&gb, 1); /* CPM */
+        if (info->cpm)
+            skip_bits(&gb, 2); /* PSBI */
+        /* Not handling PB frames - skipping TRB and DBQUANT */
+        while (get_bits1(&gb)) /* PEI */
+            skip_bits(&gb, 8); /* PSUPP */
+        state->first_row = 1;
+    } else {
+        if (!show_bits(&gb, 16))
+            parse_gob_header(&gb, info, state);
+    }
+    /* Start parsing MBs */
+    while (1) {
+        if (!show_bits(&gb, 16)) {
+            /* Improbable, should have been found by the GBSC finder */
+            if (parse_gob_header(&gb, info, state) < 0)
+                return;
+        } else {
+            if (state->mba == info->mb_per_gob) {
+                state->mba = 0;
+                state->gobn++;
+            }
+        }
+        if (parse_mb(ctx, &gb, info, state) < 0)
+            break;
+        state->mba++;
+        if (state->mba == info->mb_per_row)
+            state->first_row = 0;
+        /* Allow restarting parsing from after this MB */
+        *len = (get_bits_count(&gb) + 7)/8;
+        *ebits = (8 - (get_bits_count(&gb) & 7)) & 7;
+    }
+    /* Set predictor according to the chosen MB */
+    calc_mv_predictor(info, state, &state->hmv1, &state->vmv1);
+}
+
+#define INIT_VLC_PREALLOC(vlc, bits, a, b, c, d, e, f, g) do { \
+        vlc.table = vlc ## _table; \
+        vlc.table_allocated = sizeof(vlc ## _table)/2/sizeof(vlc ## _table[0][0]); \
+        init_vlc(&vlc, bits, a, b, c, d, e, f, g, INIT_VLC_USE_NEW_STATIC); \
+    } while (0)
+
 void ff_rtp_send_h263_rfc2190(AVFormatContext *s1, const uint8_t *buf, int size)
 {
     RTPMuxContext *s = s1->priv_data;
-    int len;
+    int len, first = 1, sbits = 0, ebits = 0;
     GetBitContext gb;
     struct H263Info info = { 0 };
+    struct H263State state = { 0 };
 
     s->timestamp = s->cur_timestamp;
 
+    if (!s->priv_data) {
+        static const RLTable rl_inter = {
+            102,
+            58,
+            avpriv_inter_vlc,
+            avpriv_inter_run,
+            avpriv_inter_level,
+        };
+        s->priv_data = av_mallocz(sizeof(struct RTPFormatSpecificContext));
+        if (!s->priv_data)
+            return;
+        INIT_VLC_PREALLOC(s->priv_data->intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 9,
+                          avpriv_h263_intra_MCBPC_bits, 1, 1,
+                          avpriv_h263_intra_MCBPC_code, 1, 1);
+        INIT_VLC_PREALLOC(s->priv_data->inter_MCBPC_vlc, INTER_MCBPC_VLC_BITS, 28,
+                          avpriv_h263_inter_MCBPC_bits, 1, 1,
+                          avpriv_h263_inter_MCBPC_code, 1, 1);
+        INIT_VLC_PREALLOC(s->priv_data->cbpy_vlc, CBPY_VLC_BITS, 16,
+                          &avpriv_h263_cbpy_tab[0][1], 2, 1,
+                          &avpriv_h263_cbpy_tab[0][0], 2, 1);
+        INIT_VLC_PREALLOC(s->priv_data->mv_vlc, MV_VLC_BITS, 33,
+                          &avpriv_mvtab[0][1], 2, 1, &avpriv_mvtab[0][0], 2, 1);
+        s->priv_data->rl_inter = rl_inter;
+        avpriv_init_rl(&s->priv_data->rl_inter, s->priv_data->rl_table_store);
+        INIT_VLC_RL(s->priv_data->rl_inter, 554);
+    }
+
     init_get_bits(&gb, buf, size*8);
     if (get_bits(&gb, 22) == 0x20) { /* Picture Start Code */
         info.tr  = get_bits(&gb, 8);
@@ -80,25 +408,54 @@  void ff_rtp_send_h263_rfc2190(AVFormatContext *s1, const uint8_t *buf, int size)
         info.s   = get_bits(&gb, 1);
         info.a   = get_bits(&gb, 1);
         info.pb  = get_bits(&gb, 1);
+        state.quant = get_bits(&gb, 5); /* PQUANT */
+        info.cpm   = get_bits(&gb, 1); /* CPM */
+    }
+    if (info.a)
+        av_log(s1, AV_LOG_ERROR,
+               "Advanced prediction in RFC 2190 not supported currently\n");
+    if (s1->streams[0]->codec->height <= 400)
+        info.mb_rows_per_gob = 1;
+    else if (s1->streams[0]->codec->height <= 800)
+        info.mb_rows_per_gob = 2;
+    else
+        info.mb_rows_per_gob = 4;
+    info.mb_per_row = s1->streams[0]->codec->width/16;
+    info.mb_per_gob = info.mb_per_row * info.mb_rows_per_gob;
+    if (info.mb_per_row > sizeof(state.mv)/sizeof(state.mv[0][0])/2) {
+        av_log(s1, AV_LOG_ERROR, "Bad H263 frame size\n");
+        return;
     }
 
     while (size > 0) {
-        len = FFMIN(s->max_payload_size - 4, size);
+        struct H263State packet_start_state = state;
+        len = FFMIN(s->max_payload_size - 8, size);
 
         /* Look for a better place to split the frame into packets. */
         if (len < size) {
             const uint8_t *end = ff_h263_find_resync_marker_reverse(buf,
                                                                     buf + len);
             len = end - buf;
-            if (len == s->max_payload_size - 4)
-                av_log(s1, AV_LOG_WARNING,
-                       "No GOB boundary found within MTU size, splitting at "
-                       "a random boundary\n");
+            if (len == s->max_payload_size - 8)
+                find_mb_boundary(s->priv_data, buf, sbits, &info, &state,
+                                 &len, &ebits, first);
         }
 
-        send_mode_a(s1, &info, buf, len, len == size);
+        if (size > 2 && !buf[0] && !buf[1])
+            send_mode_a(s1, &info, buf, len, ebits, len == size);
+        else
+            send_mode_b(s1, &info, &packet_start_state, buf, len, sbits,
+                        ebits, len == size);
 
+        if (ebits) {
+            sbits = 8 - ebits;
+            len--;
+        } else {
+            sbits = 0;
+        }
         buf  += len;
         size -= len;
+        first = 0;
+        ebits = 0;
     }
 }