Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / libzmpeg3 / video / slice.C
diff --git a/cinelerra-5.1/libzmpeg3/video/slice.C b/cinelerra-5.1/libzmpeg3/video/slice.C
new file mode 100644 (file)
index 0000000..b880f7f
--- /dev/null
@@ -0,0 +1,933 @@
+#include "../libzmpeg3.h"
+
+#ifdef __x86_64__
+#define USE_MMX
+#endif
+#ifdef USE_MMX
+#include "mmx.h"
+#if defined(__x86_64__)
+#define m_(v) (*(mmx_t*)(v))
+#else
+#define m_(v) (*(char*)(v))
+#endif
+#endif
+
+
+
+zslice_buffer_t::
+slice_buffer_t()
+{
+  data = new uint8_t[buffer_allocation=4096];
+  buffer_size = 0;
+  buffer_position = 0;
+  bits_size = 0;
+  bits = 0;
+}
+
+zslice_buffer_t::
+~slice_buffer_t()
+{
+  delete [] data;
+}
+
+uint8_t *zslice_buffer_t::
+expand_buffer(int bfrsz)
+{
+  long new_allocation = 2*buffer_allocation;
+  uint8_t *new_buffer = new uint8_t[new_allocation];
+  if( bfrsz > 0 ) memcpy(new_buffer,data,bfrsz);
+  delete [] data;
+  data = new_buffer;
+  buffer_allocation = new_allocation;
+  buffer_size = buffer_allocation-bfrsz-4;
+  return data + bfrsz;
+}
+
+    
+void zslice_buffer_t::
+fill_buffer(zbits_t *vstream)
+{
+  uint8_t *sbp = data;
+  vstream->next_byte_align();
+  demuxer_t *demux = vstream->demuxer;
+  /* sync stream to zcode and access demuxer */
+  uint32_t zcode = vstream->show_bits32_noptr();
+  for( int i=32; i>0; ) *sbp++ = (zcode>>(i-=8));
+  vstream->reset();
+  buffer_size = buffer_allocation-(4+4); /* sizeof(zcode)+padding */
+
+  /* Read the slice into the buffer including the slice start code */
+  while( !vstream->eof() ) {
+    if( buffer_size <= 0 ) sbp = expand_buffer(sbp - data);
+    if( (zcode&0xff) != 0 ) {
+      buffer_size -= 3;
+      zcode = (zcode<<8) | (*sbp++ = demux->read_char());
+      zcode = (zcode<<8) | (*sbp++ = demux->read_char());
+    }
+    else
+      --buffer_size;
+    zcode = (zcode<<8) | (*sbp++ = demux->read_char());
+    if( (zcode&0xffffff) == PACKET_START_CODE_PREFIX ) break;
+  }
+
+  /* finish trailing code as picture start code (0x100) */
+  *sbp++ = 0;
+  buffer_size = sbp - data;
+  /* reload stream bfr, position to start code */
+  vstream->reset(zcode);
+  vstream->get_byte_noptr();
+}
+
+/* limit coefficients to -2048..2047 */
+
+/* move/add 8x8-Block from block[comp] to refframe */
+
+int zslice_decoder_t::
+add_block(int comp, int bx, int by, int dct_type, int addflag)
+{
+  int cc, i, iincr;
+  uint8_t *rfp;
+  short *bp;
+  /* color component index */
+  cc = (comp < 4) ? 0 : (comp & 1) + 1; 
+
+  if( cc == 0 ) {   
+    /* luminance */
+    if( video->pict_struct == video_t::pics_FRAME_PICTURE ) {
+      if( dct_type ) {
+        /* field DCT coding */
+        rfp = video->newframe[0] + video->coded_picture_width *
+                (by + ((comp & 2) >> 1)) + bx + ((comp & 1) << 3);
+        iincr = (video->coded_picture_width << 1);
+      }
+      else {
+        /* frame DCT coding */
+        rfp = video->newframe[0] + video->coded_picture_width *
+                (by + ((comp & 2) << 2)) + bx + ((comp & 1) << 3);
+        iincr = video->coded_picture_width;
+      }
+    }
+    else {
+      /* field picture */
+      rfp = video->newframe[0] + (video->coded_picture_width << 1) *
+              (by + ((comp & 2) << 2)) + bx + ((comp & 1) << 3);
+      iincr = (video->coded_picture_width << 1);
+    }
+  }
+  else {
+    /* chrominance */
+
+    /* scale coordinates */
+    if( video->chroma_format != video_t::cfmt_444 ) bx >>= 1;
+    if( video->chroma_format == video_t::cfmt_420 ) by >>= 1;
+    if( video->pict_struct == video_t::pics_FRAME_PICTURE ) {
+      if( dct_type && (video->chroma_format != video_t::cfmt_420) ) {
+        /* field DCT coding */
+        rfp = video->newframe[cc] + video->chrom_width *
+                (by + ((comp & 2) >> 1)) + bx + (comp & 8);
+        iincr = (video->chrom_width << 1);
+      }
+      else {
+        /* frame DCT coding */
+        rfp = video->newframe[cc] + video->chrom_width *
+                (by + ((comp & 2) << 2)) + bx + (comp & 8);
+        iincr = video->chrom_width;
+      }
+    }
+    else {
+      /* field picture */
+      rfp = video->newframe[cc] + (video->chrom_width << 1) *
+              (by + ((comp & 2) << 2)) + bx + (comp & 8);
+      iincr = (video->chrom_width << 1);
+    }
+  }
+
+  bp = block[comp];
+
+  if( addflag ) {
+    for( i=0; i<8; ++i ) {
+#ifndef USE_MMX
+      rfp[0] = clip(bp[0] + rfp[0]);
+      rfp[1] = clip(bp[1] + rfp[1]);
+      rfp[2] = clip(bp[2] + rfp[2]);
+      rfp[3] = clip(bp[3] + rfp[3]);
+      rfp[4] = clip(bp[4] + rfp[4]);
+      rfp[5] = clip(bp[5] + rfp[5]);
+      rfp[6] = clip(bp[6] + rfp[6]);
+      rfp[7] = clip(bp[7] + rfp[7]);
+#else
+      movq_m2r(m_(rfp),mm1);      /* rfp[0..7] */
+      pxor_r2r(mm3,mm3);          /* zero */
+      pxor_r2r(mm4,mm4);          /* zero */
+      movq_m2r(m_(bp+0),mm5);     /* bp[0..3] */
+      movq_r2r(mm1,mm2);          /* copy rfp[0..7] */
+      movq_m2r(m_(bp+4),mm6);     /* bp[4..7] */
+      punpcklbw_r2r(mm3,mm1);     /* rfp[0..3] */
+      punpckhbw_r2r(mm3,mm2);     /* rfp[4..7] */
+      paddsw_r2r(mm5,mm1);        /* + bp[0..3] */
+      paddsw_r2r(mm6,mm2);        /* + bp[4..7] */
+      pcmpgtw_r2r(mm1,mm3);       /* 1s to fields < 0 */
+      pcmpgtw_r2r(mm2,mm4);       /* 1s to fields < 0 */
+      pandn_r2r(mm1,mm3);         /* clip <0 = zero */
+      pandn_r2r(mm2,mm4);         /* clip <0 = zero */
+      packuswb_r2r(mm4,mm3);      /* pack/clip >255 = 255 */
+      movq_r2m(mm3,m_(rfp));      /* store rfp[0..7] */
+#endif
+      rfp += iincr;
+      bp += 8;
+    }
+  }
+  else {
+    for( i=0; i<8; ++i ) {
+#ifndef USE_MMX
+      rfp[0] = clip(bp[0] + 128);
+      rfp[1] = clip(bp[1] + 128);
+      rfp[2] = clip(bp[2] + 128);
+      rfp[3] = clip(bp[3] + 128);
+      rfp[4] = clip(bp[4] + 128);
+      rfp[5] = clip(bp[5] + 128);
+      rfp[6] = clip(bp[6] + 128);
+      rfp[7] = clip(bp[7] + 128);
+#else
+      static short i128[4] = { 128, 128, 128, 128 };
+      movq_m2r(m_(i128),mm1);     /* 128,,128 */
+      pxor_r2r(mm3,mm3);          /* zero */
+      pxor_r2r(mm4,mm4);          /* zero */
+      movq_m2r(m_(bp+0),mm5);     /* bp[0..3] */
+      movq_r2r(mm1,mm2);          /* 128,,128 */
+      movq_m2r(m_(bp+4),mm6);     /* bp[4..7] */
+      paddsw_r2r(mm5,mm1);        /* + bp[0..3] */
+      paddsw_r2r(mm6,mm2);        /* + bp[4..7] */
+      pcmpgtw_r2r(mm1,mm3);       /* 1s to fields < 0 */
+      pcmpgtw_r2r(mm2,mm4);       /* 1s to fields < 0 */
+      pandn_r2r(mm1,mm3);         /* clip <0 = zero */
+      pandn_r2r(mm2,mm4);         /* clip <0 = zero */
+      packuswb_r2r(mm4,mm3);      /* pack/clip >255 = 255 */
+      movq_r2m(mm3,m_(rfp));      /* store rfp[0..7] */
+#endif
+      rfp+= iincr;
+      bp += 8;
+    }
+  }
+#ifdef USE_MMX
+  emms();
+#endif
+  return 0;
+}
+
+
+uint8_t zslice_decoder_t::
+non_linear_mquant_table[32] = {
+   0,  1,  2,  3,  4,  5,  6,  7,
+   8, 10, 12, 14, 16, 18, 20, 22,
+  24, 28, 32, 36, 40, 44, 48, 52,
+  56, 64, 72, 80, 88, 96,104,112,
+};
+
+int zslice_decoder_t::
+decode_slice()
+{
+  int comp;
+  int mb_type, cbp, motion_type = 0, dct_type;
+  int macroblock_address, mba_inc, mba_max;
+  int slice_vert_pos_ext;
+  uint32_t zcode;
+  int dc_dct_pred[3];
+  int mv_count, mv_format, mvscale;
+  int pmv[2][2][2], mv_field_sel[2][2];
+  int dmv, dmvector[2];
+  int qs;
+  int stwtype, stwclass; 
+  int snr_cbp;
+  int i;
+  /* number of macroblocks per picture */
+  mba_max = video->mb_width * video->mb_height;
+
+  /* field picture has half as many macroblocks as frame */
+  if( video->pict_struct != video_t::pics_FRAME_PICTURE )
+    mba_max >>= 1; 
+  macroblock_address = 0; 
+  /* first macroblock in slice is not skipped */
+  mba_inc = 0;
+  fault = 0;
+  zcode = slice_buffer->get_bits(32);
+  /* decode slice header (may change quant_scale) */
+  slice_vert_pos_ext = get_slice_hdr();
+  /* reset all DC coefficient and motion vector predictors */
+  dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0;
+  pmv[0][0][0] = pmv[0][0][1] = pmv[1][0][0] = pmv[1][0][1] = 0;
+  pmv[0][1][0] = pmv[0][1][1] = pmv[1][1][0] = pmv[1][1][1] = 0;
+
+  for( i=0; !slice_buffer->eob(); ++i ) {
+    if( mba_inc == 0 ) {
+      if( !slice_buffer->show_bits(23) ) break; /* Done */
+      /* decode macroblock address increment */
+      mba_inc = get_macroblock_address();
+      if( fault ) return 1;
+      if( i == 0 ) {
+        /* Get the macroblock_address */
+        int mline = (slice_vert_pos_ext << 7) + (zcode&0xff) - 1;
+        macroblock_address = mline * video->mb_width + mba_inc - 1;
+        /* first macroblock in slice: not skipped */
+        mba_inc = 1;
+      }
+    }
+
+    if( fault ) return 1;
+    if( macroblock_address >= mba_max ) {
+      /* mba_inc points beyond picture dimensions */
+//zerr("too many macroblocks in picture\n"); */
+        return 1;
+    }
+
+    /* not skipped */
+    if( mba_inc == 1 ) {
+      macroblock_modes(&mb_type, &stwtype, &stwclass, &motion_type,
+        &mv_count, &mv_format, &dmv, &mvscale, &dct_type);
+      if( fault ) return 1;
+
+      if( mb_type & mb_QUANT ) {
+        qs = slice_buffer->get_bits(5);
+        if( video->mpeg2 )
+          quant_scale = video->qscale_type ?
+            non_linear_mquant_table[qs] : (qs << 1);
+        else 
+          quant_scale = qs;
+
+        /* make sure quant_scale is valid */
+        if( video->scalable_mode == sc_DP )
+          quant_scale = quant_scale; /*???*/
+      }
+
+      /* motion vectors */
+
+      /* decode forward motion vectors */
+      if( (mb_type & mb_FORWARD) ||
+          ((mb_type & mb_INTRA) && video->conceal_mv) ) {
+        if( video->mpeg2 )
+          motion_vectors(pmv, dmvector, mv_field_sel, 0, mv_count, mv_format,
+            video->h_forw_r_size, video->v_forw_r_size, dmv, mvscale);
+        else
+          motion_vector(pmv[0][0], dmvector,
+            video->forw_r_size, video->forw_r_size, 0, 0, video->full_forw);
+      }
+      if( fault ) return 1;
+
+      /* decode backward motion vectors */
+      if( mb_type & mb_BACKWARD ) {
+        if( video->mpeg2 )
+          motion_vectors(pmv, dmvector, mv_field_sel, 1, mv_count, mv_format, 
+          video->h_back_r_size, video->v_back_r_size, 0, mvscale);
+        else
+          motion_vector(pmv[0][1], dmvector, 
+            video->back_r_size, video->back_r_size, 0, 0, video->full_back);
+      }
+
+      if( fault ) return 1;
+
+      /* remove marker_bit */
+      if( (mb_type & mb_INTRA) && video->conceal_mv )
+        slice_buffer->flush_bit();
+
+      /* macroblock_pattern */
+      if( mb_type & mb_PATTERN ) {
+        cbp = get_cbp();
+        if( video->chroma_format == video_t::cfmt_422 ) {
+          /* coded_block_pattern_1 */
+          cbp = (cbp << 2) | slice_buffer->get_bits(2); 
+        }
+        else if( video->chroma_format == video_t::cfmt_444 ) {
+          /* coded_block_pattern_2 */
+          cbp = (cbp << 6) | slice_buffer->get_bits(6); 
+        }
+      }
+      else
+        cbp = (mb_type & mb_INTRA) ? ((1 << video->blk_cnt) - 1) : 0;
+      if( fault ) return 1;
+
+      /* decode blocks */
+      clear_block(0, video->blk_cnt);
+      for( comp=0; comp<video->blk_cnt; ++comp ) {
+        if( cbp & (1 << (video->blk_cnt-comp-1)) ) {
+          if( mb_type & mb_INTRA ) {
+            if( video->mpeg2 )
+              get_mpg2_intra_block(comp, dc_dct_pred);
+            else
+              get_intra_block(comp, dc_dct_pred);
+          }
+          else {
+            if( video->mpeg2 )
+              get_mpg2_inter_block(comp);
+            else           
+              get_inter_block(comp);
+          }
+          if( fault ) return 1;
+        }
+      }
+
+      /* reset intra_dc predictors */
+      if( !(mb_type & mb_INTRA) )
+        dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0;
+
+      /* reset motion vector predictors */
+      if( (mb_type & mb_INTRA) && !video->conceal_mv ) {
+        /* intra mb without concealment motion vectors */
+        pmv[0][0][0] = pmv[0][0][1] = pmv[1][0][0] = pmv[1][0][1] = 0;
+        pmv[0][1][0] = pmv[0][1][1] = pmv[1][1][0] = pmv[1][1][1] = 0;
+      }
+
+      if( (video->pict_type == video_t::pic_type_P) &&
+          !(mb_type & (mb_FORWARD | mb_INTRA)) ) {
+        /* non-intra mb without forward mv in a P picture */
+        pmv[0][0][0] = pmv[0][0][1] = pmv[1][0][0] = pmv[1][0][1] = 0;
+
+        /* derive motion_type */
+        if( video->pict_struct == video_t::pics_FRAME_PICTURE )
+          motion_type = mc_FRAME;
+        else {
+          motion_type = mc_FIELD;
+          /* predict from field of same parity */
+          mv_field_sel[0][0] = video->pict_struct == video_t::pics_BOTTOM_FIELD ? 1 : 0;
+        }
+      }
+
+      if( stwclass == 4 ) {
+        /* purely spatially predicted macroblock */
+        pmv[0][0][0] = pmv[0][0][1] = pmv[1][0][0] = pmv[1][0][1] = 0;
+        pmv[0][1][0] = pmv[0][1][1] = pmv[1][1][0] = pmv[1][1][1] = 0;
+      }
+    }
+    else {
+      /* mba_inc!=1: skipped macroblock */
+      clear_block(0, video->blk_cnt);
+
+      /* reset intra_dc predictors */
+      dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0;
+
+      /* reset motion vector predictors */
+      if( video->pict_type == video_t::pic_type_P )
+        pmv[0][0][0] = pmv[0][0][1] = pmv[1][0][0] = pmv[1][0][1] = 0;
+
+      /* derive motion_type */
+      if( video->pict_struct == video_t::pics_FRAME_PICTURE )
+        motion_type = mc_FRAME;
+      else {
+        motion_type = mc_FIELD;
+        /* predict from field of same parity */
+        mv_field_sel[0][0] = mv_field_sel[0][1] =
+          (video->pict_struct == video_t::pics_BOTTOM_FIELD) ? 1 : 0;
+      }
+
+      /* skipped I are spatial-only predicted, */
+      /* skipped P and B are temporal-only predicted */
+      stwtype = video->pict_type == video_t::pic_type_I ? 8 : 0;
+      mb_type &= ~mb_INTRA; /* clear mb_INTRA */
+      cbp = 0; /* no block data */
+    }
+
+    snr_cbp = 0;
+
+    /* pixel coordinates of top left corner of current macroblock */
+    int mx = macroblock_address % video->mb_width;
+    int my = macroblock_address / video->mb_width;
+
+    /* thumbnails */
+    if( video->thumb && video->pict_type == video_t::pic_type_I ) {
+      uint8_t *ap = video->tdat + 4*my*video->mb_width + 2*mx;
+      uint8_t *bp = ap + 2*video->mb_width;
+      if( (mb_type&mb_INTRA) != 0 ) {
+        *ap = clip(128 + block[0][0]/8);  ++ap;
+        *ap = clip(128 + block[1][0]/8);
+        *bp = clip(128 + block[2][0]/8);  ++bp;
+        *bp = clip(128 + block[3][0]/8);
+      }
+      else {
+        *ap = clip(*ap + block[0][0]/8);  ++ap;
+        *ap = clip(*ap + block[1][0]/8);
+        *bp = clip(*bp + block[2][0]/8);  ++bp;
+        *bp = clip(*bp + block[3][0]/8);
+      }
+    }
+    /* skimming */
+    if( !video->skim ) {
+      int bx = 16*mx, by = 16*my;
+      /* motion compensation */
+      if( !(mb_type & mb_INTRA) )
+        video->reconstruct( bx, by, mb_type, motion_type, pmv, 
+          mv_field_sel, dmvector, stwtype);
+
+      /* copy or add block data into picture */
+      for( comp=0; comp<video->blk_cnt; ++comp ) {
+        if( (cbp | snr_cbp) & (1 << (video->blk_cnt-1-comp)) ) {
+          idct_conversion(block[comp]);
+          add_block(comp, bx, by, dct_type, !(mb_type & mb_INTRA) ? 1 : 0);
+        }
+      }
+    }
+
+    /* advance to next macroblock */
+    ++macroblock_address;
+    --mba_inc;
+  }
+
+  return 0;
+}
+
+void zslice_decoder_t::
+slice_loop()
+{
+  while( !done ) {
+    input_lock.lock();
+    while( !done ) {
+      decode_slice();
+      video->put_slice_buffer(slice_buffer);
+      if( get_active_slice_buffer() ) break;
+    }
+  }
+}
+
+void *zslice_decoder_t::
+the_slice_loop(void *the_slice_decoder)
+{
+  ((slice_decoder_t *)the_slice_decoder)->slice_loop();
+  return 0;
+}
+
+zslice_decoder_t::
+slice_decoder_t()
+{
+  owner = pthread_self();
+  video = 0;
+  slice_buffer = 0;
+  done = 0;
+  input_lock.lock();
+  pthread_create(&tid,0,the_slice_loop, this);
+}
+
+zslice_decoder_t::
+~slice_decoder_t()
+{
+  done = 1;
+  input_lock.unlock();
+  pthread_join(tid, 0);
+}
+
+
+int zslice_decoder_t::
+get_cbp()
+{
+  int zcode;
+  if( (zcode=slice_buffer->show_bits(9)) >= 128 ) {
+    zcode >>= 4;
+    slice_buffer->flush_bits(CBPtab0[zcode].len);
+    return CBPtab0[zcode].val;
+  }
+
+  if( zcode >= 8 ) {
+    zcode >>= 1;
+    slice_buffer->flush_bits(CBPtab1[zcode].len);
+    return CBPtab1[zcode].val;
+  }
+
+  if( zcode < 1 ) {
+//zerr("invalid coded_block_pattern code\n");
+    fault = 1;
+    return 0;
+  }
+
+  slice_buffer->flush_bits(CBPtab2[zcode].len);
+  return CBPtab2[zcode].val;
+}
+
+
+/* set block to zero */
+int zslice_decoder_t::
+clear_block(int comp, int size)
+{
+  sparse[comp] = 1;
+  memset(block[comp], 0, size*sizeof(block[0]));
+  return 0;
+}
+
+int zslice_buffer_t::
+get_dc_lum()
+{
+  int zcode, size, val;
+  zcode = show_bits(5); /* decode length */
+  if( zcode < 31 ) {
+    size = DClumtab0[zcode].val;
+    flush_bits(DClumtab0[zcode].len);
+  }
+  else {
+    zcode = show_bits(9) - 0x1f0;
+    size = DClumtab1[zcode].val;
+    flush_bits(DClumtab1[zcode].len);
+  }
+
+  if( size ) {
+    val = get_bits(size);
+    if( (val & (1 << (size-1))) == 0 )
+      val -= (1 << size)-1;
+  }
+  else
+    val = 0;
+
+  return val;
+}
+
+
+int zslice_buffer_t::
+get_dc_chrom()
+{
+  int zcode, size, val;
+  zcode = show_bits(5); /* decode length */
+  if( zcode < 31 ) {
+    size = DCchromtab0[zcode].val;
+    flush_bits(DCchromtab0[zcode].len);
+  }
+  else {
+    zcode = show_bits(10) - 0x3e0;
+    size = DCchromtab1[zcode].val;
+    flush_bits(DCchromtab1[zcode].len);
+  }
+
+  if( size ) {
+    val = get_bits(size);
+    if( (val & (1 << (size-1))) == 0 )
+      val -= (1 << size)-1;
+  }
+  else 
+    val = 0;
+
+  return val;
+}
+
+uint16_t *zslice_decoder_t::DCTlutab[3] = { 0, };
+
+void zslice_decoder_t::
+init_lut(uint16_t *&lutbl, DCTtab_t *tabn, DCTtab_t *tab0, DCTtab_t *tab1)
+{
+  int i = 0;
+  uint16_t *lut = new uint16_t[0x10000];
+  while( i < 0x0010 ) { lut[i] = 0;  ++i; }
+  while( i < 0x0020 ) { lut[i] = lu_pack(&DCTtab6[i - 16]);         ++i; }
+  while( i < 0x0040 ) { lut[i] = lu_pack(&DCTtab5[(i >> 1) - 16]);  ++i; }
+  while( i < 0x0080 ) { lut[i] = lu_pack(&DCTtab4[(i >> 2) - 16]);  ++i; }
+  while( i < 0x0100 ) { lut[i] = lu_pack(&DCTtab3[(i >> 3) - 16]);  ++i; }
+  while( i < 0x0200 ) { lut[i] = lu_pack(&DCTtab2[(i >> 4) - 16]);  ++i; }
+  while( i < 0x0400 ) { lut[i] = lu_pack(   &tab1[(i >> 6) - 8]);   ++i; }
+  int tblsz = !tabn ? 0x10000 : 0x4000;
+  while( i < tblsz  ) { lut[i] = lu_pack(   &tab0[(i >> 8) - 4]);   ++i; }
+  while( i <0x10000 ) { lut[i] = lu_pack(   &tabn[(i >>12) - 4]);   ++i; }
+  lutbl = lut;
+}
+
+void zslice_decoder_t::
+init_tables()
+{
+  if( DCTlutab[0] ) return;
+  init_lut(DCTlutab[0], DCTtabfirst, DCTtab0,  DCTtab1);
+  init_lut(DCTlutab[1], DCTtabnext , DCTtab0,  DCTtab1);
+  init_lut(DCTlutab[2],          0 , DCTtab0a, DCTtab1a);
+}
+
+/* decode one MPEG-1 coef */
+
+inline int zslice_decoder_t::
+get_coef(uint16_t *lut)
+{
+  int v, s, i = idx;
+  uint16_t zcode = slice_buffer->show_bits(16);
+  uint16_t lu = lut[zcode];
+  if( !lu ) return fault = 1;
+  int len = lu_len(lu);
+  slice_buffer->flush_bits(len);
+  int run = lu_run(lu);
+  if( run >= 32 ) {       /* escape */
+    if( run == 32 ) return -1;  /* end of block */
+    i += slice_buffer->get_bits(6);
+    if( (v = slice_buffer->get_bits(8)) < 128 ) {
+      s = 0;
+      if( !v ) v = slice_buffer->get_bits(8);
+    }
+    else {
+      if( v == 128 ) v = slice_buffer->get_bits(8);
+      s = 1;  v = 256 - v;
+    }
+  }
+  else {
+    i += run;
+    v = lu_level(lu);
+    s = slice_buffer->get_bit();
+  }
+  if( i >= 64 ) return fault = 1;
+  val = v;  sign = s;  idx = i;
+  return 0;
+}
+
+/* decode one MPEG-2 coef */
+
+inline int zslice_decoder_t::
+get_mpg2_coef(uint16_t *lut)
+{
+  int v, s, i = idx;
+  uint16_t zcode = slice_buffer->show_bits(16);
+  uint16_t lu = lut[zcode];
+  if( !lu ) return fault = 1;
+  int len = lu_len(lu);
+  slice_buffer->flush_bits(len);
+  int run = lu_run(lu);
+  if( run >= 32 ) {       /* escape */
+    if( run == 32 ) return -1;  /* end of block */
+    i += slice_buffer->get_bits(6);
+    v = slice_buffer->get_bits(12);
+    if( (v & 2047) == 0 ) return fault = 1;
+    s = (v >= 2048) ? 1 : 0;
+    if( s != 0 ) v = 4096 - v;
+  }
+  else {
+    i += run;
+    v = lu_level(lu);
+    s = slice_buffer->get_bit();
+  }
+  if( i >= 64 ) return fault = 1;
+  val = v;  sign = s;  idx = i;
+  return 0;
+}
+
+
+/* decode one intra coded MPEG-1 block */
+
+void zslice_decoder_t::
+get_intra_block(int comp, int dc_dct_pred[])
+{
+  int dc_coef = /* decode DC coefficients */
+    comp <  4 ? (dc_dct_pred[0] += slice_buffer->get_dc_lum())   :
+    comp == 4 ? (dc_dct_pred[1] += slice_buffer->get_dc_chrom()) :
+                (dc_dct_pred[2] += slice_buffer->get_dc_chrom()) ;
+  short *bp = block[comp];
+  bp[0] = dc_coef << 3;
+
+  /* decode AC coefficients */
+  int *qmat = video->intra_quantizer_matrix;
+  int j = 0;
+  idx = 1;
+  while( !get_coef(DCTlutab[1]) ) {
+    j = video->zigzag_scan_table[idx++];
+    int v = (((val * quant_scale*qmat[j])>>3)-1) | 1;
+    bp[j] = sign ? -v : v;
+  }
+
+  if( j > 0 ) /* not a sparse matrix ! */
+    sparse[comp] = 0;
+}
+
+/* decode one intra coded MPEG-2 block */
+void zslice_decoder_t::
+get_mpg2_intra_block(int comp, int dc_dct_pred[])
+{
+  int *qmat = (comp < 4 || video->chroma_format == video_t::cfmt_420) ?
+    video->intra_quantizer_matrix : video->chroma_intra_quantizer_matrix;
+  int dc_coef = /* decode DC coefficients */
+    comp < 4  ? (dc_dct_pred[0] += slice_buffer->get_dc_lum())   :
+    !(comp&1) ? (dc_dct_pred[1] += slice_buffer->get_dc_chrom()) :
+                (dc_dct_pred[2] += slice_buffer->get_dc_chrom()) ;
+/* with data partitioning, data always goes to base layer */
+  short *bp = block[comp]; 
+  bp[0] = dc_coef << (3 - video->dc_prec);
+
+  uint8_t *scan_table = video->altscan ?
+    video->alternate_scan_table : video->zigzag_scan_table;
+  uint16_t *lutbl = !video->intravlc ? DCTlutab[1] : DCTlutab[2];
+
+  int j = 0;
+  idx = 1;
+  while( !get_mpg2_coef(lutbl) ) { /* decode AC coefficients */
+    j = scan_table[idx++];
+    int v = (val * quant_scale*qmat[j]) >> 4;
+    bp[j] = sign ? -v : v;
+  }
+
+  if( j > 0 ) /* not a sparse matrix ! */
+    sparse[comp] = 0;
+}
+
+
+/* decode one non-intra coded MPEG-1 block */
+
+void zslice_decoder_t::
+get_inter_block(int comp)
+{
+  short *bp = block[comp];
+
+  idx = 0;
+  if( get_coef(DCTlutab[0])) return;
+  int j = video->zigzag_scan_table[idx++];
+  int *qmat = video->non_intra_quantizer_matrix;
+  int v = (((((val<<1) + 1) * quant_scale*qmat[j])>>4)-1) | 1;
+  bp[j] = sign ? -v : v;
+
+  /* decode AC coefficients */
+  while( !get_coef(DCTlutab[1]) ) {
+    j = video->zigzag_scan_table[idx++];
+    v = (((((val<<1) + 1) * quant_scale*qmat[j])>>4)-1) | 1;
+    bp[j] = sign ? -v : v;
+  }
+
+  if( j > 0 ) /* not a sparse matrix ! */
+    sparse[comp] = 0;
+}
+
+
+/* decode one non-intra coded MPEG-2 block */
+
+void zslice_decoder_t::
+get_mpg2_inter_block(int comp)
+{
+  /* with data partitioning, data always goes to base layer */
+  short *bp = block[comp];
+  int *qmat = (comp < 4 || video->chroma_format == video_t::cfmt_420) ?
+    video->non_intra_quantizer_matrix : video->chroma_non_intra_quantizer_matrix;
+  uint8_t *scan_table = video->altscan ?
+    video->alternate_scan_table : video->zigzag_scan_table;
+
+  idx = 0;
+  if( get_mpg2_coef(DCTlutab[0]) ) return;
+  int j = scan_table[idx++];
+  int v = (((val << 1)+1) * quant_scale*qmat[j]) >> 5;
+  bp[j] = sign ? -v : v ;
+
+  /* decode AC coefficients */
+  while( !get_mpg2_coef(DCTlutab[1]) ) {
+    j = scan_table[idx++];
+    int v = (((val << 1)+1) * quant_scale*qmat[j]) >> 5;
+    bp[j] = sign ? -v : v ;
+  }
+
+  if( j > 0 ) /* not a sparse matrix ! */
+    sparse[comp] = 0;
+}
+
+
+void zmpeg3_t::
+decode_slice(zslice_buffer_t *buffer)
+{
+  decoder_lock.lock();
+  if( avail_slice_decoders ) {
+    zslice_decoder_t *decoder = avail_slice_decoders;
+    avail_slice_decoders = decoder->next;
+    decoder->slice_buffer = buffer;
+    decoder->video = buffer->video;
+    if( !decoder_active_locked++ )
+      decoder_active.lock();
+    decoder->input_lock.unlock();
+  }
+  else {
+    buffer->next = active_slice_buffers;
+    active_slice_buffers = buffer;
+  }
+  decoder_lock.unlock();
+}
+
+int zslice_decoder_t::
+get_active_slice_buffer()
+{
+  int result;
+  src->decoder_lock.lock();
+  zslice_buffer_t *buffer = src->active_slice_buffers;
+  if( !buffer ) {
+    next = src->avail_slice_decoders;
+    src->avail_slice_decoders = this;
+    if( !--src->decoder_active_locked )
+      src->decoder_active.unlock();
+    slice_buffer = 0;
+    video = 0;
+    result = 1;
+  }
+  else {
+    src->active_slice_buffers = buffer->next;
+    slice_buffer = buffer;
+    video = buffer->video;
+    result = 0;
+  }
+  src->decoder_lock.unlock();
+  return result;
+}
+
+void zmpeg3_t::
+allocate_slice_decoders()
+{
+  if( slice_decoders ) return;
+  int count = cpus;
+  if( count > MAX_CPUS ) count = MAX_CPUS;
+  slice_decoders = new slice_decoder_t[count];
+  slice_decoder_t *decoder = &slice_decoders[0];
+  avail_slice_decoders = 0;
+  for( int i=count; --i>=0; ++decoder ) {
+    decoder->src = this;
+    decoder->next = avail_slice_decoders;
+    avail_slice_decoders = decoder;
+  }
+  total_slice_decoders = count;
+}
+
+void zmpeg3_t::
+delete_slice_decoders()
+{
+  if( !slice_decoders ) return;
+  delete [] slice_decoders;
+  slice_decoders = 0;
+  total_slice_decoders = 0;
+}
+
+void zmpeg3_t::
+reallocate_slice_decoders()
+{
+  decoder_active.lock();
+  decoder_active.unlock();
+  decoder_lock.lock();
+  if( !decoder_active_locked ) {
+    delete_slice_decoders();
+    allocate_slice_decoders();
+  }
+  decoder_lock.unlock();
+}
+
+void zvideo_t::
+allocate_slice_buffers()
+{
+  if( slice_buffers ) return;
+  int count = 2*src->cpus;
+  if( count > 2*MAX_CPUS ) count = 2*MAX_CPUS;
+  slice_buffers = new slice_buffer_t[count];
+  slice_buffer_t *buffer = &slice_buffers[0];
+  avail_slice_buffers = 0;
+  for( int i=count; --i>=0; ++buffer ) {
+    buffer->next = avail_slice_buffers;
+    avail_slice_buffers = buffer;
+  }
+  total_slice_buffers = count;
+}
+
+void zvideo_t::
+delete_slice_buffers()
+{
+  if( !slice_buffers ) return;
+  delete [] slice_buffers;
+  slice_buffers = 0;
+  total_slice_buffers = 0;
+}
+
+void zvideo_t::
+reallocate_slice_buffers()
+{
+  slice_active.lock();
+  slice_active.unlock();
+  slice_lock.lock();
+  if( !slice_active_locked ) {
+    delete_slice_buffers();
+    allocate_slice_buffers();
+  }
+  slice_lock.unlock();
+} 
+