From 5175b9376f733735322a0272e94bd996ac157dea Mon Sep 17 00:00:00 2001 From: Loic Le Loarer Date: Sat, 18 Dec 2004 03:49:07 +0000 Subject: add multi slice support for main profile H.264 streams. I have tested this on all H264 conformance streams and comparing the result with the current CVS version, there is 8 streams which decode correctly more frames and 2 streams which are now completely correct with my patch. This patch also correct some typo in comments. patch by (Loic Le Loarer at< m4x org>) Originally committed as revision 3758 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/h264.c | 74 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 28 deletions(-) (limited to 'libavcodec/h264.c') diff --git a/libavcodec/h264.c b/libavcodec/h264.c index 11b58ee538..e672028cd0 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -340,8 +340,8 @@ static inline uint32_t pack16to32(int a, int b){ /** * fill a rectangle. - * @param h height of the recatangle, should be a constant - * @param w width of the recatangle, should be a constant + * @param h height of the rectangle, should be a constant + * @param w width of the rectangle, should be a constant * @param size the size of val (1 or 4), should be a constant */ static inline void fill_rectangle(void *vp, int w, int h, int stride, uint32_t val, int size){ //FIXME ensure this IS inlined @@ -760,8 +760,10 @@ static inline int check_intra_pred_mode(H264Context *h, int mode){ static const int8_t top [7]= {LEFT_DC_PRED8x8, 1,-1,-1}; static const int8_t left[7]= { TOP_DC_PRED8x8,-1, 2,-1,DC_128_PRED8x8}; - if(mode < 0 || mode > 6) + if(mode < 0 || mode > 6) { + av_log(h->s.avctx, AV_LOG_ERROR, "out of range intra chroma pred mode at %d %d\n", s->mb_x, s->mb_y); return -1; + } if(!(h->top_samples_available&0x8000)){ mode= top[ mode ]; @@ -980,7 +982,7 @@ static inline void pred_pskip_motion(H264Context * const h, int * const mx, int const int top_ref = h->ref_cache[0][ scan8[0] - 8 ]; const int left_ref= h->ref_cache[0][ scan8[0] - 1 ]; - tprintf("pred_pskip: (%d) (%d) at %2d %2d", top_ref, left_ref, h->s.mb_x, h->s.mb_y); + tprintf("pred_pskip: (%d) (%d) at %2d %2d\n", top_ref, left_ref, h->s.mb_x, h->s.mb_y); if(top_ref == PART_NOT_AVAILABLE || left_ref == PART_NOT_AVAILABLE || (top_ref == 0 && *(uint32_t*)h->mv_cache[0][ scan8[0] - 8 ] == 0) @@ -2696,7 +2698,7 @@ static int pred_weight_table(H264Context *h){ } /** - * instantaneos decoder refresh. + * instantaneous decoder refresh. */ static void idr(H264Context *h){ int i; @@ -3001,6 +3003,7 @@ static int decode_slice_header(H264Context *h){ h->slice_type= get_ue_golomb(&s->gb); if(h->slice_type > 9){ av_log(h->s.avctx, AV_LOG_ERROR, "slice type too large (%d) at %d %d\n", h->slice_type, s->mb_x, s->mb_y); + return -1; } if(h->slice_type > 4){ h->slice_type -= 5; @@ -3035,8 +3038,8 @@ static int decode_slice_header(H264Context *h){ h->b_stride= s->mb_width*4; h->b8_stride= s->mb_width*2; - s->mb_x = first_mb_in_slice % s->mb_width; - s->mb_y = first_mb_in_slice / s->mb_width; //FIXME AFFW + s->resync_mb_x = s->mb_x = first_mb_in_slice % s->mb_width; + s->resync_mb_y = s->mb_y = first_mb_in_slice / s->mb_width; //FIXME AFFW s->width = 16*s->mb_width - 2*(h->sps.crop_left + h->sps.crop_right ); if(h->sps.frame_mbs_only_flag) @@ -3065,7 +3068,7 @@ static int decode_slice_header(H264Context *h){ } } - if(first_mb_in_slice == 0){ + if(h->slice_num == 0){ frame_start(h); } @@ -3136,7 +3139,7 @@ static int decode_slice_header(H264Context *h){ } } - if(first_mb_in_slice == 0){ + if(h->slice_num == 0){ fill_default_ref_list(h); } @@ -3185,9 +3188,11 @@ static int decode_slice_header(H264Context *h){ slice_group_change_cycle= get_bits(&s->gb, ?); #endif + h->slice_num++; + if(s->avctx->debug&FF_DEBUG_PICT_INFO){ - av_log(h->s.avctx, AV_LOG_DEBUG, "mb:%d %c pps:%d frame:%d poc:%d/%d ref:%d/%d qp:%d loop:%d\n", - first_mb_in_slice, + av_log(h->s.avctx, AV_LOG_DEBUG, "slice:%d mb:%d %c pps:%d frame:%d poc:%d/%d ref:%d/%d qp:%d loop:%d\n", + h->slice_num, first_mb_in_slice, av_get_pict_type_char(h->slice_type), pps_id, h->frame_num, s->current_picture_ptr->field_poc[0], s->current_picture_ptr->field_poc[1], @@ -3619,7 +3624,7 @@ decode_intra_mb: //FIXME we should set ref_idx_l? to 0 if we use that later ... if(IS_16X16(mb_type)){ for(list=0; list<2; list++){ - if(h->ref_count[0]>0){ + if(h->ref_count[list]>0){ if(IS_DIR(mb_type, 0, list)){ const int val= get_te0_golomb(&s->gb, h->ref_count[list]); fill_rectangle(&h->ref_cache[list][ scan8[0] ], 4, 4, 8, val, 1); @@ -5126,12 +5131,11 @@ static int decode_slice(H264Context *h){ if( ++s->mb_x >= s->mb_width ) { s->mb_x = 0; ff_draw_horiz_band(s, 16*s->mb_y, 16); - if( ++s->mb_y >= s->mb_height ) { - tprintf("slice end %d %d\n", get_bits_count(&s->gb), s->gb.size_in_bits); - } + ++s->mb_y; } if( eos || s->mb_y >= s->mb_height ) { + tprintf("slice end %d %d\n", get_bits_count(&s->gb), s->gb.size_in_bits); ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, (AC_END|DC_END|MV_END)&part_mask); return 0; } @@ -5184,6 +5188,7 @@ static int decode_slice(H264Context *h){ } if(get_bits_count(&s->gb) >= s->gb.size_in_bits && s->mb_skip_run<=0){ + tprintf("slice end %d %d\n", get_bits_count(&s->gb), s->gb.size_in_bits); if(get_bits_count(&s->gb) == s->gb.size_in_bits ){ ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, (AC_END|DC_END|MV_END)&part_mask); @@ -5492,23 +5497,34 @@ static inline int decode_picture_parameter_set(H264Context *h){ * finds the end of the current frame in the bitstream. * @return the position of the first byte of the next frame, or -1 */ -static int find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size){ +static int find_frame_end(H264Context *h, const uint8_t *buf, int buf_size){ int i; uint32_t state; + ParseContext *pc = &(h->s.parse_context); //printf("first %02X%02X%02X%02X\n", buf[0], buf[1],buf[2],buf[3]); // mb_addr= pc->mb_addr - 1; state= pc->state; - //FIXME this will fail with slices - for(i=0; iframe_start_found, i); if(pc->frame_start_found){ - pc->state=-1; - pc->frame_start_found= 0; - return i-3; + // If there isn't one more byte in the buffer + // the test on first_mb_in_slice cannot be done yet + // do it at next call. + if (i >= buf_size) break; + if (buf[i] & 0x80) { + // first_mb_in_slice is 0, probably the first nal of a new + // slice + tprintf("find_frame_end frame_end_found, state = %08x, pos = %d\n", state, i); + pc->state=-1; + pc->frame_start_found= 0; + return i-4; + } } - pc->frame_start_found= 1; + pc->frame_start_found = 1; } + if (istate= state; @@ -5520,10 +5536,11 @@ static int h264_parse(AVCodecParserContext *s, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size) { - ParseContext *pc = s->priv_data; + H264Context *h = s->priv_data; + ParseContext *pc = &h->s.parse_context; int next; - next= find_frame_end(pc, buf, buf_size); + next= find_frame_end(h, buf, buf_size); if (ff_combine_frame(pc, next, (uint8_t **)&buf, &buf_size) < 0) { *poutbuf = NULL; @@ -5546,6 +5563,7 @@ static int decode_nal_units(H264Context *h, uint8_t *buf, int buf_size){ printf("%X ", buf[i]); } #endif + h->slice_num = 0; for(;;){ int consumed; int dst_length; @@ -5704,7 +5722,7 @@ static int decode_frame(AVCodecContext *avctx, } if(s->flags&CODEC_FLAG_TRUNCATED){ - int next= find_frame_end(&s->parse_context, buf, buf_size); + int next= find_frame_end(h, buf, buf_size); if( ff_combine_frame(&s->parse_context, next, &buf, &buf_size) < 0 ) return buf_size; @@ -5789,7 +5807,7 @@ static int decode_frame(AVCodecContext *avctx, #if 0 /* dont output the last pic after seeking */ if(s->last_picture_ptr || s->low_delay) - //Note this isnt a issue as a IDR pic should flush teh buffers + //Note this isnt a issue as a IDR pic should flush the buffers #endif *data_size = sizeof(AVFrame); return get_consumed_bytes(s, buf_index, buf_size); @@ -6016,7 +6034,7 @@ AVCodec h264_decoder = { AVCodecParser h264_parser = { { CODEC_ID_H264 }, - sizeof(ParseContext), + sizeof(H264Context), NULL, h264_parse, ff_parse_close, -- cgit v1.2.3