[FFmpeg-devel] [PATCH v3 1/4] avcodec/webp: compatibilize with avformat/webpdec

Martin Reboredo yakoyoku at gmail.com
Sun Sep 12 23:20:07 EEST 2021


The demuxer implementation splits some RIFF chunks (`RIFF`/`VP8X`/`ANMF` + frame chunk) or sends the picture chunks separately.
The internal WebP decoder waits for a complete file instead and by consequence it needs to be modified to support this kind of fractioned input.

Fixes FATE tests with WebP.

Signed-off-by: Martin Reboredo <yakoyoku at gmail.com>
---
 libavcodec/webp.c | 41 ++++++++++++++++++++++++++++++++---------
 1 file changed, 32 insertions(+), 9 deletions(-)

diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 3efd4438d9..7858d69481 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -40,6 +40,7 @@
  *   - XMP metadata
  */
 
+#include "libavformat/internal.h"
 #include "libavutil/imgutils.h"
 
 #define BITSTREAM_READER_LE
@@ -191,6 +192,7 @@ typedef struct WebPContext {
     AVFrame *alpha_frame;               /* AVFrame for alpha data decompressed from VP8L */
     AVPacket *pkt;                      /* AVPacket to be passed to the underlying VP8 decoder */
     AVCodecContext *avctx;              /* parent AVCodecContext */
+    int read_header;                    /* RIFF header has been read */
     int initialized;                    /* set once the VP8 context is initialized */
     int has_alpha;                      /* has a separate alpha chunk */
     enum AlphaCompression alpha_compression; /* compression type for alpha chunk */
@@ -1353,17 +1355,36 @@ static int webp_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
     if (bytestream2_get_bytes_left(&gb) < 12)
         return AVERROR_INVALIDDATA;
 
-    if (bytestream2_get_le32(&gb) != MKTAG('R', 'I', 'F', 'F')) {
-        av_log(avctx, AV_LOG_ERROR, "missing RIFF tag\n");
-        return AVERROR_INVALIDDATA;
-    }
-
+    chunk_type = bytestream2_get_le32(&gb);
     chunk_size = bytestream2_get_le32(&gb);
-    if (bytestream2_get_bytes_left(&gb) < chunk_size)
-        return AVERROR_INVALIDDATA;
 
-    if (bytestream2_get_le32(&gb) != MKTAG('W', 'E', 'B', 'P')) {
-        av_log(avctx, AV_LOG_ERROR, "missing WEBP tag\n");
+    for (int i = 0; !s->read_header && i < 4; i++) {
+        ff_lock_avformat();
+
+        if (s->read_header) {
+            ff_unlock_avformat();
+            break;
+        }
+
+        if (chunk_type == MKTAG('R', 'I', 'F', 'F')) {
+            int left = bytestream2_get_bytes_left(&gb);
+            if (left < chunk_size && left != 22) {
+                ff_unlock_avformat();
+                return AVERROR_INVALIDDATA;
+            }
+            if (bytestream2_get_le32(&gb) != MKTAG('W', 'E', 'B', 'P')) {
+                av_log(avctx, AV_LOG_ERROR, "missing WEBP tag\n");
+                ff_unlock_avformat();
+                return AVERROR_INVALIDDATA;
+            }
+            s->read_header = 1;
+        }
+
+        ff_unlock_avformat();
+    }
+
+    if (!s->read_header) {
+        av_log(avctx, AV_LOG_ERROR, "missing RIFF tag\n");
         return AVERROR_INVALIDDATA;
     }
 
@@ -1416,6 +1437,8 @@ static int webp_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
             ret = av_image_check_size(s->width, s->height, 0, avctx);
             if (ret < 0)
                 return ret;
+            if (bytestream2_get_bytes_left(&gb) == 0)
+                return AVERROR(EAGAIN);
             break;
         case MKTAG('A', 'L', 'P', 'H'): {
             int alpha_header, filter_m, compression;
-- 
2.32.0



More information about the ffmpeg-devel mailing list