[FFmpeg-devel,2/2] avcodec/h264: fix draw_horiz_band with slice threads

Submitted by James Darnley on Sept. 2, 2019, 2:28 p.m.

Details

Message ID 20190902142853.31171-3-jdarnley@obe.tv
State New
Headers show

Commit Message

James Darnley Sept. 2, 2019, 2:28 p.m.
From: Kieran Kunhya <kierank@obe.tv>

---
 libavcodec/h264_slice.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

Comments

Michael Niedermayer Sept. 3, 2019, 8:53 p.m.
On Mon, Sep 02, 2019 at 04:28:53PM +0200, James Darnley wrote:
> From: Kieran Kunhya <kierank@obe.tv>
> 
> ---
>  libavcodec/h264_slice.c | 29 +++++++++++++++++++++++------
>  1 file changed, 23 insertions(+), 6 deletions(-)

with this:
./ffmpeg -i Deep%20Blue.ts -t 1 -vsync 1 -bitexact -an -f framecrc -

output is different on each run
was the same before this patch

https://samples.ffmpeg.org/ffmpeg-bugs/trac/ticket697/Deep%2520Blue-short.ts

Thanks
[...]

Patch hide | download patch | download mbox

diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 5ceee107a0..fe2aa01ceb 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -2527,18 +2527,33 @@  static void predict_field_decoding_flag(const H264Context *h, H264SliceContext *
 /**
  * Draw edges and report progress for the last MB row.
  */
-static void decode_finish_row(const H264Context *h, H264SliceContext *sl)
+static void decode_finish_row(const H264Context *h, H264SliceContext *sl, int slice_end)
 {
     int top            = 16 * (sl->mb_y      >> FIELD_PICTURE(h));
     int pic_height     = 16 *  h->mb_height >> FIELD_PICTURE(h);
     int height         =  16      << FRAME_MBAFF(h);
     int deblock_border = (16 + 4) << FRAME_MBAFF(h);
 
-    if (sl->deblocking_filter) {
+    /* Slice-threaded draw_horiz_band not useful in this situation */
+    if (sl->deblocking_filter == 1) {
         if ((top + height) >= pic_height)
             height += deblock_border;
         top -= deblock_border;
     }
+    else if (sl->deblocking_filter == 2) {
+        int first_mb_y = sl->first_mb_addr / h->mb_width;
+
+        /* Draw the whole slice if it's possible:
+         * - If the beginning of the slice is at the start of a row
+         * - If we are at the end of the slice
+         * Previous slice is guaranteed not be included. */
+        if (!(sl->first_mb_addr % h->mb_width)) {
+            if (slice_end) {
+                top = 16 * (first_mb_y >> FIELD_PICTURE(h));
+                height = (16 << FRAME_MBAFF(h)) * ((sl->mb_y+1) - first_mb_y);
+            }
+        }
+    }
 
     if (top >= pic_height || (top + height) < 0)
         return;
@@ -2549,7 +2564,8 @@  static void decode_finish_row(const H264Context *h, H264SliceContext *sl)
         top    = 0;
     }
 
-    ff_h264_draw_horiz_band(h, sl, top, height);
+    if (slice_end)
+        ff_h264_draw_horiz_band(h, sl, top, height);
 
     if (h->droppable || sl->h264->slice_ctx[0].er.error_occurred)
         return;
@@ -2622,7 +2638,7 @@  static int decode_slice(struct AVCodecContext *avctx, void *arg)
 
         for (;;) {
             // START_TIMER
-            int ret, eos;
+            int ret, eos, slice_end;
             if (sl->mb_x + sl->mb_y * h->mb_width >= sl->next_slice_idx) {
                 av_log(h->avctx, AV_LOG_ERROR, "Slice overlaps with next at %d\n",
                        sl->next_slice_idx);
@@ -2669,10 +2685,11 @@  static int decode_slice(struct AVCodecContext *avctx, void *arg)
                 return AVERROR_INVALIDDATA;
             }
 
+            slice_end = eos || sl->mb_y >= h->mb_height;
             if (++sl->mb_x >= h->mb_width) {
                 loop_filter(h, sl, lf_x_start, sl->mb_x);
                 sl->mb_x = lf_x_start = 0;
-                decode_finish_row(h, sl);
+                decode_finish_row(h, sl, slice_end);
                 ++sl->mb_y;
                 if (FIELD_OR_MBAFF_PICTURE(h)) {
                     ++sl->mb_y;
@@ -2729,7 +2746,7 @@  static int decode_slice(struct AVCodecContext *avctx, void *arg)
             if (++sl->mb_x >= h->mb_width) {
                 loop_filter(h, sl, lf_x_start, sl->mb_x);
                 sl->mb_x = lf_x_start = 0;
-                decode_finish_row(h, sl);
+                decode_finish_row(h, sl, 0);
                 ++sl->mb_y;
                 if (FIELD_OR_MBAFF_PICTURE(h)) {
                     ++sl->mb_y;