www.pudn.com > p264decoder.zip > macroblock.c


/*****************************************************************************
 * macroblock.c: h264 decoder library
 *****************************************************************************
 * Copyright (C) 2003 Laurent Aimar
 * $Id: macroblock.c,v 1.1 2004/06/03 19:27:07 fenrir Exp $
 *
 * Authors: Laurent Aimar 
 *
 * Maintained by Peter Lee (lspbeyond@126.com)
 * 2005-2006 at icas of Ningbo university, China
 * p264 Decoder site: http://p264decoder.zj.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

#include 
#include 
#include 
#include 

#include "core/core.h"
#include "core/vlc.h"
#include "vlc.h"
#include "dec_cavlc.h"
#include "macroblock.h"


static const uint8_t i16x16_eg_to_cbp[26][3] =  
{ 
  0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 
    0, 1, 0, 1, 1, 0, 2, 1, 0, 3, 1, 0, 0, 2, 0,  
    1, 2, 0, 2, 2, 0, 3, 2, 0, 0, 0, 15, 1, 0, 15,  
    2, 0, 15, 3, 0, 15, 0, 1, 15, 1, 1, 15, 2, 1, 15,  
    3, 1, 15, 0, 2, 15, 1, 2, 15, 2, 2, 15, 3, 2, 15 
}; 
 
static const uint8_t golomb_to_intra4x4_cbp[48] = 
{ 
  47, 31, 15, 0, 23, 27, 29, 30, 7, 11, 13, 14, 39, 43, 45, 
    46, 16, 3, 5, 10, 12, 19, 21, 26, 28, 35, 37, 42, 44, 1, 
    2, 4, 8, 17, 18, 20, 24, 6, 9, 22, 25, 32, 33, 34, 36, 40, 
    38, 41 
}; 
 
static const uint8_t golomb_to_inter_cbp[48] =  
{ 
  0, 16, 1, 2, 4, 8, 32, 3, 5, 10, 12, 15, 47, 7, 11, 13, 14, 
    6, 9, 31, 35, 37, 42, 44, 33, 34, 36, 40, 39, 43, 45, 46, 17, 
    18, 20, 24, 19, 21, 26, 28, 23, 27, 29, 30, 22, 25, 38, 41 
};

enum //mb big type
{
  MB_I=0,
  MB_P,
  MB_B,
  MB_SI,
  MB_SP
};
int read_mb_type(p264_t *h, bs_t *s)
{
  int i_mb_big_type;
  int i_mb_type;

  i_mb_type=bs_read_ue( s );
  //if(h->sh.i_frame_num==1) //lspdebug
  //{
  //  printf("%d,",i_mb_type);
  //}

  //find the mb big type
  switch( h->sh.i_type ) 
  { 
  case SLICE_TYPE_I: 
    i_mb_big_type=MB_I; 
    break; 
  case SLICE_TYPE_P: 
    if(i_mb_type<5) 
    { 
      i_mb_big_type=MB_P; 
    } 
    else 
    { 
      i_mb_big_type=MB_I; 
      i_mb_type-=5; 
    } 
    break; 
  case SLICE_TYPE_B: 
    if(i_mb_type<23) 
    { 
      i_mb_big_type=MB_B; 
    } 
    else 
    { 
      i_mb_big_type=MB_I; 
      i_mb_type-=23; 
    } 
    break; 
  default: 
    fprintf( stderr, "slice unsupported yet \n" ); //lsptodo 
    return -1; 
  }//end of switch( h->sh.i_type )

  //set the predict mode and cbp info
  if (MB_I == i_mb_big_type) 
  { 
    if (0==i_mb_type) 
    { 
      h->mb.i_type=I_4x4; 
    } 
    else if (i_mb_type<25) 
    { 
      h->mb.i_type=I_16x16; 
      h->mb.i_intra16x16_pred_mode = (i_mb_type - 1)%4; 
      h->mb.i_cbp_chroma = ( (i_mb_type-1) / 4 )%3; 
      h->mb.i_cbp_luma   = (i_mb_type>12) ? 0x0f : 0x00; 
    } 
    else if (25==i_mb_type) 
    { 
      h->mb.i_type=I_PCM; 
    } 
    else 
    { 
      fprintf( stderr, "invalid mb type %d \n", i_mb_type); 
      return -1; 
    } 
  }//end of if (MB_I == i_mb_big_type)
  else if (MB_P == i_mb_big_type) 
  { 
    if (0==i_mb_type) //ÊÇ·ñÍêÕûÁË£¿£¿ 
    { 
      h->mb.i_type=P_L0; 
      h->mb.i_partition = D_16x16; 
    } 
    else if (1==i_mb_type) 
    { 
      h->mb.i_type=P_L0; 
      h->mb.i_partition = D_16x8; 
    } 
    else if (2==i_mb_type) 
    { 
      h->mb.i_type=P_L0; 
      h->mb.i_partition = D_8x16; 
    } 
    else if (3==i_mb_type || 4==i_mb_type) 
    { 
      h->mb.i_type=P_8x8;  
      h->mb.i_partition = D_8x8; 
    } 
    else 
    { 
      fprintf( stderr, "invalid mb type %d\n", i_mb_type); 
      return -1; 
    } 
  }//end of else if (MB_P == i_mb_big_type)
  else if (MB_B == i_mb_big_type) 
  { 
    //lsptodo:  
  }//end of else if (MB_B == i_mb_big_type)

  return 0;

}

//lspfinish
void set_mb_partition_ref( p264_t *h, int i_list, int i_part_idx, int i_ref )
{ 
  int x,  y; 
  int width,  height;
  int dx, dy;
  int block8_idx;
  int i_partition=h->mb.i_partition;

  width=p264_mb_partition_size_table[i_partition][0]*2;
  height=p264_mb_partition_size_table[i_partition][1]*2;

  block8_idx=p264_mb_partition_size_table[i_partition][2]*i_part_idx;
  x=p264_block8_to_block4_table[block8_idx][0];
  y=p264_block8_to_block4_table[block8_idx][1];

  for( dx = 0; dx < width; dx++ )
  {
    for( dy = 0; dy < height; dy++ )
    {
      int j=P264_SCAN8_0 + (y+dy)*8 + x+dx;
      h->mb.cache.ref[i_list][p264_scan8[j]]=i_ref;
    }
  } 
 
}

//lspfinish
void set_mb_partition_mv( p264_t *h, int i_list, int i_part_idx, int mvd[2] )
{ 
  int x,  y; 
  int width,  height;
  int dx, dy;
  int block8_idx;
  int i_partition=h->mb.i_partition;
  int mv[2];

  width=p264_mb_partition_size_table[i_partition][0]*2;
  height=p264_mb_partition_size_table[i_partition][1]*2;

  block8_idx=p264_mb_partition_size_table[i_partition][2]*i_part_idx;
  x=p264_block8_to_block4_table[block8_idx][0];
  y=p264_block8_to_block4_table[block8_idx][1];

  p264_mb_predict_mv( h, i_list, block8_idx*4, width, mv );
  mv[0]+=mvd[0];
  mv[1]+=mvd[1];

  for( dx = 0; dx < width; dx++ )
  {
    for( dy = 0; dy < height; dy++ )
    {
      int j=P264_SCAN8_0 + (y+dy)*8 + x+dx;
      h->mb.cache.mv[i_list][j][0]=mv[0];
      h->mb.cache.mv[i_list][j][1]=mv[1];
    }
  } 
 
}

//lspfinish
void set_sub_mb_partition_mv( p264_t *h, int i_list, int i_part_idx, int i_sub_part_idx, int mvd[2] )
{ 
  int width,  height;
  int dx, dy;
  int i_sub_part=h->mb.i_sub_partition[i_part_idx];
  int mv[2];

  width=p264_mb_partition_size_table[i_sub_part][0];
  height=p264_mb_partition_size_table[i_sub_part][1];

  p264_mb_predict_mv( h, i_list, i_part_idx*4+i_sub_part_idx, width, mv );
  mv[0]+=mvd[0];
  mv[1]+=mvd[1];

  for( dx = 0; dx < width; dx++ )
  {
    for( dy = 0; dy < height; dy++ )
    {
      int j=i_part_idx*4 + dy*2 + dx;
      h->mb.cache.mv[i_list][p264_scan8[j]][0]=mv[0];
      h->mb.cache.mv[i_list][p264_scan8[j]][1]=mv[1];
    }
  } 
 
}


int read_intra_mb_pred(p264_t *h, bs_t *s)
{
  int i;

  if( h->mb.i_type == I_4x4 )
  {
    for( i = 0; i < 16; i++ )
    {
      int b_coded;

      b_coded = bs_read1( s ); //true means it's the most probable mode

      if( b_coded )
      {
        h->mb.cache.intra4x4_pred_mode[p264_scan8[i]] = p264_mb_predict_intra4x4_mode( h, i );
      }
      else
      {
        int i_predicted_mode = p264_mb_predict_intra4x4_mode( h, i );
        int i_mode = bs_read( s, 3 );

        if( i_mode >= i_predicted_mode )
        {
          h->mb.cache.intra4x4_pred_mode[p264_scan8[i]] = i_mode + 1;
        }
        else
        {
          h->mb.cache.intra4x4_pred_mode[p264_scan8[i]] = i_mode;
        }
      }
    }
  }

  h->mb.i_chroma_pred_mode = bs_read_ue( s );

  return 0;
}

//lsptodo: support b
int read_inter_mb_pred(p264_t *h, bs_t *s)
{
  int i_part = p264_mb_partition_count_table[h->mb.i_partition];
  int i;
  int mvd[2];

  //ref
  if (h->sh.i_num_ref_idx_l0_active > 1) 
  { 
    int i_ref; 
    for( i = 0; i < i_part; i++ )
    {
      i_ref = bs_read_te( s, h->sh.i_num_ref_idx_l0_active - 1 );

      set_mb_partition_ref(h,0,i,i_ref);
    } 
  }
  else
  {
    for (i=0; i<16; i++) 
    { 
      h->mb.cache.ref[0][p264_scan8[i]]=0;  
    }
  }

  //mv
  for( i = 0; i < i_part; i++ )
  {
    mvd[0] = bs_read_se( s );
    mvd[1] = bs_read_se( s );

    set_mb_partition_mv(h,0,i,mvd);
  }

  return 0;
}

//lsptodo: support b
int read_inter_sub_mb_pred(p264_t *h, bs_t *s)
{
  int i;

  //read sub mb type
  for( i = 0; i < 4; i++ )
  {
    int i_sub_partition;

    i_sub_partition = bs_read_ue( s );
    switch( i_sub_partition )
    {
    case 0:
      h->mb.i_sub_partition[i] = D_L0_8x8;
      break;
    case 1:
      h->mb.i_sub_partition[i] = D_L0_8x4;
      break;
    case 2:
      h->mb.i_sub_partition[i] = D_L0_4x8;
      break;
    case 3:
      h->mb.i_sub_partition[i] = D_L0_4x4;
      break;
    default:
      fprintf( stderr, "invalid i_sub_partition\n" );
      return -1;
    }
  }

  //ref
  if (h->sh.i_num_ref_idx_l0_active > 1)//lsp?? bs_read_te can judge it already 
  { 
    int i_ref; 
    for( i = 0; i < 4; i++ )
    {
      i_ref = bs_read_te( s, h->sh.i_num_ref_idx_l0_active - 1 );

      set_mb_partition_ref(h,0,i,i_ref);
    } 
  }
  else
  {
    for (i=0; i<16; i++) 
    { 
      h->mb.cache.ref[0][p264_scan8[i]]=0;  
    }
  }

  //mv
  for( i = 0; i < 4; i++ )
  {
    int i_sub_part=p264_mb_partition_count_table[h->mb.i_sub_partition[i]];
    int j;
    int mvd[2];

    for (j=0; jmb.i_type == I_16x16 )
  {
    /* DC Luma */
    if( p264dec_read_residual_block_cavlc( h, s, BLOCK_INDEX_LUMA_DC , h->dct.luma16x16_dc, 16 ) < 0 )
    {
      return -1;
    }

    /* AC Luma */
    for( i = 0; i < 16; i++ )
    {
      if( h->mb.i_cbp_luma & ( 1 << ( i / 4 ) ) )
      {
        if( p264dec_read_residual_block_cavlc( h, s, i, h->dct.block[i].residual_ac, 15 ) < 0 )
        {
          return -1;
        }
      }
      else
      {
        h->mb.cache.non_zero_count[p264_scan8[i]]=0;
      }
    }
  }//end of if( h->mb.i_type == I_16x16 )
  else
  {
    for( i = 0; i < 16; i++ )
    {
      if( h->mb.i_cbp_luma & ( 1 << ( i / 4 ) ) )
      {
        if( p264dec_read_residual_block_cavlc( h, s, i, h->dct.block[i].luma4x4, 16 ) < 0 )
        {
          return -1;
        }
      }
      else
      {
        h->mb.cache.non_zero_count[p264_scan8[i]]=0;
      }
    }
  }

  //[2] chroma
  if( h->mb.i_cbp_chroma &0x03 )    /* Chroma DC residual present */
  {
    if( p264dec_read_residual_block_cavlc( h, s, BLOCK_INDEX_CHROMA_DC, h->dct.chroma_dc[0], 4 ) < 0 ||
      p264dec_read_residual_block_cavlc( h, s, BLOCK_INDEX_CHROMA_DC, h->dct.chroma_dc[1], 4 ) < 0 )
    {
      return -1;
    }
  }

  if( h->mb.i_cbp_chroma&0x02 ) /* Chroma AC residual present */
  {
    for( i = 0; i < 8; i++ )
    {
      if( p264dec_read_residual_block_cavlc( h, s, 16 + i, h->dct.block[16+i].residual_ac, 15 ) < 0 )
      {
        return -1;
      }
    }
  }
  else
  {
    for( i = 0; i < 8; i++ )
    {
      h->mb.cache.non_zero_count[p264_scan8[16+i]]=0;
    }
  }
  
  return 0;
}

