]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/qtrle.c
avcodec/vlc, bitstream: Allow to use BE codes to initialize LE VLC
[ffmpeg] / libavcodec / qtrle.c
index 1cb3eb05bd1ee299b4b9eb9021357026ff7860e2..6bdde75df464e9f725dd120a0fd91fce0f29a1b7 100644 (file)
@@ -36,6 +36,7 @@
 #include <string.h>
 
 #include "avcodec.h"
+#include "decode.h"
 #include "bytestream.h"
 #include "internal.h"
 
@@ -388,7 +389,7 @@ static void qtrle_decode_32bpp(QtrleContext *s, int row_ptr, int lines_to_change
                 /* copy pixels directly to output */
                 rle_code_half = rle_code / 2;
                 while (rle_code_half--) { /* copy 2 argb raw value at the same time */
-                    AV_WN64A(rgb + pixel_ptr, bytestream2_get_ne64(&s->g));
+                    AV_WN64(rgb + pixel_ptr, bytestream2_get_ne64(&s->g));
                     pixel_ptr += 8;
                 }
 
@@ -452,35 +453,45 @@ static int qtrle_decode_frame(AVCodecContext *avctx,
     int header, start_line;
     int height, row_ptr;
     int has_palette = 0;
-    int ret;
+    int duplicate = 0;
+    int ret, size;
 
     bytestream2_init(&s->g, avpkt->data, avpkt->size);
 
     /* check if this frame is even supposed to change */
-    if (avpkt->size < 8)
-        return avpkt->size;
+    if (avpkt->size < 8) {
+        duplicate = 1;
+        goto done;
+    }
 
     /* start after the chunk size */
-    bytestream2_seek(&s->g, 4, SEEK_SET);
+    size = bytestream2_get_be32(&s->g) & 0x3FFFFFFF;
+    if (size - avpkt->size >  size * (int64_t)avctx->discard_damaged_percentage / 100)
+        return AVERROR_INVALIDDATA;
+
 
     /* fetch the header */
     header = bytestream2_get_be16(&s->g);
 
     /* if a header is present, fetch additional decoding parameters */
     if (header & 0x0008) {
-        if (avpkt->size < 14)
-            return avpkt->size;
+        if (avpkt->size < 14) {
+            duplicate = 1;
+            goto done;
+        }
         start_line = bytestream2_get_be16(&s->g);
         bytestream2_skip(&s->g, 2);
         height     = bytestream2_get_be16(&s->g);
         bytestream2_skip(&s->g, 2);
-        if (height > s->avctx->height - start_line)
-            return avpkt->size;
+        if (height > s->avctx->height - start_line) {
+            duplicate = 1;
+            goto done;
+        }
     } else {
         start_line = 0;
         height     = s->avctx->height;
     }
-    if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
+    if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
         return ret;
 
     row_ptr = s->frame->linesize[0] * start_line;
@@ -543,6 +554,17 @@ static int qtrle_decode_frame(AVCodecContext *avctx,
         memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
     }
 
+done:
+    if (!s->frame->data[0])
+        return AVERROR_INVALIDDATA;
+    if (duplicate) {
+        // ff_reget_buffer() isn't needed when frames don't change, so just update
+        // frame props.
+        ret = ff_decode_frame_props(avctx, s->frame);
+        if (ret < 0)
+            return ret;
+    }
+
     if ((ret = av_frame_ref(data, s->frame)) < 0)
         return ret;
     *got_frame      = 1;
@@ -551,6 +573,13 @@ static int qtrle_decode_frame(AVCodecContext *avctx,
     return avpkt->size;
 }
 
+static void qtrle_decode_flush(AVCodecContext *avctx)
+{
+    QtrleContext *s = avctx->priv_data;
+
+    av_frame_unref(s->frame);
+}
+
 static av_cold int qtrle_decode_end(AVCodecContext *avctx)
 {
     QtrleContext *s = avctx->priv_data;
@@ -569,5 +598,6 @@ AVCodec ff_qtrle_decoder = {
     .init           = qtrle_decode_init,
     .close          = qtrle_decode_end,
     .decode         = qtrle_decode_frame,
+    .flush          = qtrle_decode_flush,
     .capabilities   = AV_CODEC_CAP_DR1,
 };