intrax8: Keep a reference to the decoder blocks
[ffmpeg.git] / libavcodec / intrax8.c
index 54d067c..3bd8807 100644 (file)
@@ -29,6 +29,7 @@
 #include "intrax8huf.h"
 #include "intrax8.h"
 #include "intrax8dsp.h"
+#include "mpegutils.h"
 
 #define MAX_TABLE_DEPTH(table_bits, max_bits) \
     ((max_bits + table_bits - 1) / table_bits)
@@ -132,7 +133,6 @@ static void x8_reset_vlc_tables(IntraX8Context *w)
 
 static inline void x8_select_ac_table(IntraX8Context *const w, int mode)
 {
-    MpegEncContext *const s = w->s;
     int table_index;
 
     assert(mode < 4);
@@ -140,7 +140,7 @@ static inline void x8_select_ac_table(IntraX8Context *const w, int mode)
     if (w->j_ac_vlc[mode])
         return;
 
-    table_index       = get_bits(&s->gb, 3);
+    table_index       = get_bits(w->gb, 3);
     // 2 modes use same tables
     w->j_ac_vlc[mode] = &j_ac_vlc[w->quant < 13][mode >> 1][table_index];
 
@@ -149,16 +149,14 @@ static inline void x8_select_ac_table(IntraX8Context *const w, int mode)
 
 static inline int x8_get_orient_vlc(IntraX8Context *w)
 {
-    MpegEncContext *const s = w->s;
-
     if (!w->j_orient_vlc) {
-        int table_index = get_bits(&s->gb, 1 + (w->quant < 13));
+        int table_index = get_bits(w->gb, 1 + (w->quant < 13));
         w->j_orient_vlc = &j_orient_vlc[w->quant < 13][table_index];
     }
     assert(w->j_orient_vlc);
     assert(w->j_orient_vlc->table);
 
-    return get_vlc2(&s->gb, w->j_orient_vlc->table, OR_VLC_BITS, OR_VLC_MTD);
+    return get_vlc2(w->gb, w->j_orient_vlc->table, OR_VLC_BITS, OR_VLC_MTD);
 }
 
 #define extra_bits(eb)  (eb)        // 3 bits
@@ -211,11 +209,10 @@ static const uint32_t ac_decode_table[] = {
 static void x8_get_ac_rlf(IntraX8Context *const w, const int mode,
                           int *const run, int *const level, int *const final)
 {
-    MpegEncContext *const s = w->s;
     int i, e;
 
 //    x8_select_ac_table(w, mode);
-    i = get_vlc2(&s->gb, w->j_ac_vlc[mode]->table, AC_VLC_BITS, AC_VLC_MTD);
+    i = get_vlc2(w->gb, w->j_ac_vlc[mode]->table, AC_VLC_BITS, AC_VLC_MTD);
 
     if (i < 46) { // [0-45]
         int t, l;
@@ -254,7 +251,7 @@ static void x8_get_ac_rlf(IntraX8Context *const w, const int mode,
         i -= 46;
         sm = ac_decode_table[i];
 
-        e    = get_bits(&s->gb, sm & 0xF);
+        e    = get_bits(w->gb, sm & 0xF);
         sm >>= 8;                               // 3bits
         mask = sm & 0xff;
         sm >>= 8;                               // 1bit
@@ -271,13 +268,13 @@ static void x8_get_ac_rlf(IntraX8Context *const w, const int mode,
         };
 
         (*final) = !(i & 1);
-        e        = get_bits(&s->gb, 5); // get the extra bits
+        e        = get_bits(w->gb, 5); // get the extra bits
         (*run)   = crazy_mix_runlevel[e] >> 4;
         (*level) = crazy_mix_runlevel[e] & 0x0F;
     } else {
-        (*level) = get_bits(&s->gb, 7 - 3 * (i & 1));
-        (*run)   = get_bits(&s->gb, 6);
-        (*final) = get_bits1(&s->gb);
+        (*level) = get_bits(w->gb, 7 - 3 * (i & 1));
+        (*run)   = get_bits(w->gb, 6);
+        (*final) = get_bits1(w->gb);
     }
     return;
 }
@@ -292,19 +289,18 @@ static const uint8_t dc_index_offset[] = {
 static int x8_get_dc_rlf(IntraX8Context *const w, const int mode,
                          int *const level, int *const final)
 {
-    MpegEncContext *const s = w->s;
     int i, e, c;
 
     assert(mode < 3);
     if (!w->j_dc_vlc[mode]) {
-        int table_index = get_bits(&s->gb, 3);
+        int table_index = get_bits(w->gb, 3);
         // 4 modes, same table
         w->j_dc_vlc[mode] = &j_dc_vlc[w->quant < 13][table_index];
     }
     assert(w->j_dc_vlc);
     assert(w->j_dc_vlc[mode]->table);
 
-    i = get_vlc2(&s->gb, w->j_dc_vlc[mode]->table, DC_VLC_BITS, DC_VLC_MTD);
+    i = get_vlc2(w->gb, w->j_dc_vlc[mode]->table, DC_VLC_BITS, DC_VLC_MTD);
 
     /* (i >= 17) { i -= 17; final =1; } */
     c        = i > 16;
@@ -318,7 +314,7 @@ static int x8_get_dc_rlf(IntraX8Context *const w, const int mode,
     c  = (i + 1) >> 1; // hackish way to calculate dc_extra_sbits[]
     c -= c > 1;
 
-    e = get_bits(&s->gb, c); // get the extra bits
+    e = get_bits(w->gb, c); // get the extra bits
     i = dc_index_offset[i] + (e >> 1);
 
     e        = -(e & 1); // 0, 0xffffff
@@ -330,13 +326,12 @@ static int x8_get_dc_rlf(IntraX8Context *const w, const int mode,
 
 static int x8_setup_spatial_predictor(IntraX8Context *const w, const int chroma)
 {
-    MpegEncContext *const s = w->s;
     int range;
     int sum;
     int quant;
 
-    w->dsp.setup_spatial_compensation(s->dest[chroma], s->sc.edge_emu_buffer,
-                                      s->current_picture.f->linesize[chroma > 0],
+    w->dsp.setup_spatial_compensation(w->dest[chroma], w->scratchpad,
+                                      w->frame->linesize[chroma > 0],
                                       &range, &sum, w->edges);
     if (chroma) {
         w->orient = w->chroma_orient;
@@ -390,9 +385,7 @@ static int x8_setup_spatial_predictor(IntraX8Context *const w, const int chroma)
 static void x8_update_predictions(IntraX8Context *const w, const int orient,
                                   const int est_run)
 {
-    MpegEncContext *const s = w->s;
-
-    w->prediction_table[s->mb_x * 2 + (s->mb_y & 1)] = (est_run << 2) + 1 * (orient == 4) + 2 * (orient == 8);
+    w->prediction_table[w->mb_x * 2 + (w->mb_y & 1)] = (est_run << 2) + 1 * (orient == 4) + 2 * (orient == 8);
 /*
  * y = 2n + 0 -> // 0 2 4
  * y = 2n + 1 -> // 1 3 5
@@ -401,11 +394,9 @@ static void x8_update_predictions(IntraX8Context *const w, const int orient,
 
 static void x8_get_prediction_chroma(IntraX8Context *const w)
 {
-    MpegEncContext *const s = w->s;
-
-    w->edges  = 1 * (!(s->mb_x >> 1));
-    w->edges |= 2 * (!(s->mb_y >> 1));
-    w->edges |= 4 * (s->mb_x >= (2 * s->mb_width - 1)); // mb_x for chroma would always be odd
+    w->edges  = 1 * (!(w->mb_x >> 1));
+    w->edges |= 2 * (!(w->mb_y >> 1));
+    w->edges |= 4 * (w->mb_x >= (2 * w->mb_width - 1)); // mb_x for chroma would always be odd
 
     w->raw_orient = 0;
     // lut_co[8] = {inv,4,8,8, inv,4,8,8} <- => {1,1,0,0;1,1,0,0} => 0xCC
@@ -414,29 +405,28 @@ static void x8_get_prediction_chroma(IntraX8Context *const w)
         return;
     }
     // block[x - 1][y | 1 - 1)]
-    w->chroma_orient = (w->prediction_table[2 * s->mb_x - 2] & 0x03) << 2;
+    w->chroma_orient = (w->prediction_table[2 * w->mb_x - 2] & 0x03) << 2;
 }
 
 static void x8_get_prediction(IntraX8Context *const w)
 {
-    MpegEncContext *const s = w->s;
     int a, b, c, i;
 
-    w->edges  = 1 * (!s->mb_x);
-    w->edges |= 2 * (!s->mb_y);
-    w->edges |= 4 * (s->mb_x >= (2 * s->mb_width - 1));
+    w->edges  = 1 * (!w->mb_x);
+    w->edges |= 2 * (!w->mb_y);
+    w->edges |= 4 * (w->mb_x >= (2 * w->mb_width - 1));
 
     switch (w->edges & 3) {
     case 0:
         break;
     case 1:
         // take the one from the above block[0][y - 1]
-        w->est_run = w->prediction_table[!(s->mb_y & 1)] >> 2;
+        w->est_run = w->prediction_table[!(w->mb_y & 1)] >> 2;
         w->orient  = 1;
         return;
     case 2:
         // take the one from the previous block[x - 1][0]
-        w->est_run = w->prediction_table[2 * s->mb_x - 2] >> 2;
+        w->est_run = w->prediction_table[2 * w->mb_x - 2] >> 2;
         w->orient  = 2;
         return;
     case 3:
@@ -445,15 +435,15 @@ static void x8_get_prediction(IntraX8Context *const w)
         return;
     }
     // no edge cases
-    b = w->prediction_table[2 * s->mb_x     + !(s->mb_y & 1)]; // block[x    ][y - 1]
-    a = w->prediction_table[2 * s->mb_x - 2 +  (s->mb_y & 1)]; // block[x - 1][y    ]
-    c = w->prediction_table[2 * s->mb_x - 2 + !(s->mb_y & 1)]; // block[x - 1][y - 1]
+    b = w->prediction_table[2 * w->mb_x     + !(w->mb_y & 1)]; // block[x    ][y - 1]
+    a = w->prediction_table[2 * w->mb_x - 2 +  (w->mb_y & 1)]; // block[x - 1][y    ]
+    c = w->prediction_table[2 * w->mb_x - 2 + !(w->mb_y & 1)]; // block[x - 1][y - 1]
 
     w->est_run = FFMIN(b, a);
     /* This condition has nothing to do with w->edges, even if it looks
      * similar it would trigger if e.g. x = 3; y = 2;
      * I guess somebody wrote something wrong and it became standard. */
-    if ((s->mb_x & s->mb_y) != 0)
+    if ((w->mb_x & w->mb_y) != 0)
         w->est_run = FFMIN(c, w->est_run);
     w->est_run >>= 2;
 
@@ -490,9 +480,8 @@ static void x8_get_prediction(IntraX8Context *const w)
 static void x8_ac_compensation(IntraX8Context *const w, const int direction,
                                const int dc_level)
 {
-    MpegEncContext *const s = w->s;
     int t;
-#define B(x, y) s->block[0][s->idsp.idct_permutation[(x) + (y) * 8]]
+#define B(x, y) w->block[0][w->idsp.idct_permutation[(x) + (y) * 8]]
 #define T(x)  ((x) * dc_level + 0x8000) >> 16;
     switch (direction) {
     case 0:
@@ -536,7 +525,7 @@ static void x8_ac_compensation(IntraX8Context *const w, const int direction,
         t        = T(1084); // g
         B(1, 1) += t;
 
-        s->block_last_index[0] = FFMAX(s->block_last_index[0], 7 * 8);
+        w->block_last_index[0] = FFMAX(w->block_last_index[0], 7 * 8);
         break;
     case 1:
         B(0, 1) -= T(6269);
@@ -544,7 +533,7 @@ static void x8_ac_compensation(IntraX8Context *const w, const int direction,
         B(0, 5) -= T(172);
         B(0, 7) -= T(73);
 
-        s->block_last_index[0] = FFMAX(s->block_last_index[0], 7 * 8);
+        w->block_last_index[0] = FFMAX(w->block_last_index[0], 7 * 8);
         break;
     case 2:
         B(1, 0) -= T(6269);
@@ -552,7 +541,7 @@ static void x8_ac_compensation(IntraX8Context *const w, const int direction,
         B(5, 0) -= T(172);
         B(7, 0) -= T(73);
 
-        s->block_last_index[0] = FFMAX(s->block_last_index[0], 7);
+        w->block_last_index[0] = FFMAX(w->block_last_index[0], 7);
         break;
     }
 #undef B
@@ -582,8 +571,6 @@ static const int16_t quant_table[64] = {
 
 static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma)
 {
-    MpegEncContext *const s = w->s;
-
     uint8_t *scantable;
     int final, run, level;
     int ac_mode, dc_mode, est_run, dc_level;
@@ -593,7 +580,7 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma)
     int sign;
 
     assert(w->orient < 12);
-    s->bdsp.clear_block(s->block[0]);
+    w->bdsp.clear_block(w->block[0]);
 
     if (chroma)
         dc_mode = 2;
@@ -648,18 +635,18 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma)
             level  = (level + 1) * w->dquant;
             level += w->qsum;
 
-            sign  = -get_bits1(&s->gb);
+            sign  = -get_bits1(w->gb);
             level = (level ^ sign) - sign;
 
             if (use_quant_matrix)
                 level = (level * quant_table[pos]) >> 8;
 
-            s->block[0][scantable[pos]] = level;
+            w->block[0][scantable[pos]] = level;
         } while (!final);
 
-        s->block_last_index[0] = pos;
+        w->block_last_index[0] = pos;
     } else { // DC only
-        s->block_last_index[0] = 0;
+        w->block_last_index[0] = 0;
         if (w->flat_dc && ((unsigned) (dc_level + 1)) < 3) { // [-1; 1]
             int32_t divide_quant = !chroma ? w->divide_quant_dc_luma
                                            : w->divide_quant_dc_chroma;
@@ -671,17 +658,17 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma)
             dc_level += (w->predicted_dc * divide_quant + (1 << 12)) >> 13;
 
             dsp_x8_put_solidcolor(av_clip_uint8((dc_level * dc_quant + 4) >> 3),
-                                  s->dest[chroma],
-                                  s->current_picture.f->linesize[!!chroma]);
+                                  w->dest[chroma],
+                                  w->frame->linesize[!!chroma]);
 
             goto block_placed;
         }
         zeros_only = (dc_level == 0);
     }
     if (!chroma)
-        s->block[0][0] = dc_level * w->quant;
+        w->block[0][0] = dc_level * w->quant;
     else
-        s->block[0][0] = dc_level * w->quant_dc_chroma;
+        w->block[0][0] = dc_level * w->quant_dc_chroma;
 
     // there is !zero_only check in the original, but dc_level check is enough
     if ((unsigned int) (dc_level + 1) >= 3 && (w->edges & 3) != 3) {
@@ -691,30 +678,30 @@ static int x8_decode_intra_mb(IntraX8Context *const w, const int chroma)
         direction = (0x6A017C >> (w->orient * 2)) & 3;
         if (direction != 3) {
             // modify block_last[]
-            x8_ac_compensation(w, direction, s->block[0][0]);
+            x8_ac_compensation(w, direction, w->block[0][0]);
         }
     }
 
     if (w->flat_dc) {
-        dsp_x8_put_solidcolor(w->predicted_dc, s->dest[chroma],
-                              s->current_picture.f->linesize[!!chroma]);
+        dsp_x8_put_solidcolor(w->predicted_dc, w->dest[chroma],
+                              w->frame->linesize[!!chroma]);
     } else {
-        w->dsp.spatial_compensation[w->orient](s->sc.edge_emu_buffer,
-                                               s->dest[chroma],
-                                               s->current_picture.f->linesize[!!chroma]);
+        w->dsp.spatial_compensation[w->orient](w->scratchpad,
+                                               w->dest[chroma],
+                                               w->frame->linesize[!!chroma]);
     }
     if (!zeros_only)
-        s->idsp.idct_add(s->dest[chroma],
-                         s->current_picture.f->linesize[!!chroma],
-                         s->block[0]);
+        w->idsp.idct_add(w->dest[chroma],
+                         w->frame->linesize[!!chroma],
+                         w->block[0]);
 
 block_placed:
     if (!chroma)
         x8_update_predictions(w, w->orient, n);
 
-    if (s->loop_filter) {
-        uint8_t *ptr = s->dest[chroma];
-        int linesize = s->current_picture.f->linesize[!!chroma];
+    if (w->loopfilter) {
+        uint8_t *ptr = w->dest[chroma];
+        int linesize = w->frame->linesize[!!chroma];
 
         if (!((w->edges & 2) || (zeros_only && (w->orient | 4) == 4)))
             w->dsp.h_loop_filter(ptr, linesize, w->quant);
@@ -726,44 +713,56 @@ block_placed:
 }
 
 // FIXME maybe merge with ff_*
-static void x8_init_block_index(MpegEncContext *s)
+static void x8_init_block_index(IntraX8Context *w, AVFrame *frame)
 {
-    // not s->linesize as this would be wrong for field pics
+    // not parent codec linesize as this would be wrong for field pics
     // not that IntraX8 has interlacing support ;)
-    const int linesize   = s->current_picture.f->linesize[0];
-    const int uvlinesize = s->current_picture.f->linesize[1];
+    const int linesize   = frame->linesize[0];
+    const int uvlinesize = frame->linesize[1];
 
-    s->dest[0] = s->current_picture.f->data[0];
-    s->dest[1] = s->current_picture.f->data[1];
-    s->dest[2] = s->current_picture.f->data[2];
+    w->dest[0] = frame->data[0];
+    w->dest[1] = frame->data[1];
+    w->dest[2] = frame->data[2];
 
-    s->dest[0] +=  s->mb_y         * linesize   << 3;
+    w->dest[0] +=  w->mb_y         * linesize   << 3;
     // chroma blocks are on add rows
-    s->dest[1] += (s->mb_y & (~1)) * uvlinesize << 2;
-    s->dest[2] += (s->mb_y & (~1)) * uvlinesize << 2;
+    w->dest[1] += (w->mb_y & (~1)) * uvlinesize << 2;
+    w->dest[2] += (w->mb_y & (~1)) * uvlinesize << 2;
 }
 
-av_cold int ff_intrax8_common_init(IntraX8Context *w, MpegEncContext *const s)
+av_cold int ff_intrax8_common_init(AVCodecContext *avctx,
+                                   IntraX8Context *w, IDCTDSPContext *idsp,
+                                   int16_t (*block)[64],
+                                   int block_last_index[12],
+                                   int mb_width, int mb_height,
+                                   MpegEncContext *const s)
 {
     int ret = x8_vlc_init();
     if (ret < 0)
         return ret;
 
+    w->avctx = avctx;
+    w->idsp = *idsp;
+    w->mb_width  = mb_width;
+    w->mb_height = mb_height;
+    w->block = block;
+    w->block_last_index = block_last_index;
     w->s = s;
 
     // two rows, 2 blocks per cannon mb
-    w->prediction_table = av_mallocz(s->mb_width * 2 * 2);
+    w->prediction_table = av_mallocz(w->mb_width * 2 * 2);
     if (!w->prediction_table)
         return AVERROR(ENOMEM);
 
-    ff_init_scantable(s->idsp.idct_permutation, &w->scantable[0],
+    ff_init_scantable(w->idsp.idct_permutation, &w->scantable[0],
                       ff_wmv1_scantable[0]);
-    ff_init_scantable(s->idsp.idct_permutation, &w->scantable[1],
+    ff_init_scantable(w->idsp.idct_permutation, &w->scantable[1],
                       ff_wmv1_scantable[2]);
-    ff_init_scantable(s->idsp.idct_permutation, &w->scantable[2],
+    ff_init_scantable(w->idsp.idct_permutation, &w->scantable[2],
                       ff_wmv1_scantable[3]);
 
     ff_intrax8dsp_init(&w->dsp);
+    ff_blockdsp_init(&w->bdsp, avctx);
 
     return 0;
 }
@@ -773,17 +772,25 @@ av_cold void ff_intrax8_common_end(IntraX8Context *w)
     av_freep(&w->prediction_table);
 }
 
-int ff_intrax8_decode_picture(IntraX8Context *const w, int dquant,
-                              int quant_offset)
+int ff_intrax8_decode_picture(IntraX8Context *const w, Picture *pict,
+                              GetBitContext *gb, int *mb_x, int *mb_y,
+                              int dquant, int quant_offset,
+                              int loopfilter, int lowdelay)
 {
     MpegEncContext *const s = w->s;
     int mb_xy;
     assert(s);
-    w->use_quant_matrix = get_bits1(&s->gb);
 
+    w->gb     = gb;
     w->dquant = dquant;
     w->quant  = dquant >> 1;
     w->qsum   = quant_offset;
+    w->frame  = pict->f;
+    w->loopfilter = loopfilter;
+    w->use_quant_matrix = get_bits1(w->gb);
+
+    w->mb_x = *mb_x;
+    w->mb_y = *mb_y;
 
     w->divide_quant_dc_luma = ((1 << 16) + (w->quant >> 1)) / w->quant;
     if (w->quant < 5) {
@@ -795,18 +802,17 @@ int ff_intrax8_decode_picture(IntraX8Context *const w, int dquant,
     }
     x8_reset_vlc_tables(w);
 
-    for (s->mb_y = 0; s->mb_y < s->mb_height * 2; s->mb_y++) {
-        x8_init_block_index(s);
-        mb_xy = (s->mb_y >> 1) * s->mb_stride;
-
-        for (s->mb_x = 0; s->mb_x < s->mb_width * 2; s->mb_x++) {
+    for (w->mb_y = 0; w->mb_y < w->mb_height * 2; w->mb_y++) {
+        x8_init_block_index(w, w->frame);
+        mb_xy = (w->mb_y >> 1) * (w->mb_width + 1);
+        for (w->mb_x = 0; w->mb_x < w->mb_width * 2; w->mb_x++) {
             x8_get_prediction(w);
             if (x8_setup_spatial_predictor(w, 0))
                 goto error;
             if (x8_decode_intra_mb(w, 0))
                 goto error;
 
-            if (s->mb_x & s->mb_y & 1) {
+            if (w->mb_x & w->mb_y & 1) {
                 x8_get_prediction_chroma(w);
 
                 /* when setting up chroma, no vlc is read,
@@ -819,21 +825,26 @@ int ff_intrax8_decode_picture(IntraX8Context *const w, int dquant,
                 if (x8_decode_intra_mb(w, 2))
                     goto error;
 
-                s->dest[1] += 8;
-                s->dest[2] += 8;
+                w->dest[1] += 8;
+                w->dest[2] += 8;
 
                 /* emulate MB info in the relevant tables */
                 s->mbskip_table[mb_xy]                 = 0;
                 s->mbintra_table[mb_xy]                = 1;
-                s->current_picture.qscale_table[mb_xy] = w->quant;
+                pict->qscale_table[mb_xy] = w->quant;
                 mb_xy++;
             }
-            s->dest[0] += 8;
+            w->dest[0] += 8;
         }
-        if (s->mb_y & 1)
-            ff_mpeg_draw_horiz_band(s, (s->mb_y - 1) * 8, 16);
+        if (w->mb_y & 1)
+            ff_draw_horiz_band(w->avctx, w->frame, w->frame,
+                               (w->mb_y - 1) * 8, 16,
+                               PICT_FRAME, 0, lowdelay);
     }
 
 error:
+    *mb_x = w->mb_x;
+    *mb_y = w->mb_y;
+
     return 0;
 }