From bea669e57cdd72b22cfc51514493a90f62dc96c9 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Fri, 13 Sep 2002 09:45:32 +0000 Subject: [PATCH] interlaced mpeg4 b frame decoding Originally committed as revision 936 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/h263.c | 204 +++++++++++++++++++++++++++------------- libavcodec/motion_est.c | 4 +- libavcodec/mpeg4data.h | 4 + libavcodec/mpegvideo.c | 29 ++++-- libavcodec/mpegvideo.h | 11 ++- 5 files changed, 177 insertions(+), 75 deletions(-) diff --git a/libavcodec/h263.c b/libavcodec/h263.c index 5cf1733504..d4fd024a5e 100644 --- a/libavcodec/h263.c +++ b/libavcodec/h263.c @@ -1331,7 +1331,7 @@ void ff_set_mpeg4_time(MpegEncContext * s, int picture_number){ time_mod= s->time%s->time_increment_resolution; if(s->pict_type==B_TYPE){ - s->bp_time= s->last_non_b_time - s->time; + s->pb_time= s->pp_time - (s->last_non_b_time - s->time); }else{ s->last_time_base= s->time_base; s->time_base= time_div; @@ -2828,35 +2828,107 @@ int h263_decode_mb(MpegEncContext *s, h263_dc_scale(s); } } -// decode_interlaced_info(s, cbp, mb_type); + s->mv_type= MV_TYPE_16X16; //might be changed to 8X8 or FIELD later + + if(!s->progressive_sequence){ + if(cbp) + s->interlaced_dct= get_bits1(&s->gb); + + if(mb_type!=MB_TYPE_B_DIRECT){ + if(get_bits1(&s->gb)){ + s->mv_type= MV_TYPE_FIELD; + + if(mb_type!=MB_TYPE_B_BACKW){ + s->field_select[0][0]= get_bits1(&s->gb); //FIXME move down + s->field_select[0][1]= get_bits1(&s->gb); + } + if(mb_type!=MB_TYPE_B_FORW){ + s->field_select[1][0]= get_bits1(&s->gb); + s->field_select[1][1]= get_bits1(&s->gb); + } + } + } + } }else{ - mb_type=4; //like 0 but no vectors coded + s->mv_type= MV_TYPE_16X16; //might be changed to 8X8 later + mb_type=4; //like MB_TYPE_B_DIRECT but no vectors coded cbp=0; } - s->mv_type = MV_TYPE_16X16; // we'll switch to 8x8 only if the last P frame had 8x8 for this MB and mb_type=0 here - mx=my=0; //for case 4, we could put this to the mb_type=4 but than gcc compains about uninitalized mx/my - switch(mb_type) - { - case 0: /* direct */ + + mx=my=0; + if(mb_type==MB_TYPE_B_DIRECT){ mx = h263_decode_motion(s, 0, 1); my = h263_decode_motion(s, 0, 1); - case 4: /* direct with mx=my=0 */ + } + + if(s->mv_type==MV_TYPE_16X16){ + if(mb_type==MB_TYPE_B_FORW || mb_type==MB_TYPE_B_BIDIR){ + s->mv_dir = MV_DIR_FORWARD; + mx = h263_decode_motion(s, s->last_mv[0][0][0], s->f_code); + my = h263_decode_motion(s, s->last_mv[0][0][1], s->f_code); + s->last_mv[0][1][0]= s->last_mv[0][0][0]= s->mv[0][0][0] = mx; + s->last_mv[0][1][1]= s->last_mv[0][0][1]= s->mv[0][0][1] = my; + }else + s->mv_dir = 0; + + if(mb_type==MB_TYPE_B_BACKW || mb_type==MB_TYPE_B_BIDIR){ + s->mv_dir |= MV_DIR_BACKWARD; + mx = h263_decode_motion(s, s->last_mv[1][0][0], s->b_code); + my = h263_decode_motion(s, s->last_mv[1][0][1], s->b_code); + s->last_mv[1][1][0]= s->last_mv[1][0][0]= s->mv[1][0][0] = mx; + s->last_mv[1][1][1]= s->last_mv[1][0][1]= s->mv[1][0][1] = my; + } + if(mb_type!=4 && mb_type!=MB_TYPE_B_DIRECT) + PRINT_MB_TYPE(mb_type==MB_TYPE_B_FORW ? "F" : (mb_type==MB_TYPE_B_BACKW ? "B" : "T")); + }else{ + /* MV_TYPE_FIELD */ + if(mb_type==MB_TYPE_B_FORW || mb_type==MB_TYPE_B_BIDIR){ + s->mv_dir = MV_DIR_FORWARD; + for(i=0; i<2; i++){ + mx = h263_decode_motion(s, s->last_mv[0][i][0] , s->f_code); + my = h263_decode_motion(s, s->last_mv[0][i][1]/2, s->f_code); + s->last_mv[0][i][0]= s->mv[0][i][0] = mx; + s->last_mv[0][i][1]= (s->mv[0][i][1] = my)*2; + } + }else + s->mv_dir = 0; + + if(mb_type==MB_TYPE_B_BACKW || mb_type==MB_TYPE_B_BIDIR){ + s->mv_dir |= MV_DIR_BACKWARD; + for(i=0; i<2; i++){ + mx = h263_decode_motion(s, s->last_mv[1][i][0] , s->b_code); + my = h263_decode_motion(s, s->last_mv[1][i][1]/2, s->b_code); + s->last_mv[1][i][0]= s->mv[1][i][0] = mx; + s->last_mv[1][i][1]= (s->mv[1][i][1] = my)*2; + } + } + if(mb_type!=4 && mb_type!=MB_TYPE_B_DIRECT) + PRINT_MB_TYPE(mb_type==MB_TYPE_B_FORW ? "f" : (mb_type==MB_TYPE_B_BACKW ? "b" : "t")); + } + + if(mb_type==4 || mb_type==MB_TYPE_B_DIRECT){ + int mb_index= s->mb_x + s->mb_y*s->mb_width; + int i; + s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; xy= s->block_index[0]; time_pp= s->pp_time; - time_pb= time_pp - s->bp_time; -//if(time_pp>3000 )printf("%d %d ", time_pp, time_pb); + time_pb= s->pb_time; + //FIXME avoid divides - s->mv[0][0][0] = s->motion_val[xy][0]*time_pb/time_pp + mx; - s->mv[0][0][1] = s->motion_val[xy][1]*time_pb/time_pp + my; - s->mv[1][0][0] = mx ? s->mv[0][0][0] - s->motion_val[xy][0] - : s->motion_val[xy][0]*(time_pb - time_pp)/time_pp; - s->mv[1][0][1] = my ? s->mv[0][0][1] - s->motion_val[xy][1] - : s->motion_val[xy][1]*(time_pb - time_pp)/time_pp; - if(s->non_b_mv4_table[xy]){ - int i; + switch(s->co_located_type_table[mb_index]){ + case 0: + s->mv[0][0][0] = s->motion_val[xy][0]*time_pb/time_pp + mx; + s->mv[0][0][1] = s->motion_val[xy][1]*time_pb/time_pp + my; + s->mv[1][0][0] = mx ? s->mv[0][0][0] - s->motion_val[xy][0] + : s->motion_val[xy][0]*(time_pb - time_pp)/time_pp; + s->mv[1][0][1] = my ? s->mv[0][0][1] - s->motion_val[xy][1] + : s->motion_val[xy][1]*(time_pb - time_pp)/time_pp; + PRINT_MB_TYPE(mb_type==4 ? "D" : "S"); + break; + case CO_LOCATED_TYPE_4MV: s->mv_type = MV_TYPE_8X8; - for(i=1; i<4; i++){ + for(i=0; i<4; i++){ xy= s->block_index[i]; s->mv[0][i][0] = s->motion_val[xy][0]*time_pb/time_pp + mx; s->mv[0][i][1] = s->motion_val[xy][1]*time_pb/time_pp + my; @@ -2866,45 +2938,30 @@ int h263_decode_mb(MpegEncContext *s, : s->motion_val[xy][1]*(time_pb - time_pp)/time_pp; } PRINT_MB_TYPE("4"); - }else{ - PRINT_MB_TYPE(mb_type==4 ? "D" : "S"); + break; + case CO_LOCATED_TYPE_FIELDMV: + s->mv_type = MV_TYPE_FIELD; + for(i=0; i<2; i++){ + if(s->top_field_first){ + time_pp= s->pp_field_time - s->field_select_table[mb_index][i] + i; + time_pb= s->pb_field_time - s->field_select_table[mb_index][i] + i; + }else{ + time_pp= s->pp_field_time + s->field_select_table[mb_index][i] - i; + time_pb= s->pb_field_time + s->field_select_table[mb_index][i] - i; + } + s->mv[0][i][0] = s->field_mv_table[mb_index][i][0]*time_pb/time_pp + mx; + s->mv[0][i][1] = s->field_mv_table[mb_index][i][1]*time_pb/time_pp + my; + s->mv[1][i][0] = mx ? s->mv[0][i][0] - s->field_mv_table[mb_index][i][0] + : s->field_mv_table[mb_index][i][0]*(time_pb - time_pp)/time_pp; + s->mv[1][i][1] = my ? s->mv[0][i][1] - s->field_mv_table[mb_index][i][1] + : s->field_mv_table[mb_index][i][1]*(time_pb - time_pp)/time_pp; + } + PRINT_MB_TYPE("="); + break; } -/* s->mv[0][0][0] = - s->mv[0][0][1] = - s->mv[1][0][0] = - s->mv[1][0][1] = 1000;*/ - break; -//FIXME additional MVs for interlaced stuff - case 1: - s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; - mx = h263_decode_motion(s, s->last_mv[0][0][0], s->f_code); - my = h263_decode_motion(s, s->last_mv[0][0][1], s->f_code); - s->last_mv[0][0][0]= s->mv[0][0][0] = mx; - s->last_mv[0][0][1]= s->mv[0][0][1] = my; - - mx = h263_decode_motion(s, s->last_mv[1][0][0], s->b_code); - my = h263_decode_motion(s, s->last_mv[1][0][1], s->b_code); - s->last_mv[1][0][0]= s->mv[1][0][0] = mx; - s->last_mv[1][0][1]= s->mv[1][0][1] = my; - PRINT_MB_TYPE("i"); - break; - case 2: - s->mv_dir = MV_DIR_BACKWARD; - mx = h263_decode_motion(s, s->last_mv[1][0][0], s->b_code); - my = h263_decode_motion(s, s->last_mv[1][0][1], s->b_code); - s->last_mv[1][0][0]= s->mv[1][0][0] = mx; - s->last_mv[1][0][1]= s->mv[1][0][1] = my; - PRINT_MB_TYPE("B"); - break; - case 3: - s->mv_dir = MV_DIR_FORWARD; - mx = h263_decode_motion(s, s->last_mv[0][0][0], s->f_code); - my = h263_decode_motion(s, s->last_mv[0][0][1], s->f_code); - s->last_mv[0][0][0]= s->mv[0][0][0] = mx; - s->last_mv[0][0][1]= s->mv[0][0][1] = my; - PRINT_MB_TYPE("F"); - break; - default: + } + + if(mb_type<0 || mb_type>4){ printf("illegal MB_type\n"); return -1; } @@ -3793,6 +3850,7 @@ int mpeg4_decode_picture_header(MpegEncContext * s) skip_bits1(&s->gb); /* marker */ s->time_increment_resolution = get_bits(&s->gb, 16); + s->time_increment_bits = av_log2(s->time_increment_resolution - 1) + 1; if (s->time_increment_bits < 1) s->time_increment_bits = 1; @@ -4005,15 +4063,28 @@ int mpeg4_decode_picture_header(MpegEncContext * s) s->last_time_base= s->time_base; s->time_base+= time_incr; s->time= s->time_base*s->time_increment_resolution + time_increment; + if(s->time < s->last_non_b_time && s->workaround_bugs==3){ + fprintf(stderr, "header is not mpeg4 compatible, broken encoder, trying to workaround\n"); + s->time_base++; + s->time+= s->time_increment_resolution; + } s->pp_time= s->time - s->last_non_b_time; s->last_non_b_time= s->time; }else{ s->time= (s->last_time_base + time_incr)*s->time_increment_resolution + time_increment; - s->bp_time= s->last_non_b_time - s->time; - if(s->pp_time <=s->bp_time){ + s->pb_time= s->pp_time - (s->last_non_b_time - s->time); + if(s->pp_time <=s->pb_time || s->pp_time <= s->pp_time - s->pb_time || s->pp_time<=0){ // printf("messed up order, seeking?, skiping current b frame\n"); return FRAME_SKIPED; } + + if(s->t_frame==0) s->t_frame= s->time - s->last_time_base; + if(s->t_frame==0) s->t_frame=1; // 1/0 protection +//printf("%Ld %Ld %d %d\n", s->last_non_b_time, s->time, s->pp_time, s->t_frame); fflush(stdout); + s->pp_field_time= ( ROUNDED_DIV(s->last_non_b_time, s->t_frame) + - ROUNDED_DIV(s->last_non_b_time - s->pp_time, s->t_frame))*2; + s->pb_field_time= ( ROUNDED_DIV(s->time, s->t_frame) + - ROUNDED_DIV(s->last_non_b_time - s->pp_time, s->t_frame))*2; } s->avctx->pts= s->time*1000LL*1000LL / s->time_increment_resolution; @@ -4028,8 +4099,8 @@ int mpeg4_decode_picture_header(MpegEncContext * s) /* vop coded */ if (get_bits1(&s->gb) != 1) goto redo; -//printf("time %d %d %d || %d %d %d\n", s->time_increment_bits, s->time_increment, s->time_base, -//s->time, s->last_non_b_time[0], s->last_non_b_time[1]); +//printf("time %d %d %d || %Ld %Ld %Ld\n", s->time_increment_bits, s->time_increment_resolution, s->time_base, +//s->time, s->last_non_b_time, s->last_non_b_time - s->pp_time); if (s->shape != BIN_ONLY_SHAPE && ( s->pict_type == P_TYPE || (s->pict_type == S_TYPE && s->vol_sprite_usage==GMC_SPRITE))) { /* rounding type for motion estimation */ @@ -4101,9 +4172,12 @@ int mpeg4_decode_picture_header(MpegEncContext * s) s->b_code = get_bits(&s->gb, 3); }else s->b_code=1; - -//printf("qpuant:%d fcode:%d bcode:%d type:%d size:%d pro:%d alt:%d\n", -// s->qscale, s->f_code, s->b_code, s->pict_type, s->gb.size,s->progressive_sequence, s->alternate_scan); +#if 0 +printf("qp:%d fc:%d bc:%d type:%s size:%d pro:%d alt:%d qpel:%d part:%d resync:%d\n", + s->qscale, s->f_code, s->b_code, + s->pict_type == I_TYPE ? "I" : (s->pict_type == P_TYPE ? "P" : (s->pict_type == B_TYPE ? "B" : "S")), + s->gb.size,s->progressive_sequence, s->alternate_scan, s->quarter_sample, s->data_partitioning, s->resync_marker); +#endif if(!s->scalability){ if (s->shape!=RECT_SHAPE && s->pict_type!=I_TYPE) { skip_bits1(&s->gb); // vop shape coding type diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index 325d0f5525..032556a6d4 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -1391,8 +1391,8 @@ static inline int direct_search(MpegEncContext * s, const int motion_px= s->p_mv_table[mot_xy][0]; const int motion_py= s->p_mv_table[mot_xy][1]; const int time_pp= s->pp_time; - const int time_bp= s->bp_time; - const int time_pb= time_pp - time_bp; + const int time_pb= s->pb_time; + const int time_bp= time_pp - time_pb; int bx, by; int mx, my, mx2, my2; uint8_t *ref_picture= s->me_scratchpad - (mb_x - 1 + (mb_y - 1)*s->linesize)*16; diff --git a/libavcodec/mpeg4data.h b/libavcodec/mpeg4data.h index 3d8de7ca6f..88101a5442 100644 --- a/libavcodec/mpeg4data.h +++ b/libavcodec/mpeg4data.h @@ -17,6 +17,10 @@ #define MOTION_MARKER 0x1F001 #define DC_MARKER 0x6B001 +#define MB_TYPE_B_DIRECT 0 +#define MB_TYPE_B_BIDIR 1 +#define MB_TYPE_B_BACKW 2 +#define MB_TYPE_B_FORW 3 /* dc encoding for mpeg4 */ const UINT8 DCtab_lum[13][2] = diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 1693b484a1..bbd23482d2 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -259,9 +259,13 @@ int MPV_common_init(MpegEncContext *s) /* MV prediction */ size = (2 * s->mb_width + 2) * (2 * s->mb_height + 2); CHECKED_ALLOCZ(s->motion_val, size * 2 * sizeof(INT16)); - - /* 4mv direct mode decoding table */ - CHECKED_ALLOCZ(s->non_b_mv4_table, size * sizeof(UINT8)) + } + + if(s->codec_id==CODEC_ID_MPEG4){ + /* 4mv and interlaced direct mode decoding tables */ + CHECKED_ALLOCZ(s->co_located_type_table, s->mb_num * sizeof(UINT8)) + CHECKED_ALLOCZ(s->field_mv_table, s->mb_num*2*2 * sizeof(INT16)) + CHECKED_ALLOCZ(s->field_select_table, s->mb_num*2* sizeof(INT8)) } if (s->h263_pred || s->h263_plus) { @@ -350,7 +354,9 @@ void MPV_common_end(MpegEncContext *s) av_freep(&s->tex_pb_buffer); av_freep(&s->pb2_buffer); av_freep(&s->edge_emu_buffer); - av_freep(&s->non_b_mv4_table); + av_freep(&s->co_located_type_table); + av_freep(&s->field_mv_table); + av_freep(&s->field_select_table); av_freep(&s->avctx->stats_out); av_freep(&s->ac_stats); @@ -1466,20 +1472,32 @@ void MPV_decode_mb(MpegEncContext *s, DCTELEM block[6][64]) const int wrap = s->block_wrap[0]; const int xy = s->block_index[0]; + const int mb_index= s->mb_x + s->mb_y*s->mb_width; if(s->mv_type == MV_TYPE_8X8){ - s->non_b_mv4_table[xy]=1; + s->co_located_type_table[mb_index]= CO_LOCATED_TYPE_4MV; } else { int motion_x, motion_y; if (s->mb_intra) { motion_x = 0; motion_y = 0; + if(s->co_located_type_table) + s->co_located_type_table[mb_index]= 0; } else if (s->mv_type == MV_TYPE_16X16) { motion_x = s->mv[0][0][0]; motion_y = s->mv[0][0][1]; + if(s->co_located_type_table) + s->co_located_type_table[mb_index]= 0; } else /*if (s->mv_type == MV_TYPE_FIELD)*/ { + int i; motion_x = s->mv[0][0][0] + s->mv[0][1][0]; motion_y = s->mv[0][0][1] + s->mv[0][1][1]; motion_x = (motion_x>>1) | (motion_x&1); + for(i=0; i<2; i++){ + s->field_mv_table[mb_index][i][0]= s->mv[0][i][0]; + s->field_mv_table[mb_index][i][1]= s->mv[0][i][1]; + s->field_select_table[mb_index][i]= s->field_select[0][i]; + } + s->co_located_type_table[mb_index]= CO_LOCATED_TYPE_FIELDMV; } /* no update if 8X8 because it has been done during parsing */ s->motion_val[xy][0] = motion_x; @@ -1490,7 +1508,6 @@ void MPV_decode_mb(MpegEncContext *s, DCTELEM block[6][64]) s->motion_val[xy + wrap][1] = motion_y; s->motion_val[xy + 1 + wrap][0] = motion_x; s->motion_val[xy + 1 + wrap][1] = motion_y; - s->non_b_mv4_table[xy]=0; } } diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 7d62e4fc2b..ee184b1406 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -339,7 +339,9 @@ typedef struct MpegEncContext { INT64 time; /* time of current frame */ INT64 last_non_b_time; UINT16 pp_time; /* time distance between the last 2 p,s,i frames */ - UINT16 bp_time; /* time distance between the last b and p,s,i frame */ + UINT16 pb_time; /* time distance between the last b and p,s,i frame */ + UINT16 pp_field_time; + UINT16 pb_field_time; /* like above, just for interlaced */ int shape; int vol_sprite_usage; int sprite_width; @@ -377,7 +379,12 @@ typedef struct MpegEncContext { uint8_t *tex_pb_buffer; uint8_t *pb2_buffer; int mpeg_quant; - INT8 *non_b_mv4_table; +#define CO_LOCATED_TYPE_4MV 1 +#define CO_LOCATED_TYPE_FIELDMV 2 + INT8 *co_located_type_table; /* 4mv & field_mv info for next b frame */ + INT16 (*field_mv_table)[2][2]; /* used for interlaced b frame decoding */ + INT8 (*field_select_table)[2]; /* wtf, no really another table for interlaced b frames */ + int t_frame; /* time distance of first I -> B, used for interlaced b frames */ /* divx specific, used to workaround (many) bugs in divx5 */ int divx_version;