int p264_macroblock_read_cavlc( p264_t *h, bs_t *s ) 
{ 
  int i; 
 
  //[1] skip mb 
  if( h->sh.i_type != SLICE_TYPE_I && h->sh.i_type != SLICE_TYPE_SI && h->i_skip_run==-1) 
  { 
    h->i_skip_run = bs_read_ue( s );//skip mb number 
    if(h->i_skip_run>0) 
    { 
      return 0;//!!! 
    } 
  } 
 
  //[2] mb type 
  if( read_mb_type(h,s) < 0 ) 
  { 
    fprintf(stderr,"read mb type failed!\n"); 
    return -1; 
  } 
 
  //[3] read pred mode, mv, ref (important!) 
  if(I_PCM==h->mb.i_type)//lsptodo 
  { 
    fprintf(stderr,"unsupport i_pcm mb\n"); 
    return -1;     
  } 
  else if(IS_INTRA( h->mb.i_type )) 
  { 
    if(read_intra_mb_pred(h,s)<0) 
    { 
      fprintf(stderr,"read intra mb pred mode failed\n"); 
      return -1;     
    } 
  } 
  else if( h->mb.i_type == P_8x8 || h->mb.i_type == B_8x8) 
  { 
    if(read_inter_sub_mb_pred(h,s)<0) 
    { 
      fprintf(stderr,"read inter sub mb pred mode failed\n"); 
      return -1;     
    } 
  } 
  else if( h->mb.i_type != B_DIRECT ) 
  { 
    if(read_inter_mb_pred(h,s)<0) 
    { 
      fprintf(stderr,"read inter mb pred mode failed\n"); 
      return -1;     
    } 
  } 
 
  //[4] cbp 
  if( h->mb.i_type != I_16x16 )
  {
    int i_cbp;

    i_cbp = bs_read_ue( s );
    if( i_cbp >= 48 )
    {
      fprintf( stderr, "invalid cbp\n" );
      return -1;
    }

    if( h->mb.i_type == I_4x4 )
    {
      i_cbp = golomb_to_intra4x4_cbp[i_cbp];
    }
    else
    {
      i_cbp = golomb_to_inter_cbp[i_cbp];
    }
    h->mb.i_cbp_luma   = i_cbp&0x0f;
    h->mb.i_cbp_chroma = i_cbp >> 4;
    //printf("%d,",i_cbp); //lspdebug
  } 
 
  //[5] residual 
  if( h->mb.i_cbp_luma > 0 || h->mb.i_cbp_chroma > 0 || h->mb.i_type == I_16x16 )
  { //need read residual
    h->mb.i_qp = bs_read_se( s ) + h->pps->i_pic_init_qp + h->sh.i_qp_delta;

    if(read_residual(h,s)<0)
    {
      fprintf(stderr, "read residual data failed\n");
      return -1;
    }
  }
  else //it's an all zero coeff mb
  {
    h->mb.i_qp = h->pps->i_pic_init_qp + h->sh.i_qp_delta;
    for( i = 0; i < 16; i++ )
    {
      h->mb.cache.non_zero_count[p264_scan8[i]]=0;
    }
    for( i = 0; i < 8; i++ )
    {
      h->mb.cache.non_zero_count[p264_scan8[16+i]]=0;
    }
  } 
 
  //fprintf( stderr, "mb read type=%d\n", h->mb.i_type ); 
 
  return 0; 
} 

