# HG changeset patch # User michaelni # Date 1023020188 0 # Node ID eda22d628b2d358ab69c06a8f291f375c69a5617 # Parent 69876443a723b9167d70277b5723160154667cb7 error concealment / error resilience merging s->first_gob_line & s->first_slice_line diff -r 69876443a723 -r eda22d628b2d h263dec.c --- a/h263dec.c Sun Jun 02 12:15:17 2002 +0000 +++ b/h263dec.c Sun Jun 02 12:16:28 2002 +0000 @@ -49,7 +49,7 @@ switch(avctx->codec->id) { case CODEC_ID_H263: s->gob_number = 0; - s->first_gob_line = 0; + s->first_slice_line = 0; break; case CODEC_ID_MPEG4: s->time_increment_bits = 4; /* default value for broken headers */ @@ -122,7 +122,9 @@ #endif s->hurry_up= avctx->hurry_up; - + s->error_resilience= avctx->error_resilience; + s->workaround_bugs= avctx->workaround_bugs; + /* no supplementary picture */ if (buf_size == 0) { *data_size = 0; @@ -165,19 +167,33 @@ } if(ret==FRAME_SKIPED) return 0; + /* skip if the header was thrashed */ if (ret < 0) return -1; /* skip b frames if we dont have reference frames */ if(s->num_available_buffers<2 && s->pict_type==B_TYPE) return 0; /* skip b frames if we are in a hurry */ if(s->hurry_up && s->pict_type==B_TYPE) return 0; - + + if(s->next_p_frame_damaged){ + if(s->pict_type==B_TYPE) + return 0; + else + s->next_p_frame_damaged=0; + } + MPV_frame_start(s); #ifdef DEBUG printf("qscale=%d\n", s->qscale); #endif + /* init resync/ error resilience specific variables */ + s->next_resync_qscale= s->qscale; + s->next_resync_gb= s->gb; + if(s->resync_marker) s->mb_num_left= 0; + else s->mb_num_left= s->mb_num; + /* decode each macroblock */ s->block_wrap[0]= s->block_wrap[1]= @@ -190,7 +206,13 @@ /* FIXME: In the future H.263+ will have intra prediction */ /* and we are gonna need another way to detect MPEG4 */ if (s->mb_y && !s->h263_pred) { - s->first_gob_line = h263_decode_gob_header(s); + s->first_slice_line = h263_decode_gob_header(s); + } + + if(s->msmpeg4_version==1){ + s->last_dc[0]= + s->last_dc[1]= + s->last_dc[2]= 128; } s->block_index[0]= s->block_wrap[0]*(s->mb_y*2 + 1) - 1; @@ -209,9 +231,40 @@ #ifdef DEBUG printf("**mb x=%d y=%d\n", s->mb_x, s->mb_y); #endif + + if(s->resync_marker){ + if(s->mb_num_left<=0){ + /* except the first block */ + if(s->mb_x!=0 || s->mb_y!=0){ + /* did we miss the next resync marker without noticing an error yet */ + if(((get_bits_count(&s->gb)+8)&(~7)) != s->next_resync_pos && s->decoding_error==0){ + fprintf(stderr, "slice end missmatch x:%d y:%d %d %d\n", + s->mb_x, s->mb_y, get_bits_count(&s->gb), s->next_resync_pos); + ff_conceal_past_errors(s, 1); + } + } + s->qscale= s->next_resync_qscale; + s->gb= s->next_resync_gb; + s->resync_mb_x= s->mb_x; //we know that the marker is here cuz mb_num_left was the distance to it + s->resync_mb_y= s->mb_y; + s->first_slice_line=1; + + if(s->codec_id==CODEC_ID_MPEG4){ + ff_mpeg4_clean_buffers(s); + ff_mpeg4_resync(s); + } + } + + if( s->resync_mb_x==s->mb_x + && s->resync_mb_y==s->mb_y && s->decoding_error!=0){ + fprintf(stderr, "resynced at %d %d\n", s->mb_x, s->mb_y); + s->decoding_error= 0; + } + } + //fprintf(stderr,"\nFrame: %d\tMB: %d",avctx->frame_number, (s->mb_y * s->mb_width) + s->mb_x); /* DCT & quantize */ - if (s->h263_pred && s->msmpeg4_version!=2) { + if (s->h263_pred && !(s->msmpeg4_version==1 || s->msmpeg4_version==2)) { /* old ffmpeg encoded msmpeg4v3 workaround */ if(s->workaround_bugs==1 && s->msmpeg4_version==3) ff_old_msmpeg4_dc_scale(s); @@ -222,22 +275,48 @@ s->y_dc_scale = 8; s->c_dc_scale = 8; } - clear_blocks(s->block[0]); + + if(s->decoding_error!=DECODING_DESYNC){ + int last_error= s->decoding_error; + clear_blocks(s->block[0]); - s->mv_dir = MV_DIR_FORWARD; - s->mv_type = MV_TYPE_16X16; - if (s->h263_msmpeg4) { - if (msmpeg4_decode_mb(s, s->block) < 0) { - fprintf(stderr,"\nError at MB: %d\n", (s->mb_y * s->mb_width) + s->mb_x); - return -1; - } - } else { - if (h263_decode_mb(s, s->block) < 0) { - fprintf(stderr,"\nError at MB: %d\n", (s->mb_y * s->mb_width) + s->mb_x); - return -1; + s->mv_dir = MV_DIR_FORWARD; + s->mv_type = MV_TYPE_16X16; + if (s->h263_msmpeg4) { + if (msmpeg4_decode_mb(s, s->block) < 0) { + fprintf(stderr,"Error at MB: %d\n", (s->mb_y * s->mb_width) + s->mb_x); + s->decoding_error=DECODING_DESYNC; + } + } else { + if (h263_decode_mb(s, s->block) < 0) { + fprintf(stderr,"Error at MB: %d\n", (s->mb_y * s->mb_width) + s->mb_x); + s->decoding_error=DECODING_DESYNC; + } + } + + if(s->decoding_error!=last_error){ + ff_conceal_past_errors(s, 0); } } + + /* conceal errors */ + if( s->decoding_error==DECODING_DESYNC + || (s->decoding_error==DECODING_ACDC_LOST && s->mb_intra)){ + s->mv_dir = MV_DIR_FORWARD; + s->mv_type = MV_TYPE_16X16; + s->mb_skiped=0; + s->mb_intra=0; + s->mv[0][0][0]=0; //FIXME this is not optimal + s->mv[0][0][1]=0; + clear_blocks(s->block[0]); + }else if(s->decoding_error && !s->mb_intra){ + clear_blocks(s->block[0]); + } + //FIXME remove AC for intra + MPV_decode_mb(s, s->block); + + s->mb_num_left--; } if ( avctx->draw_horiz_band && (s->num_available_buffers>=1 || (!s->has_b_frames)) ) { @@ -267,11 +346,40 @@ /* divx 5.01+ bistream reorder stuff */ if(s->codec_id==CODEC_ID_MPEG4 && s->bitstream_buffer_size==0){ - int current_pos= get_bits_count(&s->gb)/8; + int current_pos= get_bits_count(&s->gb)>>3; + if( buf_size - current_pos > 5 && buf_size - current_pos < BITSTREAM_BUFFER_SIZE){ - memcpy(s->bitstream_buffer, buf + current_pos, buf_size - current_pos); - s->bitstream_buffer_size= buf_size - current_pos; + int i; + int startcode_found=0; + for(i=current_pos; ibitstream_buffer, buf + current_pos, buf_size - current_pos); + s->bitstream_buffer_size= buf_size - current_pos; + } + } + } + + if(s->bitstream_buffer_size==0 && s->error_resilience>0){ + int left= s->gb.size*8 - get_bits_count(&s->gb); + int max_extra=8; + + if(s->codec_id==CODEC_ID_MPEG4) max_extra+=32; + + if(left>max_extra){ + fprintf(stderr, "discarding %d junk bits at end, next would be %X\n", left, show_bits(&s->gb, 24)); + if(s->decoding_error==0) + ff_conceal_past_errors(s, 1); + } + if(left<0){ + fprintf(stderr, "overreading %d bits\n", -left); + if(s->decoding_error==0) + ff_conceal_past_errors(s, 1); } }