[FFmpeg-devel,4/4] avcodec/nuv: Avoid duplicating frames

Submitted by Michael Niedermayer on May 30, 2019, 2:04 p.m.

Details

Message ID 20190530140400.6205-4-michael@niedermayer.cc
State New
Headers show

Commit Message

Michael Niedermayer May 30, 2019, 2:04 p.m.
Fixes: Timeout (14sec -> 133ms)
Fixes: 14843/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_NUV_fuzzer-5661969614372864

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavcodec/nuv.c          | 35 ++++++++++++++++++++++++++++++++---
 tests/ref/fate/nuv-rtjpeg |  1 -
 2 files changed, 32 insertions(+), 4 deletions(-)

Patch hide | download patch | download mbox

diff --git a/libavcodec/nuv.c b/libavcodec/nuv.c
index 75b14bce5b..043b299080 100644
--- a/libavcodec/nuv.c
+++ b/libavcodec/nuv.c
@@ -42,6 +42,8 @@  typedef struct NuvContext {
     unsigned char *decomp_buf;
     uint32_t lq[64], cq[64];
     RTJpegContext rtj;
+    int need_flush;
+    AVPacket flush_pkt;
 } NuvContext;
 
 static const uint8_t fallback_lquant[] = {
@@ -66,6 +68,12 @@  static const uint8_t fallback_cquant[] = {
     99, 99, 99, 99, 99, 99, 99, 99
 };
 
+static void decode_flush(AVCodecContext *avctx){
+    NuvContext *s = avctx->priv_data;
+
+    s->need_flush = 0;
+}
+
 /**
  * @brief copy frame data from buffer to AVFrame, handling stride.
  * @param f destination AVFrame
@@ -172,6 +180,25 @@  static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
         NUV_COPY_LAST     = 'L'
     } comptype;
 
+    if (!avpkt->data) {
+        if (c->need_flush) {
+            c->need_flush = 0;
+            if ((ret = ff_reget_buffer(avctx, c->pic)) < 0)
+                return ret;
+            c->pic->pkt_pos      = c->flush_pkt.pos;
+            c->pic->pkt_duration = c->flush_pkt.duration;
+            c->pic->pkt_dts      = c->flush_pkt.dts;
+            c->pic->pkt_pts      =
+            c->pic->pts          = c->flush_pkt.pts;
+            if ((ret = av_frame_ref(data, c->pic)) < 0)
+                return ret;
+            *got_frame = 1;
+        }
+        return 0;
+    }
+    c->flush_pkt = *avpkt;
+
+
     if (buf_size < 12) {
         av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
         return AVERROR_INVALIDDATA;
@@ -204,8 +231,8 @@  static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
         }
         break;
     case NUV_COPY_LAST:
-        keyframe = 0;
-        break;
+        c->need_flush = 1;
+        return buf_size;
     default:
         keyframe = 1;
         break;
@@ -313,6 +340,7 @@  retry:
     if ((result = av_frame_ref(picture, c->pic)) < 0)
         return result;
 
+    c->need_flush = 0;
     *got_frame = 1;
     return orig_size;
 }
@@ -364,6 +392,7 @@  AVCodec ff_nuv_decoder = {
     .init           = decode_init,
     .close          = decode_end,
     .decode         = decode_frame,
-    .capabilities   = AV_CODEC_CAP_DR1,
+    .flush          = decode_flush,
+    .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
     .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
 };
diff --git a/tests/ref/fate/nuv-rtjpeg b/tests/ref/fate/nuv-rtjpeg
index b6f3b080dc..0914b985ec 100644
--- a/tests/ref/fate/nuv-rtjpeg
+++ b/tests/ref/fate/nuv-rtjpeg
@@ -6,7 +6,6 @@ 
 0,        118,        118,        0,   460800, 0x54aedafe
 0,        152,        152,        0,   460800, 0xb7aa8b56
 0,        177,        177,        0,   460800, 0x283ea3b5
-0,        202,        202,        0,   460800, 0x283ea3b5
 0,        235,        235,        0,   460800, 0x10e577de
 0,        269,        269,        0,   460800, 0x4e091ee2
 0,        302,        302,        0,   460800, 0x2ea88828