int p264_macroblock_read_cabac( p264_t *h, bs_t *s ) 
{ 
  return -1; 
} 
 
/****************************************************************************
* UnScan functions
****************************************************************************/
static const int scan_zigzag_x[16]={0, 1, 0, 0, 1, 2, 3, 2, 1, 0, 1, 2, 3, 3, 2, 3};
static const int scan_zigzag_y[16]={0, 0, 1, 2, 1, 0, 0, 1, 2, 3, 3, 2, 1, 2, 3, 3};

static inline void unscan_zigzag_4x4full( int16_t dct[4][4], int level[16] )
{
  int i;

  for( i = 0; i < 16; i++ )
  {
    dct[scan_zigzag_y[i]][scan_zigzag_x[i]] = level[i];
  }
}
static inline void unscan_zigzag_4x4( int16_t dct[4][4], int level[15] )
{
  int i;

  for( i = 1; i < 16; i++ )
  {
    dct[scan_zigzag_y[i]][scan_zigzag_x[i]] = level[i - 1];
  }
}

static inline void unscan_zigzag_2x2_dc( int16_t dct[2][2], int level[4] )
{
  dct[0][0] = level[0];
  dct[0][1] = level[1];
  dct[1][0] = level[2];
  dct[1][1] = level[3];
} 
 
