changeset 2392:299f2d85d27d libavcodec

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 <lll+ffmpeg >at< m4x org>)
author michael
date Sat, 18 Dec 2004 03:49:07 +0000
parents 336a239ad9a4
children 0433866b1075
files h264.c
diffstat 1 files changed, 46 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/h264.c	Sat Dec 18 03:07:15 2004 +0000
+++ b/h264.c	Sat Dec 18 03:49:07 2004 +0000
@@ -340,8 +340,8 @@
 
 /**
  * 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 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 @@
     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 @@
 }
 
 /**
- * instantaneos decoder refresh.
+ * instantaneous decoder refresh.
  */
 static void idr(H264Context *h){
     int i;
@@ -3001,6 +3003,7 @@
     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 @@
     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 @@
         }
     }
 
-    if(first_mb_in_slice == 0){
+    if(h->slice_num == 0){
         frame_start(h);
     }
 
@@ -3136,7 +3139,7 @@
         }
     }
 
-    if(first_mb_in_slice == 0){
+    if(h->slice_num == 0){
         fill_default_ref_list(h);
     }
 
@@ -3185,9 +3188,11 @@
         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 @@
          //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 @@
             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 @@
             }
 
             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 @@
  * 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; i<buf_size; i++){
-        state= (state<<8) | buf[i];
+    for(i=0; i<=buf_size; i++){
         if((state&0xFFFFFF1F) == 0x101 || (state&0xFFFFFF1F) == 0x102 || (state&0xFFFFFF1F) == 0x105){
+            tprintf("find_frame_end new startcode = %08x, frame_start_found = %d, pos = %d\n", state, pc->frame_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 (i<buf_size)
+            state= (state<<8) | buf[i];
     }
     
     pc->state= state;
@@ -5520,10 +5536,11 @@
                       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 @@
         printf("%X ", buf[i]);
     }
 #endif
+    h->slice_num = 0;
     for(;;){
         int consumed;
         int dst_length;
@@ -5704,7 +5722,7 @@
     }
     
     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 @@
 #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 @@
 
 AVCodecParser h264_parser = {
     { CODEC_ID_H264 },
-    sizeof(ParseContext),
+    sizeof(H264Context),
     NULL,
     h264_parse,
     ff_parse_close,