OSDN Git Service

- patch a reference picture leak in ffmpeg/libavcodec/mpegvideo.c that caused aborts...
authorvan <van@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Mon, 18 Aug 2008 01:54:15 +0000 (01:54 +0000)
committervan <van@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Mon, 18 Aug 2008 01:54:15 +0000 (01:54 +0000)
 - patch the log level of some h264 decoder error messages so we don't fill our log with messages about stuff that's a very likely & not terribly significant.
 - don't let hb.c set the ffmpeg av_log level to AV_LOG_DEBUG -- it fills the HB activity log with junk.
 - add a count of the decoder errors to decavcodec's final report.
 - when we don't have any chapter text (i.e., during a typical cli encode) just print the chapter number rather than empty quote marks.

git-svn-id: svn://localhost/HandBrake/trunk@1639 b64f7644-9d1e-0410-96f1-a4d463321fa5

contrib/Jamfile
contrib/patch-ffmpeg-mpegleak.patch [new file with mode: 0644]
libhb/decavcodec.c
libhb/hb.c

index 4a87190..98b310b 100644 (file)
@@ -79,6 +79,7 @@ rule LibAvCodec
 {
     FFMPEG_PATCH = "$(PATCH) -p0 < ../patch-ffmpeg.patch" ;
     FFMPEG_PATCH += " && $(PATCH) -p0 < ../patch-ffmpeg-latm.patch " ;
+    FFMPEG_PATCH += " && $(PATCH) -p0 < ../patch-ffmpeg-mpegleak.patch " ;
     if $(OS) = CYGWIN
     {
         FFMPEG_PATCH += " && $(PATCH) -p1 < ../patch-ffmpeg-cygwin.patch " ;
diff --git a/contrib/patch-ffmpeg-mpegleak.patch b/contrib/patch-ffmpeg-mpegleak.patch
new file mode 100644 (file)
index 0000000..8853892
--- /dev/null
@@ -0,0 +1,71 @@
+Index: libavcodec/h264.c
+===================================================================
+--- libavcodec/h264.c  (revision 14820)
++++ libavcodec/h264.c  (working copy)
+@@ -3355,7 +3355,7 @@
+          * stream. Need to discard one frame. Prevents overrun of the
+          * short_ref and long_ref buffers.
+          */
+-        av_log(h->s.avctx, AV_LOG_ERROR,
++        av_log(h->s.avctx, AV_LOG_DEBUG,
+                "number of reference frames exceeds max (probably "
+                "corrupt input), discarding one\n");
+@@ -7557,7 +7557,7 @@
+     if(!(s->flags2 & CODEC_FLAG2_CHUNKS) && !s->current_picture_ptr){
+         if (avctx->skip_frame >= AVDISCARD_NONREF || s->hurry_up) return 0;
+-        av_log(avctx, AV_LOG_ERROR, "no frame!\n");
++        av_log(avctx, AV_LOG_DEBUG, "no frame!\n");
+         return -1;
+     }
+Index: libavcodec/mpegvideo.c
+===================================================================
+--- libavcodec/mpegvideo.c     (revision 14820)
++++ libavcodec/mpegvideo.c     (working copy)
+@@ -772,6 +772,15 @@
+     }else{
+         for(i=0; i<MAX_PICTURE_COUNT; i++){
+             if(s->picture[i].data[0]==NULL && s->picture[i].type!=0) return i; //FIXME
++            /* XXX there seems to be a leak caused by h264 in mpeg transport
++             * streams: Over-the-air streams have a lot of errors. A picture
++             * may be marked as referenced but the actual references get lost
++             * so it never gets released. We take care of that here by purging
++             * pictures that are impossibly old.
++             */
++            if (s->coded_picture_number - s->picture[i].coded_picture_number >
++                32*MAX_PICTURE_COUNT)
++                s->avctx->release_buffer(s->avctx, (AVFrame*)&s->picture[i]);
+         }
+         for(i=0; i<MAX_PICTURE_COUNT; i++){
+             if(s->picture[i].data[0]==NULL) return i;
+@@ -779,19 +788,15 @@
+     }
+     av_log(s->avctx, AV_LOG_FATAL, "Internal error, picture buffer overflow\n");
+-    /* We could return -1, but the codec would crash trying to draw into a
+-     * non-existing frame anyway. This is safer than waiting for a random crash.
+-     * Also the return of this is never useful, an encoder must only allocate
+-     * as much as allowed in the specification. This has no relationship to how
+-     * much libavcodec could allocate (and MAX_PICTURE_COUNT is always large
+-     * enough for such valid streams).
+-     * Plus, a decoder has to check stream validity and remove frames if too
+-     * many reference frames are around. Waiting for "OOM" is not correct at
+-     * all. Similarly, missing reference frames have to be replaced by
+-     * interpolated/MC frames, anything else is a bug in the codec ...
+-     */
+-    abort();
+-    return -1;
++    /* assume that we don't have a picture because of the leak described above.
++     * just release the oldest we have & reuse its slot. */
++    int oldest=0;
++    for(i=0; i<MAX_PICTURE_COUNT; i++){
++        if (s->picture[i].coded_picture_number < s->picture[oldest].coded_picture_number)
++            oldest = i;
++    }
++    s->avctx->release_buffer(s->avctx, (AVFrame*)&s->picture[oldest]);
++    return oldest;
+ }
+ static void update_noise_reduction(MpegEncContext *s){
index a945680..62eca65 100644 (file)
@@ -92,8 +92,9 @@ struct hb_work_private_s
     int64_t              chap_time; // time of next chap mark (if new_chap != 0)
     int                  new_chap;
     int                  ignore_pts; // workaround M$ bugs
-    int                  nframes;
-    int                  ndrops;
+    uint32_t             nframes;
+    uint32_t             ndrops;
+    uint32_t             decode_errors;
     double               duration;  // frame duration (for video)
 };
 
@@ -340,8 +341,16 @@ static int get_frame_buf( AVCodecContext *context, AVFrame *frame )
 static void log_chapter( hb_work_private_t *pv, int chap_num, int64_t pts )
 {
     hb_chapter_t *c = hb_list_item( pv->job->title->list_chapter, chap_num - 1 );
-    hb_log( "%s: \"%s\" (%d) at frame %u time %lld", pv->context->codec->name,
-            c->title, chap_num, pv->nframes, pts );
+    if ( c && c->title )
+    {
+        hb_log( "%s: \"%s\" (%d) at frame %u time %lld",
+                pv->context->codec->name, c->title, chap_num, pv->nframes, pts );
+    }
+    else
+    {
+        hb_log( "%s: Chapter %d at frame %u time %lld",
+                pv->context->codec->name, chap_num, pv->nframes, pts );
+    }
 }
 
 static int decodeFrame( hb_work_private_t *pv, uint8_t *data, int size )
@@ -349,7 +358,10 @@ static int decodeFrame( hb_work_private_t *pv, uint8_t *data, int size )
     int got_picture;
     AVFrame frame;
 
-    avcodec_decode_video( pv->context, &frame, &got_picture, data, size );
+    if ( avcodec_decode_video( pv->context, &frame, &got_picture, data, size ) < 0 )
+    {
+        ++pv->decode_errors;     
+    }
     if( got_picture )
     {
         // ffmpeg makes it hard to attach a pts to a frame. if the MPEG ES
@@ -498,7 +510,8 @@ static int decavcodecvWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
         decodeVideo( pv, in->data, in->size, pts, dts );
         hb_list_add( pv->list, in );
         *buf_out = link_buf_list( pv );
-        hb_log( "%s done: %d frames", pv->context->codec->name, pv->nframes );
+        hb_log( "%s done: %u frames, %u decoder errors",
+                pv->context->codec->name, pv->nframes, pv->decode_errors );
         return HB_WORK_DONE;
     }
 
@@ -710,8 +723,9 @@ static int decavcodecviWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
         }
         hb_list_add( pv->list, in );
         *buf_out = link_buf_list( pv );
-        hb_log( "%s done: %d frames %d drops", pv->context->codec->name,
-                pv->nframes, pv->ndrops );
+        hb_log( "%s done: %u frames, %u decoder errors, %u drops",
+                pv->context->codec->name, pv->nframes, pv->decode_errors,
+                pv->ndrops );
         return HB_WORK_DONE;
     }
 
index 0e0bddb..f73a243 100644 (file)
@@ -73,7 +73,6 @@ hb_handle_t * hb_init_real( int verbose, int update_check )
     if( verbose > HB_DEBUG_NONE )
     {
         putenv( "HB_DEBUG=1" );
-               av_log_set_level(AV_LOG_DEBUG);
     }
 
     /* Check for an update on the website if asked to */
@@ -153,7 +152,6 @@ hb_handle_t * hb_init_dl( int verbose, int update_check )
     if( verbose > HB_DEBUG_NONE )
     {
         putenv( "HB_DEBUG=1" );
-               av_log_set_level(AV_LOG_DEBUG);
     }
 
     /* Check for an update on the website if asked to */