////////////////////////////////////////////////////////////////////////// 
//valid intra mode function 
////////////////////////////////////////////////////////////////////////// 
int valid_intra16x16_mode(p264_t *h, uint8_t *src, int i_stride, int i_mode) 
{ 
  int b_left=h->mb.i_neighbour & MB_LEFT; 
  int b_top=h->mb.i_neighbour & MB_TOP; 
  //int b_top_right=h->mb.i_neighbour & MB_TOPRIGHT; 
  int b_top_left=h->mb.i_neighbour & MB_TOPLEFT; 
 
  //[1] further detail about DC_MODE 
  if(I_PRED_16x16_DC==i_mode) 
  { 
    if(b_top_left) 
    { 
      return I_PRED_16x16_DC; 
    } 
    else if(b_left) 
    { 
      return I_PRED_16x16_DC_LEFT; 
    } 
    else if(b_top) 
    { 
      return I_PRED_16x16_DC_TOP; 
    } 
    else 
    { 
      return I_PRED_16x16_DC_128; 
    } 
  } 
 
  //[2] check  invalid case 
 
  return i_mode; 
 
} 
 
int valid_intra4x4_mode(p264_t *h, uint8_t *src, int i_stride, int i, int i_mode) 
{ 
  int b_left=h->mb.i_neighbour4[i] & MB_LEFT; 
  int b_top=h->mb.i_neighbour4[i] & MB_TOP; 
  int b_top_right=h->mb.i_neighbour4[i] & MB_TOPRIGHT; 
  int b_top_left=h->mb.i_neighbour4[i] & MB_TOPLEFT; 
 
  //[1] further detail about DC_MODE 
  if(I_PRED_4x4_DC==i_mode) 
  { 
    if(b_left && b_top) 
    { 
      return I_PRED_4x4_DC; 
    } 
    else if(b_left) 
    { 
      return I_PRED_4x4_DC_LEFT; 
    } 
    else if(b_top) 
    { 
      return I_PRED_4x4_DC_TOP; 
    } 
    else 
    { 
      return I_PRED_4x4_DC_128; 
    } 
  } 
 
  //[2] constant the invalid neighbour pixel 
  if(!b_left) 
  { 
    src[-1]=src[-1+i_stride]=src[-1+2*i_stride]=src[-1+3*i_stride]=128; 
  } 
  if(!b_top) 
  { 
    src[-i_stride]=src[1 - i_stride]=src[2 - i_stride]=src[3 - i_stride]=128; 
  } 
  if(!b_top_right) 
  { 
    src[4-i_stride]=src[5 - i_stride]=src[6 - i_stride]=src[7 - i_stride]=src[3 - i_stride]; 
  } 
  if(!b_top_left) 
  { 
    src[-1-i_stride]=128; 
  } 
 
  //[3] check the mode whether is valid //lsp?? 
   
  return i_mode; 
 
} 
 
