nengel@2: /* nengel@2: * H.26L/H.264/AVC/JVT/14496-10/... direct mb/block decoding nengel@2: * Copyright (c) 2003 Michael Niedermayer nengel@2: * nengel@2: * This file is part of FFmpeg. nengel@2: * nengel@2: * FFmpeg is free software; you can redistribute it and/or nengel@2: * modify it under the terms of the GNU Lesser General Public nengel@2: * License as published by the Free Software Foundation; either nengel@2: * version 2.1 of the License, or (at your option) any later version. nengel@2: * nengel@2: * FFmpeg is distributed in the hope that it will be useful, nengel@2: * but WITHOUT ANY WARRANTY; without even the implied warranty of nengel@2: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU nengel@2: * Lesser General Public License for more details. nengel@2: * nengel@2: * You should have received a copy of the GNU Lesser General Public nengel@2: * License along with FFmpeg; if not, write to the Free Software nengel@2: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA nengel@2: */ nengel@2: nengel@2: /** nengel@2: * @file nengel@2: * H.264 / AVC / MPEG4 part10 direct mb/block decoding. nengel@2: * @author Michael Niedermayer nengel@2: */ nengel@2: nengel@2: #include "dsputil.h" nengel@2: #include "avcodec.h" nengel@2: #include "h264_data.h" nengel@2: #include "h264.h" nengel@2: #include "rectangle.h" nengel@2: nengel@2: //#undef NDEBUG nengel@2: #include nengel@2: nengel@2: static const uint8_t left_block_options[4][16]={ nengel@2: {0,1,2,3,7,10,8,11,7+0*8, 7+1*8, 7+2*8, 7+3*8, 2+0*8, 2+3*8, 2+1*8, 2+2*8}, nengel@2: {2,2,3,3,8,11,8,11,7+2*8, 7+2*8, 7+3*8, 7+3*8, 2+1*8, 2+2*8, 2+1*8, 2+2*8}, nengel@2: {0,0,1,1,7,10,7,10,7+0*8, 7+0*8, 7+1*8, 7+1*8, 2+0*8, 2+3*8, 2+0*8, 2+3*8}, nengel@2: {0,2,0,2,7,10,7,10,7+0*8, 7+2*8, 7+0*8, 7+2*8, 2+0*8, 2+3*8, 2+0*8, 2+3*8} nengel@2: }; nengel@2: nengel@2: nengel@2: // static void check_cache_copy(MBRecContext *mrc, H264Slice *s, H264Mb *m){ nengel@2: // for (int list=0; list<2; list++){ nengel@2: // for (int i=0; i<40; i++){ nengel@2: // assert (m->ref_cache[list][i] == m->ref_cache_copy[list][i]); nengel@2: // assert (mrs->mv_cache[list][i][0] == mrs->mv_cache_copy[list][i][0]); nengel@2: // assert (mrs->mv_cache[list][i][1] == mrs->mv_cache_copy[list][i][1]); nengel@2: // } nengel@2: // } nengel@2: // } nengel@2: nengel@2: // static void check_cache_copy2(MBRecContext *mrc, H264Slice *s, H264Mb *m){ nengel@2: // for (int list=0; list<2; list++){ nengel@2: // for (int i=0; i<40; i++){ nengel@2: // assert (m->ref_cache[list][i] == m->ref_cache_copy2[list][i]); nengel@2: // assert (mrs->mv_cache[list][i][0] == mrs->mv_cache_copy2[list][i][0]); nengel@2: // assert (mrs->mv_cache[list][i][1] == mrs->mv_cache_copy2[list][i][1]); nengel@2: // } nengel@2: // } nengel@2: // } nengel@2: nengel@2: static void fill_decode_caches_rec(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, H264Mb *m, int mb_type){ nengel@2: int topleft_type, top_type, topright_type, left_type; nengel@2: const uint8_t * left_block= left_block_options[0]; nengel@2: const int mb_x = m->mb_x; nengel@2: int i; nengel@2: nengel@2: mrs->top_type = mrs->mb_type_top[mb_x ]; nengel@2: mrs->left_type = mrs->mb_type [mb_x-1]; nengel@2: nengel@2: topleft_type = mrs->mb_type_top[mb_x-1]; nengel@2: top_type = mrs->mb_type_top[mb_x ]; nengel@2: topright_type= mrs->mb_type_top[mb_x+1]; nengel@2: left_type = mrs->mb_type [mb_x-1]; nengel@2: nengel@2: int type_mask= s->pps.constrained_intra_pred ? 1 : -1; nengel@2: nengel@2: if(!IS_SKIP(mb_type)){ nengel@2: // memset(mrc->non_zero_count_cache, 0, sizeof(mrc->non_zero_count_cache)); nengel@2: AV_COPY32(&mrs->non_zero_count_cache[4+8*1], &m->non_zero_count[ 0]); nengel@2: AV_COPY32(&mrs->non_zero_count_cache[4+8*2], &m->non_zero_count[ 4]); nengel@2: AV_COPY32(&mrs->non_zero_count_cache[4+8*3], &m->non_zero_count[ 8]); nengel@2: AV_COPY32(&mrs->non_zero_count_cache[4+8*4], &m->non_zero_count[12]); nengel@2: nengel@2: for (int i=0; i<2; i++) { nengel@2: mrs->non_zero_count_cache[8*1 + 8*i + 1] = m->non_zero_count[16 + i*2 ]; nengel@2: mrs->non_zero_count_cache[8*1 + 8*i + 2] = m->non_zero_count[16 + i*2 +1]; nengel@2: mrs->non_zero_count_cache[8*4 + 8*i + 1] = m->non_zero_count[20 + i*2 ]; nengel@2: mrs->non_zero_count_cache[8*4 + 8*i + 2] = m->non_zero_count[20 + i*2 +1]; nengel@2: } nengel@2: nengel@2: if(IS_INTRA(mb_type)){ nengel@2: // memset(mrc->intra4x4_pred_mode_cache, 0, sizeof(mrc->intra4x4_pred_mode_cache)); nengel@2: nengel@2: mrs->topleft_samples_available= nengel@2: mrs->top_samples_available= nengel@2: mrs->left_samples_available= 0xFFFF; nengel@2: mrs->topright_samples_available= 0xEEEA; nengel@2: nengel@2: if(!(top_type & type_mask)){ nengel@2: mrs->topleft_samples_available= 0xB3FF; nengel@2: mrs->top_samples_available= 0x33FF; nengel@2: mrs->topright_samples_available= 0x26EA; nengel@2: } nengel@2: nengel@2: if(!(left_type & type_mask)){ nengel@2: mrs->topleft_samples_available&= 0xDF5F; nengel@2: mrs->left_samples_available&= 0x5F5F; nengel@2: } nengel@2: nengel@2: if(!(topleft_type & type_mask)) nengel@2: mrs->topleft_samples_available&= 0x7FFF; nengel@2: nengel@2: if(!(topright_type & type_mask)) nengel@2: mrs->topright_samples_available&= 0xFBFF; nengel@2: nengel@2: if(IS_INTRA4x4(mb_type)){ nengel@2: if(IS_INTRA4x4(top_type)){ nengel@2: AV_COPY32(mrs->intra4x4_pred_mode_cache+4+8*0, &mrs->intra4x4_pred_mode_top[4*mb_x]); nengel@2: }else{ nengel@2: mrs->intra4x4_pred_mode_cache[4+8*0]= nengel@2: mrs->intra4x4_pred_mode_cache[5+8*0]= nengel@2: mrs->intra4x4_pred_mode_cache[6+8*0]= nengel@2: mrs->intra4x4_pred_mode_cache[7+8*0]= 2 - 3*!(top_type & type_mask); nengel@2: } nengel@2: nengel@2: if(IS_INTRA4x4(left_type)){ nengel@2: #if OMPSS nengel@2: mrs->intra4x4_pred_mode_cache[3+8*1]= m->intra4x4_pred_mode_left[0]; nengel@2: mrs->intra4x4_pred_mode_cache[3+8*2]= m->intra4x4_pred_mode_left[1]; nengel@2: mrs->intra4x4_pred_mode_cache[3+8*3]= m->intra4x4_pred_mode_left[2]; nengel@2: mrs->intra4x4_pred_mode_cache[3+8*4]= m->intra4x4_pred_mode_left[3]; nengel@2: #else nengel@2: mrs->intra4x4_pred_mode_cache[3+8*1]= mrs->intra4x4_pred_mode_left[0]; nengel@2: mrs->intra4x4_pred_mode_cache[3+8*2]= mrs->intra4x4_pred_mode_left[1]; nengel@2: mrs->intra4x4_pred_mode_cache[3+8*3]= mrs->intra4x4_pred_mode_left[2]; nengel@2: mrs->intra4x4_pred_mode_cache[3+8*4]= mrs->intra4x4_pred_mode_left[3]; nengel@2: #endif nengel@2: }else{ nengel@2: mrs->intra4x4_pred_mode_cache[3+8*1]= nengel@2: mrs->intra4x4_pred_mode_cache[3+8*2]= nengel@2: mrs->intra4x4_pred_mode_cache[3+8*3]= nengel@2: mrs->intra4x4_pred_mode_cache[3+8*4]= 2 - 3*!(left_type & type_mask); nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: if(IS_INTER(mb_type) ||(IS_DIRECT(mb_type) && s->direct_spatial_mv_pred)){ nengel@2: int list; nengel@2: nengel@2: // memset(mrs->mv_cache, 0, sizeof(mrs->mv_cache)); nengel@2: // memset(mrs->ref_cache, 0, sizeof(mrs->ref_cache)); nengel@2: nengel@2: mrs->ref_cache[0][scan8[5 ]+1] = mrs->ref_cache[0][scan8[7 ]+1] = mrs->ref_cache[0][scan8[13]+1] = nengel@2: mrs->ref_cache[1][scan8[5 ]+1] = mrs->ref_cache[1][scan8[7 ]+1] = mrs->ref_cache[1][scan8[13]+1] = PART_NOT_AVAILABLE; nengel@2: nengel@2: for(list=0; listlist_count; list++){ nengel@2: if(!USES_LIST(mb_type, list)){ nengel@2: continue; nengel@2: } nengel@2: assert(!(IS_DIRECT(mb_type) && !s->direct_spatial_mv_pred)); nengel@2: nengel@2: if(USES_LIST(top_type, list)){ nengel@2: const int b_xy= 4*mb_x + 3*mrc->b_stride; nengel@2: AV_COPY128(mrs->mv_cache[list][scan8[0] + 0 - 1*8], mrs->motion_val_top[list][b_xy + 0]); nengel@2: mrs->ref_cache[list][scan8[0] + 0 - 1*8]= nengel@2: mrs->ref_cache[list][scan8[0] + 1 - 1*8]= mrs->ref_index_top[list][4*mb_x + 2]; nengel@2: mrs->ref_cache[list][scan8[0] + 2 - 1*8]= nengel@2: mrs->ref_cache[list][scan8[0] + 3 - 1*8]= mrs->ref_index_top[list][4*mb_x + 3]; nengel@2: }else{ nengel@2: AV_ZERO128(mrs->mv_cache[list][scan8[0] + 0 - 1*8]); nengel@2: AV_WN32A(&mrs->ref_cache[list][scan8[0] + 0 - 1*8], ((top_type ? LIST_NOT_USED : PART_NOT_AVAILABLE)&0xFF)*0x01010101); nengel@2: } nengel@2: nengel@2: if(mb_type & (MB_TYPE_16x8|MB_TYPE_8x8)){ nengel@2: for(i=0; i<2; i++){ nengel@2: int cache_idx = scan8[0] - 1 + i*2*8; nengel@2: if(USES_LIST(left_type, list)){ nengel@2: const int b_xy= 4*(mb_x-1) + 3; nengel@2: const int b8_x= 4*(mb_x-1) + 1; nengel@2: AV_COPY32(mrs->mv_cache[list][cache_idx ], mrs->motion_val[list][b_xy + mrc->b_stride*left_block[0+i*2]]); nengel@2: AV_COPY32(mrs->mv_cache[list][cache_idx+8], mrs->motion_val[list][b_xy + mrc->b_stride*left_block[1+i*2]]); nengel@2: mrs->ref_cache[list][cache_idx ]= mrs->ref_index[list][b8_x + (left_block[0+i*2]&~1)]; nengel@2: mrs->ref_cache[list][cache_idx+8]= mrs->ref_index[list][b8_x + (left_block[1+i*2]&~1)]; nengel@2: }else{ nengel@2: AV_ZERO32(mrs->mv_cache [list][cache_idx ]); nengel@2: AV_ZERO32(mrs->mv_cache [list][cache_idx+8]); nengel@2: mrs->ref_cache[list][cache_idx ]= nengel@2: mrs->ref_cache[list][cache_idx+8]= (left_type ? LIST_NOT_USED : PART_NOT_AVAILABLE); nengel@2: } nengel@2: } nengel@2: }else{ nengel@2: if(USES_LIST(left_type, list)){ nengel@2: const int b_x = 4*(mb_x-1) + 3; nengel@2: const int b8_x= 4*(mb_x-1) + 1; nengel@2: AV_COPY32(mrs->mv_cache[list][scan8[0] - 1], mrs->motion_val[list][b_x + mrc->b_stride*left_block[0]]); nengel@2: mrs->ref_cache[list][scan8[0] - 1]= mrs->ref_index[list][b8_x + (left_block[0]&~1)]; nengel@2: }else{ nengel@2: AV_ZERO32(mrs->mv_cache [list][scan8[0] - 1]); nengel@2: mrs->ref_cache[list][scan8[0] - 1]= left_type ? LIST_NOT_USED : PART_NOT_AVAILABLE; nengel@2: } nengel@2: } nengel@2: nengel@2: if(USES_LIST(topright_type, list)){ nengel@2: const int b_xy= 4*(mb_x+1) + 3*mrc->b_stride; nengel@2: AV_COPY32(mrs->mv_cache[list][scan8[0] + 4 - 1*8], mrs->motion_val_top[list][b_xy]); nengel@2: mrs->ref_cache[list][scan8[0] + 4 - 1*8]= mrs->ref_index_top[list][4*(mb_x+1) + 2]; nengel@2: }else{ nengel@2: AV_ZERO32(mrs->mv_cache [list][scan8[0] + 4 - 1*8]); nengel@2: mrs->ref_cache[list][scan8[0] + 4 - 1*8]= topright_type ? LIST_NOT_USED : PART_NOT_AVAILABLE; nengel@2: } nengel@2: if(mrs->ref_cache[list][scan8[0] + 4 - 1*8] < 0){ nengel@2: int topleft_partition= -1; nengel@2: if(USES_LIST(topleft_type, list)){ nengel@2: const int b_xy = 4*(mb_x-1) + 3 + mrc->b_stride + (topleft_partition & 2*mrc->b_stride); nengel@2: const int b8_x= 4*(mb_x-1) + 1 + (topleft_partition & 2); nengel@2: AV_COPY32(mrs->mv_cache[list][scan8[0] - 1 - 1*8], mrs->motion_val_top[list][b_xy]); nengel@2: mrs->ref_cache[list][scan8[0] - 1 - 1*8]= mrs->ref_index_top[list][b8_x]; nengel@2: }else{ nengel@2: AV_ZERO32(mrs->mv_cache[list][scan8[0] - 1 - 1*8]); nengel@2: mrs->ref_cache[list][scan8[0] - 1 - 1*8]= topleft_type ? LIST_NOT_USED : PART_NOT_AVAILABLE; nengel@2: } nengel@2: } nengel@2: nengel@2: if((mb_type&(MB_TYPE_SKIP|MB_TYPE_DIRECT2))) nengel@2: continue; nengel@2: nengel@2: if(!(mb_type&(MB_TYPE_SKIP|MB_TYPE_DIRECT2))) { nengel@2: mrs->ref_cache[list][scan8[4 ]] = nengel@2: mrs->ref_cache[list][scan8[12]] = PART_NOT_AVAILABLE; nengel@2: AV_ZERO32(mrs->mv_cache [list][scan8[4 ]]); nengel@2: AV_ZERO32(mrs->mv_cache [list][scan8[12]]); nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: static inline void write_back_motion_rec(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, H264Mb *m, int mb_type){ nengel@2: const int b_stride = mrc->b_stride; nengel@2: const int b_x = 4*m->mb_x; //try mb2b(8)_xy nengel@2: const int b8_x= 4*m->mb_x; nengel@2: int list; nengel@2: nengel@2: if(!USES_LIST(mb_type, 0)) nengel@2: fill_rectangle(&mrs->ref_index[0][b8_x], 2, 2, 2, (uint8_t)LIST_NOT_USED, 1); nengel@2: nengel@2: for(list=0; listlist_count; list++){ nengel@2: int y; nengel@2: int16_t (*mv_dst)[2]; nengel@2: int16_t (*mv_src)[2]; nengel@2: nengel@2: if(!USES_LIST(mb_type, list)) nengel@2: continue; nengel@2: nengel@2: mv_dst = &mrs->motion_val[list][b_x]; nengel@2: mv_src = &mrs->mv_cache[list][scan8[0]]; nengel@2: for(y=0; y<4; y++){ nengel@2: AV_COPY128(mv_dst + y*b_stride, mv_src + 8*y); nengel@2: } nengel@2: nengel@2: { nengel@2: int8_t *ref_index = &mrs->ref_index[list][b8_x]; nengel@2: ref_index[0+0*2]= mrs->ref_cache[list][scan8[0]]; nengel@2: ref_index[1+0*2]= mrs->ref_cache[list][scan8[4]]; nengel@2: ref_index[0+1*2]= mrs->ref_cache[list][scan8[8]]; nengel@2: ref_index[1+1*2]= mrs->ref_cache[list][scan8[12]]; nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: nengel@2: /** nengel@2: * checks if the top & left blocks are available if needed & changes the dc mode so it only uses the available blocks. nengel@2: */ nengel@2: static int check_intra4x4_pred_mode(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, H264Mb *m){ nengel@2: static const int8_t top [12]= {-1, 0,LEFT_DC_PRED,-1,-1,-1,-1,-1, 0}; nengel@2: static const int8_t left[12]= { 0,-1, TOP_DC_PRED, 0,-1,-1,-1, 0,-1,DC_128_PRED}; nengel@2: int i; nengel@2: nengel@2: if(!(mrs->top_samples_available&0x8000)){ nengel@2: for(i=0; i<4; i++){ nengel@2: int status= top[ mrs->intra4x4_pred_mode_cache[scan8[0] + i] ]; nengel@2: if(status<0){ nengel@2: av_log(AV_LOG_ERROR, "top block unavailable for requested intra4x4 mode %d at %d %d\n", status, m->mb_x, m->mb_y); nengel@2: return -1; nengel@2: } else if(status){ nengel@2: mrs->intra4x4_pred_mode_cache[scan8[0] + i]= status; nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: if((mrs->left_samples_available&0x8888)!=0x8888){ nengel@2: static const int mask[4]={0x8000,0x2000,0x80,0x20}; nengel@2: for(i=0; i<4; i++){ nengel@2: if(!(mrs->left_samples_available&mask[i])){ nengel@2: int status= left[ mrs->intra4x4_pred_mode_cache[scan8[0] + 8*i] ]; nengel@2: if(status<0){ nengel@2: av_log(AV_LOG_ERROR, "left block unavailable for requested intra4x4 mode %d at %d %d\n", status, m->mb_x, m->mb_y); nengel@2: return -1; nengel@2: } else if(status){ nengel@2: mrs->intra4x4_pred_mode_cache[scan8[0] + 8*i]= status; nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: return 0; nengel@2: } nengel@2: nengel@2: /** nengel@2: * checks if the top & left blocks are available if needed & changes the dc mode so it only uses the available blocks. nengel@2: */ nengel@2: static int check_intra_pred_mode(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, H264Mb *m, int mode){ nengel@2: static const int8_t top [7]= {LEFT_DC_PRED8x8, 1,-1,-1}; nengel@2: static const int8_t left[7]= { TOP_DC_PRED8x8,-1, 2,-1,DC_128_PRED8x8}; nengel@2: nengel@2: if(mode > 6) { nengel@2: av_log(AV_LOG_ERROR, "out of range intra chroma pred mode at %d %d\n", m->mb_x, m->mb_y); nengel@2: return -1; nengel@2: } nengel@2: nengel@2: if(!(mrs->top_samples_available&0x8000)){ nengel@2: mode= top[ mode ]; nengel@2: if(mode<0){ nengel@2: av_log(AV_LOG_ERROR, "top block unavailable for requested intra mode at %d %d\n", m->mb_x, m->mb_y); nengel@2: return -1; nengel@2: } nengel@2: } nengel@2: nengel@2: if((mrs->left_samples_available&0x8080) != 0x8080){ nengel@2: mode= left[ mode ]; nengel@2: if(mrs->left_samples_available&0x8080){ //mad cow disease mode, aka MBAFF + constrained_intra_pred nengel@2: mode= ALZHEIMER_DC_L0T_PRED8x8 + (!(mrs->left_samples_available&0x8000)) + 2*(mode == DC_128_PRED8x8); nengel@2: } nengel@2: if(mode<0){ nengel@2: av_log(AV_LOG_ERROR, "left block unavailable for requested intra mode at %d %d\n", m->mb_x, m->mb_y); nengel@2: return -1; nengel@2: } nengel@2: } nengel@2: return mode; nengel@2: } nengel@2: nengel@2: /** nengel@2: * gets the predicted intra4x4 prediction mode. nengel@2: */ nengel@2: static inline int pred_intra_mode(MBRecContext *mrc, MBRecState *mrs, int n){ nengel@2: const int index8= scan8[n]; nengel@2: const int left= mrs->intra4x4_pred_mode_cache[index8 - 1]; nengel@2: const int top = mrs->intra4x4_pred_mode_cache[index8 - 8]; nengel@2: const int min= FFMIN(left, top); nengel@2: nengel@2: if(min<0) return DC_PRED; nengel@2: else return min; nengel@2: } nengel@2: nengel@2: static void write_back_intra_pred_mode_rec(MBRecContext *mrc, MBRecState *mrs, H264Mb *m, int mb_x){ nengel@2: int8_t *mode= &mrs->intra4x4_pred_mode[4*mb_x]; nengel@2: nengel@2: AV_COPY32(mode, mrs->intra4x4_pred_mode_cache + 4 + 8*4); nengel@2: #if OMPSS nengel@2: if (m->mb_x < mrc->mb_width-1){ nengel@2: H264Mb *mr= m+1; nengel@2: mode = mr->intra4x4_pred_mode_left; nengel@2: mode[0]= mrs->intra4x4_pred_mode_cache[7+8*1]; nengel@2: mode[1]= mrs->intra4x4_pred_mode_cache[7+8*2]; nengel@2: mode[2]= mrs->intra4x4_pred_mode_cache[7+8*3]; nengel@2: mode[3]= mrs->intra4x4_pred_mode_cache[7+8*4]; nengel@2: } nengel@2: #else nengel@2: mode = mrs->intra4x4_pred_mode_left; nengel@2: mode[0]= mrs->intra4x4_pred_mode_cache[7+8*1]; nengel@2: mode[1]= mrs->intra4x4_pred_mode_cache[7+8*2]; nengel@2: mode[2]= mrs->intra4x4_pred_mode_cache[7+8*3]; nengel@2: mode[3]= mrs->intra4x4_pred_mode_cache[7+8*4]; nengel@2: #endif nengel@2: } nengel@2: nengel@2: static void pred_spatial_direct_motion_rec(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, H264Mb *m, int *mb_type){ nengel@2: int b4_stride = mrc->b_stride; nengel@2: const int mb_x = m->mb_x; nengel@2: int mb_type_col[2]; nengel@2: const int16_t (*l1mv0)[2], (*l1mv1)[2]; nengel@2: const int8_t *l1ref0, *l1ref1; nengel@2: const int is_b8x8 = IS_8X8(*mb_type); nengel@2: unsigned int sub_mb_type= MB_TYPE_L0L1; nengel@2: int i8, i4; nengel@2: int ref[2]; nengel@2: int mv[2]; nengel@2: int list; nengel@2: nengel@2: //assert(h->ref_list[1][0].reference&3); nengel@2: nengel@2: #define MB_TYPE_16x16_OR_INTRA (MB_TYPE_16x16|MB_TYPE_INTRA4x4|MB_TYPE_INTRA16x16|MB_TYPE_INTRA_PCM) nengel@2: nengel@2: /* ref = min(neighbors) */ nengel@2: for(list=0; list<2; list++){ nengel@2: int left_ref = mrs->ref_cache[list][scan8[0] - 1]; nengel@2: int top_ref = mrs->ref_cache[list][scan8[0] - 8]; nengel@2: int refc = mrs->ref_cache[list][scan8[0] - 8 + 4]; nengel@2: const int16_t *C= mrs->mv_cache[list][ scan8[0] - 8 + 4]; nengel@2: if(refc == PART_NOT_AVAILABLE){ nengel@2: refc = mrs->ref_cache[list][scan8[0] - 8 - 1]; nengel@2: C = mrs->mv_cache[list][scan8[0] - 8 - 1]; nengel@2: } nengel@2: ref[list] = FFMIN3((unsigned)left_ref, (unsigned)top_ref, (unsigned)refc); nengel@2: if(ref[list] >= 0){ nengel@2: //this is just pred_motion() but with the cases removed that cannot happen for direct blocks nengel@2: const int16_t * const A= mrs->mv_cache[list][ scan8[0] - 1 ]; nengel@2: const int16_t * const B= mrs->mv_cache[list][ scan8[0] - 8 ]; nengel@2: nengel@2: int match_count= (left_ref==ref[list]) + (top_ref==ref[list]) + (refc==ref[list]); nengel@2: if(match_count > 1){ //most common nengel@2: mv[list]= pack16to32(mid_pred(A[0], B[0], C[0]), nengel@2: mid_pred(A[1], B[1], C[1]) ); nengel@2: }else { nengel@2: assert(match_count==1); nengel@2: if(left_ref==ref[list]){ nengel@2: mv[list]= AV_RN32A(A); nengel@2: }else if(top_ref==ref[list]){ nengel@2: mv[list]= AV_RN32A(B); nengel@2: }else{ nengel@2: mv[list]= AV_RN32A(C); nengel@2: } nengel@2: } nengel@2: }else{ nengel@2: int mask= ~(MB_TYPE_L0 << (2*list)); nengel@2: mv[list] = 0; nengel@2: ref[list] = -1; nengel@2: if(!is_b8x8) nengel@2: *mb_type &= mask; nengel@2: sub_mb_type &= mask; nengel@2: } nengel@2: } nengel@2: nengel@2: if(ref[0] < 0 && ref[1] < 0){ nengel@2: ref[0] = ref[1] = 0; nengel@2: if(!is_b8x8) nengel@2: *mb_type |= MB_TYPE_L0L1; nengel@2: sub_mb_type |= MB_TYPE_L0L1; nengel@2: } nengel@2: nengel@2: if(!(is_b8x8|mv[0]|mv[1])){ nengel@2: fill_rectangle(&mrs->ref_cache[0][scan8[0]], 4, 4, 8, (uint8_t)ref[0], 1); nengel@2: fill_rectangle(&mrs->ref_cache[1][scan8[0]], 4, 4, 8, (uint8_t)ref[1], 1); nengel@2: fill_rectangle(&mrs->mv_cache[0][scan8[0]], 4, 4, 8, 0, 4); nengel@2: fill_rectangle(&mrs->mv_cache[1][scan8[0]], 4, 4, 8, 0, 4); nengel@2: *mb_type= (*mb_type & ~(MB_TYPE_8x8|MB_TYPE_16x8|MB_TYPE_8x16|MB_TYPE_P1L0|MB_TYPE_P1L1))|MB_TYPE_16x16|MB_TYPE_DIRECT2; nengel@2: return; nengel@2: } nengel@2: nengel@2: mb_type_col[0] = nengel@2: mb_type_col[1] = mrs->list1_mb_type[mb_x]; nengel@2: nengel@2: sub_mb_type |= MB_TYPE_16x16|MB_TYPE_DIRECT2; /* B_SUB_8x8 */ nengel@2: if(!is_b8x8 && (mb_type_col[0] & MB_TYPE_16x16_OR_INTRA)){ nengel@2: *mb_type |= MB_TYPE_16x16|MB_TYPE_DIRECT2; /* B_16x16 */ nengel@2: }else if(!is_b8x8 && (mb_type_col[0] & (MB_TYPE_16x8|MB_TYPE_8x16))){ nengel@2: *mb_type |= MB_TYPE_DIRECT2 | (mb_type_col[0] & (MB_TYPE_16x8|MB_TYPE_8x16)); nengel@2: }else{ nengel@2: if(!s->direct_8x8_inference_flag){ nengel@2: /* FIXME save sub mb types from previous frames (or derive from MVs) nengel@2: * so we know exactly what block size to use */ nengel@2: sub_mb_type += (MB_TYPE_8x8-MB_TYPE_16x16); /* B_SUB_4x4 */ nengel@2: } nengel@2: *mb_type |= MB_TYPE_8x8; nengel@2: } nengel@2: nengel@2: l1mv0 = (void *) &mrs->list1_motion_val[0][4*mb_x]; nengel@2: l1mv1 = (void *) &mrs->list1_motion_val[1][4*mb_x]; nengel@2: l1ref0 = &mrs->list1_ref_index [0][4*mb_x]; nengel@2: l1ref1 = &mrs->list1_ref_index [1][4*mb_x]; nengel@2: // if(!b8_stride){ nengel@2: // if(m->mb_y&1){ nengel@2: // l1ref0 += 2; nengel@2: // l1ref1 += 2; nengel@2: // l1mv0 += 2*b4_stride; nengel@2: // l1mv1 += 2*b4_stride; nengel@2: // } nengel@2: // } nengel@2: nengel@2: if(IS_16X16(*mb_type)){ nengel@2: int a,b; nengel@2: nengel@2: fill_rectangle(&mrs->ref_cache[0][scan8[0]], 4, 4, 8, (uint8_t)ref[0], 1); nengel@2: fill_rectangle(&mrs->ref_cache[1][scan8[0]], 4, 4, 8, (uint8_t)ref[1], 1); nengel@2: if(!IS_INTRA(mb_type_col[0]) && ( (l1ref0[0] == 0 && FFABS(l1mv0[0][0]) <= 1 && FFABS(l1mv0[0][1]) <= 1) nengel@2: || (l1ref0[0] < 0 && l1ref1[0] == 0 && FFABS(l1mv1[0][0]) <= 1 && FFABS(l1mv1[0][1]) <= 1 nengel@2: ))){ nengel@2: a=b=0; nengel@2: if(ref[0] > 0) nengel@2: a= mv[0]; nengel@2: if(ref[1] > 0) nengel@2: b= mv[1]; nengel@2: }else{ nengel@2: a= mv[0]; nengel@2: b= mv[1]; nengel@2: } nengel@2: fill_rectangle(&mrs->mv_cache[0][scan8[0]], 4, 4, 8, a, 4); nengel@2: fill_rectangle(&mrs->mv_cache[1][scan8[0]], 4, 4, 8, b, 4); nengel@2: }else{ nengel@2: int n=0; nengel@2: for(i8=0; i8<4; i8++){ nengel@2: const int x8 = i8&1; nengel@2: const int y8 = i8>>1; nengel@2: nengel@2: if(is_b8x8 && !IS_DIRECT(m->sub_mb_type[i8])) nengel@2: continue; nengel@2: m->sub_mb_type[i8] = sub_mb_type; nengel@2: nengel@2: fill_rectangle(&mrs->mv_cache[0][scan8[i8*4]], 2, 2, 8, mv[0], 4); nengel@2: fill_rectangle(&mrs->mv_cache[1][scan8[i8*4]], 2, 2, 8, mv[1], 4); nengel@2: fill_rectangle(&mrs->ref_cache[0][scan8[i8*4]], 2, 2, 8, (uint8_t)ref[0], 1); nengel@2: fill_rectangle(&mrs->ref_cache[1][scan8[i8*4]], 2, 2, 8, (uint8_t)ref[1], 1); nengel@2: nengel@2: /* col_zero_flag */ nengel@2: if(!IS_INTRA(mb_type_col[0]) && (l1ref0[i8] == 0 || (l1ref0[i8] < 0 && l1ref1[i8] == 0 )) nengel@2: ){ nengel@2: const int16_t (*l1mv)[2]= l1ref0[i8] == 0 ? l1mv0 : l1mv1; nengel@2: if(IS_SUB_8X8(sub_mb_type)){ nengel@2: const int16_t *mv_col = l1mv[x8*3 + y8*3*b4_stride]; nengel@2: if(FFABS(mv_col[0]) <= 1 && FFABS(mv_col[1]) <= 1){ nengel@2: if(ref[0] == 0) nengel@2: fill_rectangle(&mrs->mv_cache[0][scan8[i8*4]], 2, 2, 8, 0, 4); nengel@2: if(ref[1] == 0) nengel@2: fill_rectangle(&mrs->mv_cache[1][scan8[i8*4]], 2, 2, 8, 0, 4); nengel@2: n+=4; nengel@2: } nengel@2: }else{ nengel@2: int k=0; nengel@2: for(i4=0; i4<4; i4++){ nengel@2: const int16_t *mv_col = l1mv[x8*2 + (i4&1) + (y8*2 + (i4>>1))*b4_stride]; nengel@2: if(FFABS(mv_col[0]) <= 1 && FFABS(mv_col[1]) <= 1){ nengel@2: if(ref[0] == 0) nengel@2: AV_ZERO32(mrs->mv_cache[0][scan8[i8*4+i4]]); nengel@2: if(ref[1] == 0) nengel@2: AV_ZERO32(mrs->mv_cache[1][scan8[i8*4+i4]]); nengel@2: k++; nengel@2: } nengel@2: } nengel@2: if(!(k&3)) nengel@2: m->sub_mb_type[i8]+= MB_TYPE_16x16 - MB_TYPE_8x8; nengel@2: n+=k; nengel@2: } nengel@2: } nengel@2: } nengel@2: if(!is_b8x8 && !(n&15)){ nengel@2: *mb_type= (*mb_type & ~(MB_TYPE_8x8|MB_TYPE_16x8|MB_TYPE_8x16|MB_TYPE_P1L0|MB_TYPE_P1L1))|MB_TYPE_16x16|MB_TYPE_DIRECT2; nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: static void pred_temp_direct_motion_rec(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, H264Mb *m, int *mb_type){ nengel@2: const int mb_x = m->mb_x; nengel@2: int b4_stride = mrc->b_stride; nengel@2: int mb_type_col[2]; nengel@2: const int16_t (*l1mv0)[2], (*l1mv1)[2]; nengel@2: const int8_t *l1ref0, *l1ref1; nengel@2: const int is_b8x8 = IS_8X8(*mb_type); nengel@2: unsigned int sub_mb_type; nengel@2: int i8, i4; nengel@2: const int *map_col_to_list0[2] = {s->map_col_to_list0[0], s->map_col_to_list0[1]}; nengel@2: const int *dist_scale_factor = s->dist_scale_factor; nengel@2: nengel@2: mb_type_col[0] = nengel@2: mb_type_col[1] = mrs->list1_mb_type[mb_x]; nengel@2: nengel@2: sub_mb_type = MB_TYPE_16x16|MB_TYPE_P0L0|MB_TYPE_P0L1|MB_TYPE_DIRECT2; /* B_SUB_8x8 */ nengel@2: if(!is_b8x8 && (mb_type_col[0] & MB_TYPE_16x16_OR_INTRA)){ nengel@2: *mb_type |= MB_TYPE_16x16|MB_TYPE_P0L0|MB_TYPE_P0L1|MB_TYPE_DIRECT2; /* B_16x16 */ nengel@2: }else if(!is_b8x8 && (mb_type_col[0] & (MB_TYPE_16x8|MB_TYPE_8x16))){ nengel@2: *mb_type |= MB_TYPE_L0L1|MB_TYPE_DIRECT2 | (mb_type_col[0] & (MB_TYPE_16x8|MB_TYPE_8x16)); nengel@2: }else{ nengel@2: if(!s->direct_8x8_inference_flag){ nengel@2: /* FIXME save sub mb types from previous frames (or derive from MVs) nengel@2: * so we know exactly what block size to use */ nengel@2: sub_mb_type = MB_TYPE_8x8|MB_TYPE_P0L0|MB_TYPE_P0L1|MB_TYPE_DIRECT2; /* B_SUB_4x4 */ nengel@2: } nengel@2: *mb_type |= MB_TYPE_8x8|MB_TYPE_L0L1; nengel@2: } nengel@2: nengel@2: l1mv0 = (void *) &mrs->list1_motion_val[0][4*mb_x]; nengel@2: l1mv1 = (void *) &mrs->list1_motion_val[1][4*mb_x]; nengel@2: l1ref0 = &mrs->list1_ref_index [0][4*mb_x]; nengel@2: l1ref1 = &mrs->list1_ref_index [1][4*mb_x]; nengel@2: nengel@2: /* one-to-one mv scaling */ nengel@2: if(IS_16X16(*mb_type)){ nengel@2: int ref, mv0, mv1; nengel@2: nengel@2: fill_rectangle(&mrs->ref_cache[1][scan8[0]], 4, 4, 8, 0, 1); nengel@2: if(IS_INTRA(mb_type_col[0])){ nengel@2: ref=mv0=mv1=0; nengel@2: }else{ nengel@2: const int ref0 = l1ref0[0] >= 0 ? map_col_to_list0[0][l1ref0[0]] nengel@2: : map_col_to_list0[1][l1ref1[0]]; nengel@2: const int scale = dist_scale_factor[ref0]; nengel@2: const int16_t *mv_col = l1ref0[0] >= 0 ? l1mv0[0] : l1mv1[0]; nengel@2: int mv_l0[2]; nengel@2: mv_l0[0] = (scale * mv_col[0] + 128) >> 8; nengel@2: mv_l0[1] = (scale * mv_col[1] + 128) >> 8; nengel@2: ref= ref0; nengel@2: mv0= pack16to32(mv_l0[0],mv_l0[1]); nengel@2: mv1= pack16to32(mv_l0[0]-mv_col[0],mv_l0[1]-mv_col[1]); nengel@2: } nengel@2: fill_rectangle(&mrs->ref_cache[0][scan8[0]], 4, 4, 8, ref, 1); nengel@2: fill_rectangle(&mrs->mv_cache[0][scan8[0]], 4, 4, 8, mv0, 4); nengel@2: fill_rectangle(&mrs->mv_cache[1][scan8[0]], 4, 4, 8, mv1, 4); nengel@2: }else{ nengel@2: for(i8=0; i8<4; i8++){ nengel@2: const int x8 = i8&1; nengel@2: const int y8 = i8>>1; nengel@2: int ref0, scale; nengel@2: const int16_t (*l1mv)[2]= l1mv0; nengel@2: nengel@2: if(is_b8x8 && !IS_DIRECT(m->sub_mb_type[i8])) nengel@2: continue; nengel@2: m->sub_mb_type[i8] = sub_mb_type; nengel@2: fill_rectangle(&mrs->ref_cache[1][scan8[i8*4]], 2, 2, 8, 0, 1); nengel@2: if(IS_INTRA(mb_type_col[0])){ nengel@2: fill_rectangle(&mrs->ref_cache[0][scan8[i8*4]], 2, 2, 8, 0, 1); nengel@2: fill_rectangle(&mrs->mv_cache[0][scan8[i8*4]], 2, 2, 8, 0, 4); nengel@2: fill_rectangle(&mrs->mv_cache[1][scan8[i8*4]], 2, 2, 8, 0, 4); nengel@2: continue; nengel@2: } nengel@2: nengel@2: ref0 = l1ref0[i8]; nengel@2: if(ref0 >= 0) nengel@2: ref0 = map_col_to_list0[0][ref0 ]; nengel@2: else{ nengel@2: ref0 = map_col_to_list0[1][l1ref1[i8]]; nengel@2: l1mv= l1mv1; nengel@2: } nengel@2: scale = dist_scale_factor[ref0]; nengel@2: nengel@2: fill_rectangle(&mrs->ref_cache[0][scan8[i8*4]], 2, 2, 8, ref0, 1); nengel@2: if(IS_SUB_8X8(sub_mb_type)){ nengel@2: const int16_t *mv_col = l1mv[x8*3 + y8*3*b4_stride]; nengel@2: int mx = (scale * mv_col[0] + 128) >> 8; nengel@2: int my = (scale * mv_col[1] + 128) >> 8; nengel@2: fill_rectangle(&mrs->mv_cache[0][scan8[i8*4]], 2, 2, 8, pack16to32(mx,my), 4); nengel@2: fill_rectangle(&mrs->mv_cache[1][scan8[i8*4]], 2, 2, 8, pack16to32(mx-mv_col[0],my-mv_col[1]), 4); nengel@2: }else nengel@2: for(i4=0; i4<4; i4++){ nengel@2: const int16_t *mv_col = l1mv[x8*2 + (i4&1) + (y8*2 + (i4>>1))*b4_stride]; nengel@2: int16_t *mv_l0 = mrs->mv_cache[0][scan8[i8*4+i4]]; nengel@2: mv_l0[0] = (scale * mv_col[0] + 128) >> 8; nengel@2: mv_l0[1] = (scale * mv_col[1] + 128) >> 8; nengel@2: AV_WN32A(mrs->mv_cache[1][scan8[i8*4+i4]], nengel@2: pack16to32(mv_l0[0]-mv_col[0],mv_l0[1]-mv_col[1])); nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: void ff_h264_pred_direct_motion_rec(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, H264Mb *m, int *mb_type){ nengel@2: if(s->direct_spatial_mv_pred){ nengel@2: pred_spatial_direct_motion_rec(mrc, mrs, s, m, mb_type); nengel@2: }else{ nengel@2: pred_temp_direct_motion_rec(mrc, mrs, s, m, mb_type); nengel@2: } nengel@2: } nengel@2: nengel@2: static inline int fetch_diagonal_mv(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, const int16_t **C, int i, int list, int part_width){ nengel@2: const int topright_ref= mrs->ref_cache[list][ i - 8 + part_width ]; nengel@2: nengel@2: if(topright_ref != PART_NOT_AVAILABLE){ nengel@2: *C= mrs->mv_cache[list][ i - 8 + part_width ]; nengel@2: return topright_ref; nengel@2: }else{ nengel@2: *C= mrs->mv_cache[list][ i - 8 - 1 ]; nengel@2: return mrs->ref_cache[list][ i - 8 - 1 ]; nengel@2: } nengel@2: } nengel@2: nengel@2: /** nengel@2: * gets the predicted MV. nengel@2: * @param n the block index nengel@2: * @param part_width the width of the partition (4, 8,16) -> (1, 2, 4) nengel@2: * @param mx the x component of the predicted motion vector nengel@2: * @param my the y component of the predicted motion vector nengel@2: */ nengel@2: static inline void pred_motion(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, int n, int part_width, int list, int ref, int * const mx, int * const my){ nengel@2: const int index8= scan8[n]; nengel@2: const int top_ref= mrs->ref_cache[list][ index8 - 8 ]; nengel@2: const int left_ref= mrs->ref_cache[list][ index8 - 1 ]; nengel@2: const int16_t * const A= mrs->mv_cache[list][ index8 - 1 ]; nengel@2: const int16_t * const B= mrs->mv_cache[list][ index8 - 8 ]; nengel@2: const int16_t * C; nengel@2: int diagonal_ref, match_count; nengel@2: nengel@2: assert(part_width==1 || part_width==2 || part_width==4); nengel@2: nengel@2: /* mv_cache nengel@2: B . . A T T T T nengel@2: U . . L . . , . nengel@2: U . . L . . . . nengel@2: U . . L . . , . nengel@2: . . . L . . . . nengel@2: */ nengel@2: nengel@2: diagonal_ref= fetch_diagonal_mv(mrc, mrs, s, &C, index8, list, part_width); nengel@2: match_count= (diagonal_ref==ref) + (top_ref==ref) + (left_ref==ref); nengel@2: nengel@2: if(match_count > 1){ //most common nengel@2: *mx= mid_pred(A[0], B[0], C[0]); nengel@2: *my= mid_pred(A[1], B[1], C[1]); nengel@2: }else if(match_count==1){ nengel@2: if(left_ref==ref){ nengel@2: *mx= A[0]; nengel@2: *my= A[1]; nengel@2: }else if(top_ref==ref){ nengel@2: *mx= B[0]; nengel@2: *my= B[1]; nengel@2: }else{ nengel@2: *mx= C[0]; nengel@2: *my= C[1]; nengel@2: } nengel@2: }else{ nengel@2: if(top_ref == PART_NOT_AVAILABLE && diagonal_ref == PART_NOT_AVAILABLE && left_ref != PART_NOT_AVAILABLE){ nengel@2: *mx= A[0]; nengel@2: *my= A[1]; nengel@2: }else{ nengel@2: *mx= mid_pred(A[0], B[0], C[0]); nengel@2: *my= mid_pred(A[1], B[1], C[1]); nengel@2: } nengel@2: } nengel@2: nengel@2: } nengel@2: nengel@2: /** nengel@2: * gets the directionally predicted 16x8 MV. nengel@2: * @param n the block index nengel@2: * @param mx the x component of the predicted motion vector nengel@2: * @param my the y component of the predicted motion vector nengel@2: */ nengel@2: static inline void pred_16x8_motion(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, int n, int list, int ref, int * const mx, int * const my){ nengel@2: if(n==0){ nengel@2: const int top_ref= mrs->ref_cache[list][ scan8[0] - 8 ]; nengel@2: const int16_t * const B= mrs->mv_cache[list][ scan8[0] - 8 ]; nengel@2: nengel@2: if(top_ref == ref){ nengel@2: *mx= B[0]; nengel@2: *my= B[1]; nengel@2: return; nengel@2: } nengel@2: }else{ nengel@2: const int left_ref= mrs->ref_cache[list][ scan8[8] - 1 ]; nengel@2: const int16_t * const A= mrs->mv_cache[list][ scan8[8] - 1 ]; nengel@2: nengel@2: if(left_ref == ref){ nengel@2: *mx= A[0]; nengel@2: *my= A[1]; nengel@2: return; nengel@2: } nengel@2: } nengel@2: nengel@2: //RARE nengel@2: pred_motion(mrc, mrs, s, n, 4, list, ref, mx, my); nengel@2: } nengel@2: nengel@2: /** nengel@2: * gets the directionally predicted 8x16 MV. nengel@2: * @param n the block index nengel@2: * @param mx the x component of the predicted motion vector nengel@2: * @param my the y component of the predicted motion vector nengel@2: */ nengel@2: static inline void pred_8x16_motion(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, int n, int list, int ref, int * const mx, int * const my){ nengel@2: if(n==0){ nengel@2: const int left_ref= mrs->ref_cache[list][ scan8[0] - 1 ]; nengel@2: const int16_t * const A= mrs->mv_cache[list][ scan8[0] - 1 ]; nengel@2: nengel@2: if(left_ref == ref){ nengel@2: *mx= A[0]; nengel@2: *my= A[1]; nengel@2: return; nengel@2: } nengel@2: }else{ nengel@2: const int16_t * C; nengel@2: int diagonal_ref; nengel@2: nengel@2: diagonal_ref= fetch_diagonal_mv(mrc, mrs, s, &C, scan8[4], list, 2); nengel@2: if(diagonal_ref == ref){ nengel@2: *mx= C[0]; nengel@2: *my= C[1]; nengel@2: return; nengel@2: } nengel@2: } nengel@2: nengel@2: //RARE nengel@2: pred_motion(mrc, mrs, s, n, 2, list, ref, mx, my); nengel@2: } nengel@2: nengel@2: static inline void pred_pskip_motion(MBRecContext *mrc, MBRecState *mrs, H264Slice *s, H264Mb * m, int * const mx, int * const my){ nengel@2: const int top_ref = mrs->ref_cache[0][ scan8[0] - 8 ]; nengel@2: const int left_ref= mrs->ref_cache[0][ scan8[0] - 1 ]; nengel@2: nengel@2: if(top_ref == PART_NOT_AVAILABLE || left_ref == PART_NOT_AVAILABLE nengel@2: || !( top_ref | AV_RN32A(mrs->mv_cache[0][ scan8[0] - 8 ])) nengel@2: || !(left_ref | AV_RN32A(mrs->mv_cache[0][ scan8[0] - 1 ]))){ nengel@2: nengel@2: *mx = *my = 0; nengel@2: return; nengel@2: } nengel@2: nengel@2: pred_motion(mrc, mrs, s, 0, 4, 0, 0, mx, my); nengel@2: nengel@2: return; nengel@2: } nengel@2: nengel@2: #define ADD_MVD(list) \ nengel@2: { \ nengel@2: mx += m->mvd[list][mp][0]; \ nengel@2: my += m->mvd[list][mp][1]; \ nengel@2: mp++; \ nengel@2: } nengel@2: nengel@2: int pred_motion_mb_rec (MBRecContext *mrc, MBRecState *mrs, H264Slice *s, H264Mb *m){ nengel@2: int mp=0; nengel@2: int mb_type = m->mb_type; nengel@2: const int mb_x = m->mb_x; nengel@2: nengel@2: // mrc->m =m; nengel@2: nengel@2: fill_decode_caches_rec(mrc, mrs, s, m, mb_type); nengel@2: if (IS_SKIP(mb_type)){ nengel@2: mb_type=0; nengel@2: nengel@2: if( s->slice_type_nos == FF_B_TYPE ) nengel@2: { nengel@2: mb_type|= MB_TYPE_L0L1|MB_TYPE_DIRECT2|MB_TYPE_SKIP; nengel@2: ff_h264_pred_direct_motion_rec(mrc, mrs, s, m, &mb_type); nengel@2: } nengel@2: else nengel@2: { nengel@2: int mx, my; nengel@2: nengel@2: mb_type|= MB_TYPE_16x16|MB_TYPE_P0L0|MB_TYPE_P1L0|MB_TYPE_SKIP; //FIXME check required nengel@2: pred_pskip_motion(mrc, mrs, s, m, &mx, &my); nengel@2: fill_rectangle(&mrs->ref_cache[0][scan8[0]], 4, 4, 8, 0, 1); nengel@2: fill_rectangle(mrs->mv_cache[0][scan8[0]], 4, 4, 8, pack16to32(mx,my), 4); nengel@2: } nengel@2: nengel@2: write_back_motion_rec(mrc, mrs, s, m, mb_type); nengel@2: m->mb_type = mrs->mb_type[mb_x]= mb_type; nengel@2: return 0; nengel@2: } nengel@2: nengel@2: nengel@2: if (IS_INTRA_PCM(mb_type)){ nengel@2: mrs->mb_type[mb_x] = mb_type; nengel@2: return 0; nengel@2: } nengel@2: else if (IS_INTRA(mb_type)){ nengel@2: int i, pred_mode; nengel@2: nengel@2: if( IS_INTRA4x4( mb_type ) ) { nengel@2: if ( IS_8x8DCT(mb_type) ) { nengel@2: for( i = 0; i < 16; i+=4 ) { nengel@2: int pred = pred_intra_mode(mrc, mrs, i ); nengel@2: int mode = m->intra4x4_pred_mode[i]; nengel@2: nengel@2: mode = mode < 0 ? pred : mode + ( mode >= pred ); nengel@2: fill_rectangle( &mrs->intra4x4_pred_mode_cache[ scan8[i] ], 2, 2, 8, mode, 1 ); nengel@2: } nengel@2: } else { nengel@2: for( i = 0; i < 16; i++ ) { nengel@2: int pred = pred_intra_mode(mrc, mrs, i ); nengel@2: int mode = m->intra4x4_pred_mode[i]; nengel@2: mode = mode < 0 ? pred : mode + ( mode >= pred ); nengel@2: mrs->intra4x4_pred_mode_cache[ scan8[i] ] = mode; nengel@2: } nengel@2: } nengel@2: write_back_intra_pred_mode_rec(mrc, mrs, m, mb_x); nengel@2: if( check_intra4x4_pred_mode(mrc, mrs, s, m) < 0 ) return -1; nengel@2: } else { nengel@2: m->intra16x16_pred_mode= check_intra_pred_mode(mrc, mrs, s, m, m->intra16x16_pred_mode ); nengel@2: if( m->intra16x16_pred_mode < 0 ) return -1; nengel@2: } nengel@2: nengel@2: pred_mode = m->chroma_pred_mode; nengel@2: pred_mode= check_intra_pred_mode( mrc, mrs, s, m, pred_mode ); nengel@2: if( pred_mode < 0 ) return -1; nengel@2: m->chroma_pred_mode= pred_mode; nengel@2: nengel@2: } nengel@2: else if (IS_8X8(mb_type)){ nengel@2: int i, j, list; nengel@2: nengel@2: if( s->slice_type_nos == FF_B_TYPE ) { nengel@2: if( IS_DIRECT(m->sub_mb_type[0] | m->sub_mb_type[1] | nengel@2: m->sub_mb_type[2] | m->sub_mb_type[3]) ) { nengel@2: ff_h264_pred_direct_motion_rec(mrc, mrs, s, m, &mb_type); nengel@2: mrs->ref_cache[0][scan8[4]] = nengel@2: mrs->ref_cache[1][scan8[4]] = nengel@2: mrs->ref_cache[0][scan8[12]] = nengel@2: mrs->ref_cache[1][scan8[12]] = PART_NOT_AVAILABLE; nengel@2: } nengel@2: } nengel@2: nengel@2: for(list=0; listlist_count; list++){ nengel@2: for(i=0; i<4; i++){ nengel@2: if(IS_DIRECT(m->sub_mb_type[i])){ nengel@2: mrs->ref_cache[list][ scan8[4*i] ]=mrs->ref_cache[list][ scan8[4*i]+1 ]; nengel@2: continue; nengel@2: } else { nengel@2: mrs->ref_cache[list][ scan8[4*i] ]=mrs->ref_cache[list][ scan8[4*i]+1 ]= nengel@2: mrs->ref_cache[list][ scan8[4*i]+8 ]=mrs->ref_cache[list][ scan8[4*i]+9 ]= m->ref_index[list][i]; nengel@2: nengel@2: if(IS_DIR(m->sub_mb_type[i], 0, list) ){ nengel@2: const int sub_mb_type= m->sub_mb_type[i]; nengel@2: const int block_width= (sub_mb_type & (MB_TYPE_16x16|MB_TYPE_16x8)) ? 2 : 1; nengel@2: nengel@2: int sub_partition_count = IS_SUB_8X8(sub_mb_type) ? 1 : (IS_SUB_4X4(sub_mb_type)? 4 :2); nengel@2: for(j=0; jmv_cache[list][ scan8[index]]; nengel@2: pred_motion(mrc, mrs, s, index, block_width, list, mrs->ref_cache[list][ scan8[index] ], &mx, &my); nengel@2: nengel@2: ADD_MVD(list) nengel@2: nengel@2: if(IS_SUB_8X8(sub_mb_type)){ nengel@2: mv_cache[ 1 ][0]= nengel@2: mv_cache[ 8 ][0]= mv_cache[ 9 ][0]= mx; nengel@2: mv_cache[ 1 ][1]= nengel@2: mv_cache[ 8 ][1]= mv_cache[ 9 ][1]= my; nengel@2: }else if(IS_SUB_8X4(sub_mb_type)){ nengel@2: mv_cache[ 1 ][0]= mx; nengel@2: mv_cache[ 1 ][1]= my; nengel@2: }else if(IS_SUB_4X8(sub_mb_type)){ nengel@2: mv_cache[ 8 ][0]= mx; nengel@2: mv_cache[ 8 ][1]= my; nengel@2: } nengel@2: mv_cache[ 0 ][0]= mx; nengel@2: mv_cache[ 0 ][1]= my; nengel@2: } nengel@2: }else{ nengel@2: fill_rectangle(mrs->mv_cache [list][ scan8[4*i] ], 2, 2, 8, 0, 4); nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: } else if( IS_DIRECT(mb_type) ) { nengel@2: mb_type &= ~MB_TYPE_16x16; //FIXME not nice nengel@2: ff_h264_pred_direct_motion_rec(mrc, mrs, s, m, &mb_type); nengel@2: } nengel@2: else { nengel@2: int list, i; nengel@2: if(IS_16X16(mb_type)){ nengel@2: for(list=0; listlist_count; list++){ nengel@2: if(IS_DIR(mb_type, 0, list)){ nengel@2: int ref; nengel@2: int mx,my; nengel@2: nengel@2: ref = m->ref_index[list][0]; nengel@2: fill_rectangle(&mrs->ref_cache[list][ scan8[0] ], 4, 4, 8, ref, 1); nengel@2: pred_motion(mrc, mrs, s, 0, 4, list, mrs->ref_cache[list][ scan8[0] ], &mx, &my); nengel@2: ADD_MVD(list) nengel@2: fill_rectangle(mrs->mv_cache[list][ scan8[0] ], 4, 4, 8, pack16to32(mx,my), 4); nengel@2: } nengel@2: } nengel@2: } nengel@2: else if(IS_16X8(mb_type)){ nengel@2: for(list=0; listlist_count; list++){ nengel@2: for(i=0; i<2; i++){ nengel@2: if(IS_DIR(mb_type, i, list)){ nengel@2: int ref; nengel@2: int mx,my; nengel@2: ref = m->ref_index[list][i]; nengel@2: fill_rectangle(&mrs->ref_cache[list][ scan8[0] + 16*i ], 4, 2, 8, ref, 1); nengel@2: nengel@2: pred_16x8_motion(mrc, mrs, s, 8*i, list, mrs->ref_cache[list][scan8[0] + 16*i], &mx, &my); nengel@2: ADD_MVD(list) nengel@2: nengel@2: fill_rectangle(mrs->mv_cache[list][ scan8[0] + 16*i ], 4, 2, 8, pack16to32(mx,my), 4); nengel@2: }else{ nengel@2: fill_rectangle(&mrs->ref_cache[list][ scan8[0] + 16*i ], 4, 2, 8, (LIST_NOT_USED&0xFF), 1); nengel@2: fill_rectangle(mrs->mv_cache[list][ scan8[0] + 16*i ], 4, 2, 8, 0, 4); nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: }else{ nengel@2: assert(IS_8X16(mb_type)); nengel@2: nengel@2: for(list=0; listlist_count; list++){ nengel@2: for(i=0; i<2; i++){ nengel@2: if(IS_DIR(mb_type, i, list)){ //FIXME optimize nengel@2: int ref; nengel@2: int mx,my; nengel@2: ref = m->ref_index[list][i]; nengel@2: fill_rectangle(&mrs->ref_cache[list][ scan8[0] + 2*i ], 2, 4, 8, ref, 1); nengel@2: pred_8x16_motion(mrc, mrs, s, i*4, list, mrs->ref_cache[list][ scan8[0] + 2*i ], &mx, &my); nengel@2: ADD_MVD(list) nengel@2: fill_rectangle(mrs->mv_cache[list][ scan8[0] + 2*i ], 2, 4, 8, pack16to32(mx,my), 4); nengel@2: }else{ nengel@2: fill_rectangle(&mrs->ref_cache[list][ scan8[0] + 2*i ], 2, 4, 8, (LIST_NOT_USED&0xFF), 1); nengel@2: fill_rectangle(mrs->mv_cache[list][ scan8[0] + 2*i ], 2, 4, 8, 0, 4); nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: if (IS_INTER(mb_type)||(IS_DIRECT(mb_type))) nengel@2: write_back_motion_rec(mrc, mrs, s, m, mb_type); nengel@2: m->mb_type = mrs->mb_type[mb_x]= mb_type; nengel@2: nengel@2: return 0; nengel@2: }