]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/h264_refs.c
mpegvideo: claim ownership of referenced pictures
[ffmpeg] / libavcodec / h264_refs.c
index ed715c6b03153bc87db037af8afd3fb0ec0fbe7c..273c52b475b0f97071cd394d84d49a0bbdfb19de 100644 (file)
@@ -2,20 +2,20 @@
  * H.26L/H.264/AVC/JVT/14496-10/... reference picture handling
  * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
  *
- * This file is part of FFmpeg.
+ * This file is part of Libav.
  *
- * FFmpeg is free software; you can redistribute it and/or
+ * Libav is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * FFmpeg is distributed in the hope that it will be useful,
+ * Libav is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
+ * License along with Libav; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -39,16 +39,16 @@ static void pic_as_field(Picture *pic, const int parity){
     int i;
     for (i = 0; i < 4; ++i) {
         if (parity == PICT_BOTTOM_FIELD)
-            pic->data[i] += pic->linesize[i];
-        pic->reference = parity;
-        pic->linesize[i] *= 2;
+            pic->f.data[i] += pic->f.linesize[i];
+        pic->f.reference    = parity;
+        pic->f.linesize[i] *= 2;
     }
     pic->poc= pic->field_poc[parity == PICT_BOTTOM_FIELD];
 }
 
 static int split_field_copy(Picture *dest, Picture *src,
                             int parity, int id_add){
-    int match = !!(src->reference & parity);
+    int match = !!(src->f.reference & parity);
 
     if (match) {
         *dest = *src;
@@ -67,9 +67,9 @@ static int build_def_list(Picture *def, Picture **in, int len, int is_long, int
     int index=0;
 
     while(i[0]<len || i[1]<len){
-        while(i[0]<len && !(in[ i[0] ] && (in[ i[0] ]->reference & sel)))
+        while (i[0] < len && !(in[ i[0] ] && (in[ i[0] ]->f.reference & sel)))
             i[0]++;
-        while(i[1]<len && !(in[ i[1] ] && (in[ i[1] ]->reference & (sel^3))))
+        while (i[1] < len && !(in[ i[1] ] && (in[ i[1] ]->f.reference & (sel^3))))
             i[1]++;
         if(i[0] < len){
             in[ i[0] ]->pic_id= is_long ? i[0] : in[ i[0] ]->frame_num;
@@ -109,7 +109,7 @@ int ff_h264_fill_default_ref_list(H264Context *h){
     MpegEncContext * const s = &h->s;
     int i, len;
 
-    if(h->slice_type_nos==FF_B_TYPE){
+    if(h->slice_type_nos==AV_PICTURE_TYPE_B){
         Picture *sorted[32];
         int cur_poc, list;
         int lens[2];
@@ -133,7 +133,7 @@ int ff_h264_fill_default_ref_list(H264Context *h){
         }
 
         if(lens[0] == lens[1] && lens[1] > 1){
-            for(i=0; h->default_ref_list[0][i].data[0] == h->default_ref_list[1][i].data[0] && i<lens[0]; i++);
+            for (i = 0; h->default_ref_list[0][i].f.data[0] == h->default_ref_list[1][i].f.data[0] && i < lens[0]; i++);
             if(i == lens[0])
                 FFSWAP(Picture, h->default_ref_list[1][0], h->default_ref_list[1][1]);
         }
@@ -148,7 +148,7 @@ int ff_h264_fill_default_ref_list(H264Context *h){
     for (i=0; i<h->ref_count[0]; i++) {
         tprintf(h->s.avctx, "List0: %s fn:%d 0x%p\n", (h->default_ref_list[0][i].long_ref ? "LT" : "ST"), h->default_ref_list[0][i].pic_id, h->default_ref_list[0][i].data[0]);
     }
-    if(h->slice_type_nos==FF_B_TYPE){
+    if(h->slice_type_nos==AV_PICTURE_TYPE_B){
         for (i=0; i<h->ref_count[1]; i++) {
             tprintf(h->s.avctx, "List1: %s fn:%d 0x%p\n", (h->default_ref_list[1][i].long_ref ? "LT" : "ST"), h->default_ref_list[1][i].pic_id, h->default_ref_list[1][i].data[0]);
         }
@@ -229,11 +229,11 @@ int ff_h264_decode_ref_pic_list_reordering(H264Context *h){
 
                         for(i= h->short_ref_count-1; i>=0; i--){
                             ref = h->short_ref[i];
-                            assert(ref->reference);
+                            assert(ref->f.reference);
                             assert(!ref->long_ref);
                             if(
                                    ref->frame_num == frame_num &&
-                                   (ref->reference & pic_structure)
+                                   (ref->f.reference & pic_structure)
                               )
                                 break;
                         }
@@ -250,8 +250,8 @@ int ff_h264_decode_ref_pic_list_reordering(H264Context *h){
                             return -1;
                         }
                         ref = h->long_ref[long_idx];
-                        assert(!(ref && !ref->reference));
-                        if(ref && (ref->reference & pic_structure)){
+                        assert(!(ref && !ref->f.reference));
+                        if (ref && (ref->f.reference & pic_structure)) {
                             ref->pic_id= pic_id;
                             assert(ref->long_ref);
                             i=0;
@@ -285,9 +285,9 @@ int ff_h264_decode_ref_pic_list_reordering(H264Context *h){
     }
     for(list=0; list<h->list_count; list++){
         for(index= 0; index < h->ref_count[list]; index++){
-            if(!h->ref_list[list][index].data[0]){
+            if (!h->ref_list[list][index].f.data[0]) {
                 av_log(h->s.avctx, AV_LOG_ERROR, "Missing reference picture\n");
-                if(h->default_ref_list[list][0].data[0])
+                if (h->default_ref_list[list][0].f.data[0])
                     h->ref_list[list][index]= h->default_ref_list[list][0];
                 else
                     return -1;
@@ -306,13 +306,13 @@ void ff_h264_fill_mbaff_ref_list(H264Context *h){
             Picture *field = &h->ref_list[list][16+2*i];
             field[0] = *frame;
             for(j=0; j<3; j++)
-                field[0].linesize[j] <<= 1;
-            field[0].reference = PICT_TOP_FIELD;
+                field[0].f.linesize[j] <<= 1;
+            field[0].f.reference = PICT_TOP_FIELD;
             field[0].poc= field[0].field_poc[0];
             field[1] = field[0];
             for(j=0; j<3; j++)
-                field[1].data[j] += frame->linesize[j];
-            field[1].reference = PICT_BOTTOM_FIELD;
+                field[1].f.data[j] += frame->f.linesize[j];
+            field[1].f.reference = PICT_BOTTOM_FIELD;
             field[1].poc= field[1].field_poc[1];
 
             h->luma_weight[16+2*i][list][0] = h->luma_weight[16+2*i+1][list][0] = h->luma_weight[i][list][0];
@@ -338,12 +338,12 @@ void ff_h264_fill_mbaff_ref_list(H264Context *h){
  */
 static inline int unreference_pic(H264Context *h, Picture *pic, int refmask){
     int i;
-    if (pic->reference &= refmask) {
+    if (pic->f.reference &= refmask) {
         return 0;
     } else {
         for(i = 0; h->delayed_pic[i]; i++)
             if(pic == h->delayed_pic[i]){
-                pic->reference=DELAYED_PIC_REF;
+                pic->f.reference = DELAYED_PIC_REF;
                 break;
             }
         return 1;
@@ -453,7 +453,8 @@ static void print_short_term(H264Context *h) {
         av_log(h->s.avctx, AV_LOG_DEBUG, "short term list:\n");
         for(i=0; i<h->short_ref_count; i++){
             Picture *pic= h->short_ref[i];
-            av_log(h->s.avctx, AV_LOG_DEBUG, "%d fn:%d poc:%d %p\n", i, pic->frame_num, pic->poc, pic->data[0]);
+            av_log(h->s.avctx, AV_LOG_DEBUG, "%d fn:%d poc:%d %p\n",
+                   i, pic->frame_num, pic->poc, pic->f.data[0]);
         }
     }
 }
@@ -468,16 +469,36 @@ static void print_long_term(H264Context *h) {
         for(i = 0; i < 16; i++){
             Picture *pic= h->long_ref[i];
             if (pic) {
-                av_log(h->s.avctx, AV_LOG_DEBUG, "%d fn:%d poc:%d %p\n", i, pic->frame_num, pic->poc, pic->data[0]);
+                av_log(h->s.avctx, AV_LOG_DEBUG, "%d fn:%d poc:%d %p\n",
+                       i, pic->frame_num, pic->poc, pic->f.data[0]);
             }
         }
     }
 }
 
+void ff_generate_sliding_window_mmcos(H264Context *h) {
+    MpegEncContext * const s = &h->s;
+    assert(h->long_ref_count + h->short_ref_count <= h->sps.ref_frame_count);
+
+    h->mmco_index= 0;
+    if(h->short_ref_count && h->long_ref_count + h->short_ref_count == h->sps.ref_frame_count &&
+            !(FIELD_PICTURE && !s->first_field && s->current_picture_ptr->f.reference)) {
+        h->mmco[0].opcode= MMCO_SHORT2UNUSED;
+        h->mmco[0].short_pic_num= h->short_ref[ h->short_ref_count - 1 ]->frame_num;
+        h->mmco_index= 1;
+        if (FIELD_PICTURE) {
+            h->mmco[0].short_pic_num *= 2;
+            h->mmco[1].opcode= MMCO_SHORT2UNUSED;
+            h->mmco[1].short_pic_num= h->mmco[0].short_pic_num + 1;
+            h->mmco_index= 2;
+        }
+    }
+}
+
 int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
     MpegEncContext * const s = &h->s;
     int i, av_uninit(j);
-    int current_ref_assigned=0;
+    int current_ref_assigned=0, err=0;
     Picture *av_uninit(pic);
 
     if((s->avctx->debug&FF_DEBUG_MMCO) && mmco_count==0)
@@ -494,8 +515,10 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
             pic = find_short(h, frame_num, &j);
             if(!pic){
                 if(mmco[i].opcode != MMCO_SHORT2LONG || !h->long_ref[mmco[i].long_arg]
-                   || h->long_ref[mmco[i].long_arg]->frame_num != frame_num)
-                av_log(h->s.avctx, AV_LOG_ERROR, "mmco: unref short failure\n");
+                   || h->long_ref[mmco[i].long_arg]->frame_num != frame_num) {
+                    av_log(h->s.avctx, AV_LOG_ERROR, "mmco: unref short failure\n");
+                    err = AVERROR_INVALIDDATA;
+                }
                 continue;
             }
         }
@@ -542,7 +565,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
                 h->long_ref_count++;
             }
 
-            s->current_picture_ptr->reference |= s->picture_structure;
+            s->current_picture_ptr->f.reference |= s->picture_structure;
             current_ref_assigned=1;
             break;
         case MMCO_SET_MAX_LONG:
@@ -559,13 +582,9 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
             for(j = 0; j < 16; j++) {
                 remove_long(h, j, 0);
             }
-            s->current_picture_ptr->poc=
-            s->current_picture_ptr->field_poc[0]=
-            s->current_picture_ptr->field_poc[1]=
-            h->poc_lsb=
-            h->poc_msb=
             h->frame_num=
             s->current_picture_ptr->frame_num= 0;
+            h->mmco_reset = 1;
             s->current_picture_ptr->mmco_reset=1;
             break;
         default: assert(0);
@@ -581,16 +600,18 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
          */
         if (h->short_ref_count && h->short_ref[0] == s->current_picture_ptr) {
             /* Just mark the second field valid */
-            s->current_picture_ptr->reference = PICT_FRAME;
+            s->current_picture_ptr->f.reference = PICT_FRAME;
         } else if (s->current_picture_ptr->long_ref) {
             av_log(h->s.avctx, AV_LOG_ERROR, "illegal short term reference "
                                              "assignment for second field "
                                              "in complementary field pair "
                                              "(first field is long term)\n");
+            err = AVERROR_INVALIDDATA;
         } else {
             pic= remove_short(h, s->current_picture_ptr->frame_num, 0);
             if(pic){
                 av_log(h->s.avctx, AV_LOG_ERROR, "illegal short term buffer state detected\n");
+                err = AVERROR_INVALIDDATA;
             }
 
             if(h->short_ref_count)
@@ -598,19 +619,22 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
 
             h->short_ref[0]= s->current_picture_ptr;
             h->short_ref_count++;
-            s->current_picture_ptr->reference |= s->picture_structure;
+            s->current_picture_ptr->f.reference |= s->picture_structure;
         }
     }
 
-    if (h->long_ref_count + h->short_ref_count > h->sps.ref_frame_count){
+    if (h->long_ref_count + h->short_ref_count -
+            (h->short_ref[0] == s->current_picture_ptr) > h->sps.ref_frame_count){
 
         /* We have too many reference frames, probably due to corrupted
          * stream. Need to discard one frame. Prevents overrun of the
          * short_ref and long_ref buffers.
          */
         av_log(h->s.avctx, AV_LOG_ERROR,
-               "number of reference frames exceeds max (probably "
-               "corrupt input), discarding one\n");
+               "number of reference frames (%d+%d) exceeds max (%d; probably "
+               "corrupt input), discarding one\n",
+               h->long_ref_count, h->short_ref_count, h->sps.ref_frame_count);
+        err = AVERROR_INVALIDDATA;
 
         if (h->long_ref_count && !h->short_ref_count) {
             for (i = 0; i < 16; ++i)
@@ -627,7 +651,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
 
     print_short_term(h);
     print_long_term(h);
-    return 0;
+    return (h->s.avctx->err_recognition & AV_EF_EXPLODE) ? err : 0;
 }
 
 int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb){
@@ -657,7 +681,7 @@ int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb){
                 }
                 if(opcode==MMCO_SHORT2LONG || opcode==MMCO_LONG2UNUSED || opcode==MMCO_LONG || opcode==MMCO_SET_MAX_LONG){
                     unsigned int long_arg= get_ue_golomb_31(gb);
-                    if(long_arg >= 32 || (long_arg >= 16 && !(opcode == MMCO_LONG2UNUSED && FIELD_PICTURE))){
+                    if(long_arg >= 32 || (long_arg >= 16 && !(opcode == MMCO_SET_MAX_LONG && long_arg == 16) && !(opcode == MMCO_LONG2UNUSED && FIELD_PICTURE))){
                         av_log(h->s.avctx, AV_LOG_ERROR, "illegal long ref in memory management control operation %d\n", opcode);
                         return -1;
                     }
@@ -673,20 +697,7 @@ int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb){
             }
             h->mmco_index= i;
         }else{
-            assert(h->long_ref_count + h->short_ref_count <= h->sps.ref_frame_count);
-
-            if(h->short_ref_count && h->long_ref_count + h->short_ref_count == h->sps.ref_frame_count &&
-                    !(FIELD_PICTURE && !s->first_field && s->current_picture_ptr->reference)) {
-                h->mmco[0].opcode= MMCO_SHORT2UNUSED;
-                h->mmco[0].short_pic_num= h->short_ref[ h->short_ref_count - 1 ]->frame_num;
-                h->mmco_index= 1;
-                if (FIELD_PICTURE) {
-                    h->mmco[0].short_pic_num *= 2;
-                    h->mmco[1].opcode= MMCO_SHORT2UNUSED;
-                    h->mmco[1].short_pic_num= h->mmco[0].short_pic_num + 1;
-                    h->mmco_index= 2;
-                }
-            }
+            ff_generate_sliding_window_mmcos(h);
         }
     }