int valid_intra8x8c_mode(p264_t *h, int i_mode) 
{ 
  int b_left=h->mb.i_neighbour & MB_LEFT; 
  int b_top=h->mb.i_neighbour & MB_TOP; 
  //int b_top_right=h->mb.i_neighbour & MB_TOPRIGHT; 
  int b_top_left=h->mb.i_neighbour & MB_TOPLEFT; 
 
  //[1] further detail about DC_MODE 
  if(I_PRED_CHROMA_DC==i_mode) 
  { 
    if(b_top_left) 
    { 
      return I_PRED_CHROMA_DC; 
    } 
    else if(b_left) 
    { 
      return I_PRED_CHROMA_DC_LEFT; 
    } 
    else if(b_top) 
    { 
      return I_PRED_CHROMA_DC_TOP; 
    } 
    else 
    { 
      return I_PRED_CHROMA_DC_128; 
    } 
  } 
 
  //[2] check  invalid case 
 
  return i_mode; 
 
} 
 
int p264_macroblock_decode( p264_t *h ) 
{ 
  const int i_stride = h->mb.pic.i_stride[0]; 
  uint8_t  *p_dst = h->mb.pic.p_fdec[0]; 
  int i_qscale; 
  int ch; 
  int i; 
 
  if( !IS_INTRA(h->mb.i_type ) ) 
  { 
    /* Motion compensation */ 
    p264_mb_mc( h); 
  } 
 
  /* luma */ 
  i_qscale = h->mb.i_qp; 
  if( h->mb.i_type == I_16x16 ) 
  { 
    int16_t dct4x4[16+1][4][4]; 
    int i_mode=h->mb.i_intra16x16_pred_mode; 
 
    i_mode=valid_intra16x16_mode(h,p_dst,i_stride,i_mode); 
     
    /* do the right prediction */ 
    h->predict_16x16[i_mode]( p_dst, i_stride ); 
 
    /* get dc coeffs */ 
    unscan_zigzag_4x4full( dct4x4[0], h->dct.luma16x16_dc ); 
    h->dctf.idct4x4dc( dct4x4[0]); 
    p264_mb_dequant_4x4_dc( dct4x4[0], h->dequant4_mf[CQM_4IY], i_qscale ); 
 
    /* decode the 16x16 macroblock */ 
    for( i = 0; i < 16; i++ ) 
    { 
      unscan_zigzag_4x4( dct4x4[1+i], h->dct.block[i].residual_ac ); 
      h->quantf.dequant_4x4( dct4x4[1+i], h->dequant4_mf[CQM_4IY],  i_qscale ); 
 
      /* copy dc coeff */ 
      dct4x4[1+i][0][0] = dct4x4[0][block_idx_y[i]][block_idx_x[i]]; 
    } 

    /* put pixels to fdec */
    h->dctf.add16x16_idct( p_dst, i_stride, &dct4x4[1] ); 
  } 
  else if( h->mb.i_type == I_4x4 ) 
  { 
    for( i = 0; i < 16; i++ ) 
    { 
      uint8_t *p_dst_by; 
      int     i_mode; 
      //int     b_emu; 
      int16_t dct4x4[4][4]; 
       
      /* Do the right prediction */ 
      p_dst_by = p_dst + 4 * block_idx_x[i] + 4 * block_idx_y[i] * i_stride; 
      //i_mode   = p264_mb_pred_mode4x4_valid( mb, i, h->mb.block[i].i_intra4x4_pred_mode, &b_emu ); 
      i_mode=h->mb.cache.intra4x4_pred_mode[p264_scan8[i]]; 
      i_mode=valid_intra4x4_mode(h,p_dst_by,i_stride,i,i_mode); 
      //if( b_emu ) //lsp?? what's that? 
      //{ 
      //  fprintf( stderr, "mmmh b_emu\n" ); 
      //  memset( &p_dst_by[4], p_dst_by[3], 4 ); 
      //} 
      h->predict_4x4[i_mode]( p_dst_by, i_stride ); 
 
      if(h->mb.cache.non_zero_count[p264_scan8[i]]>0) 
      { 
        /* decode one 4x4 block */ 
        unscan_zigzag_4x4full( dct4x4, h->dct.block[i].luma4x4 ); 
 
        h->quantf.dequant_4x4( dct4x4, h->dequant4_mf[CQM_4IY], i_qscale ); 
 
        /* output samples to fdec */ 
        h->dctf.add4x4_idct( p_dst_by, i_stride, dct4x4 ); 
      } 
    } 
  } 
  else /* Inter mb */ 
  { 
    for( i = 0; i < 16; i++ ) 
    { 
      uint8_t *p_dst_by; 
      int16_t dct4x4[4][4]; 
 
      if( h->mb.cache.non_zero_count[p264_scan8[i]]>0 ) 
      { 
        unscan_zigzag_4x4full( dct4x4, h->dct.block[i].luma4x4 ); 
        h->quantf.dequant_4x4( dct4x4, h->dequant4_mf[CQM_4PY], i_qscale ); 
 
        p_dst_by = p_dst + 4 * block_idx_x[i] + 4 * block_idx_y[i] * i_stride; 
        /* output samples to fdec */ 
        h->dctf.add4x4_idct( p_dst_by, i_stride, dct4x4 ); //lspmust??? 
      } 
    } 
  } 
 
  /* chroma */ 
  i_qscale = i_chroma_qp_table[p264_clip3( i_qscale + h->pps->i_chroma_qp_index_offset, 0, 51 )]; 
  if( IS_INTRA( h->mb.i_type ) ) 
  { 
    int i_mode=valid_intra8x8c_mode(h,h->mb.i_chroma_pred_mode); 
    /* do the right prediction */ 
    h->predict_8x8c[i_mode]( h->mb.pic.p_fdec[1], h->mb.pic.i_stride[1] ); 
    h->predict_8x8c[i_mode]( h->mb.pic.p_fdec[2], h->mb.pic.i_stride[2] ); 
  } 
 
  if( h->mb.i_cbp_chroma != 0 ) 
  { 
    for( ch = 0; ch < 2; ch++ ) 
    { 
      int16_t dct2x2[2][2]; 
      int16_t dct4x4[4][4][4]; 
 
      /* get dc chroma */ 
      unscan_zigzag_2x2_dc( dct2x2, h->dct.chroma_dc[ch] ); 
      h->dctf.idct2x2dc( dct2x2); 
      //p264_mb_dequant_2x2_dc( dct2x2,h->dequant4_mf[CQM_4IC + b_inter], i_qscale ); 
      p264_mb_dequant_2x2_dc( dct2x2,h->dequant4_mf[CQM_4IC], i_qscale ); 
 
      for( i = 0; i < 4; i++ ) 
      { 
        unscan_zigzag_4x4( dct4x4[i], h->dct.block[16+i+ch*4].residual_ac ); 
        //lsp??  
        //h->quantf.dequant_4x4( dct4x4[i], h->dequant4_mf[CQM_4IC + b_inter], i_qscale ); 
        h->quantf.dequant_4x4( dct4x4[i], h->dequant4_mf[CQM_4IC], i_qscale ); 
      } 
 
      /* calculate dct coeffs */
      for( i = 0; i < 4; i++ )
      {
        /* copy dc coeff */
        dct4x4[i][0][0] = dct2x2[block_idx_y[i]][block_idx_x[i]];
      }
      h->dctf.add8x8_idct( h->mb.pic.p_fdec[1+ch],  h->mb.pic.i_stride[1+ch], dct4x4 ); 
    } 
  } 
 
  return 0; 
} 
 
void p264_macroblock_decode_skip( p264_t *h )
{
  int i;
  int x, y;
  int mv[2];

  /* decode it as a 16x16 with no luma/chroma */
  h->mb.i_type = P_L0;
  h->mb.i_partition = D_16x16;
  h->mb.i_cbp_luma = 0;
  h->mb.i_cbp_chroma = 0;
  for( i = 0; i < 16 + 8; i++ )
  {
    h->mb.cache.non_zero_count[p264_scan8[i]] = 0;
  }

  /* set ref0 */
  for( i = 0; i < 16; i++ )
  {
    h->mb.cache.ref[0][p264_scan8[i]] = 0; 
  }

  /* get mv */
  p264_mb_predict_mv_pskip( h, mv );

  //set mv for cache save
  for( y = 0; y < 4; y++ )
  {
    for( x = 0; x < 4; x++ )
    {
      h->mb.cache.mv[0][P264_SCAN8_0+x+8*y][0]=mv[0];
      h->mb.cache.mv[0][P264_SCAN8_0+x+8*y][1]=mv[1];
    }
  }

  /* Motion compensation */
  p264_mb_mc( h );

  h->mb.i_type = P_SKIP; //!!
}