From patchwork Wed Sep 8 18:49:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Reboredo X-Patchwork-Id: 30078 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6602:2a4a:0:0:0:0 with SMTP id k10csp697087iov; Wed, 8 Sep 2021 11:49:48 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwrL8uvfA/jeAWBhkyF++6H6xAuC069D1oh9JGcbvmAzb3oj9PsAtKwrtKRLoISx82f/Eog X-Received: by 2002:a17:906:15cf:: with SMTP id l15mr1354467ejd.568.1631126988720; Wed, 08 Sep 2021 11:49:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1631126988; cv=none; d=google.com; s=arc-20160816; b=ii3dePKLJ4WHtkF171n6K4TIKoHcM6OPenHro9D/gmcAiJezIU4Cr7Rj//6NmBT/Ml /AzQ8KZ5hXSKZkl666ZtV1Jj5pXpdAAweavG0DHqfLFn2fK1lykTNdF3iz9BVhcQusnL WMfPIvO8cXpZpq1y+yx3rUn0rzGegirRKRmUSpk9LrqTI0LI80IIplbe6Td9J9t9zVwU lo8n0Fz+fOQI47hTKRFVTG5Y74EJkH+1gpWj5P56wO2OUbIU0aMrQVibIImXgMOONbNA zKMo3e7Ia20y+4vIdeGWVczJClGufCHUcPkp9r7WcrRarlCsn+HIZjb0FYbB+bGin9U4 mOWA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=ImEyb4y1QxMRIXp9uHl2VsqEy6VexMx07kSmYcfl8C8=; b=fS741eXGwUQTyCgtK/1icguAnE+tad+kB13+TeHI3K5lH1PVVVrqzjEtJAT4tQwVs0 4FttgJKM6cgI3/Wysytzth6F8RUPTntX4CbJich9vvloNsn1bjVtf1geigkXVLM8snhq VaMImjYyIEJZN47AHXe6kxK23Ggpk43gvxY74kKak0RwGJF27R2fpNKMm6uFCfsdTdIh SOh2xBAtEWFSgXwdXhTE3h8aJH1j51dQHaReJbsfs0/GsedA4Y1lJeW/Ailt0qC50Az0 uR418UCgVGDP8Mi0b91IvsnlfS454t2TlJy/e57Ax3SQZ5sddN5nAALsxvfgsb9OHWfy W0lw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=GCJthlJZ; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id u1si3944677edc.285.2021.09.08.11.49.47; Wed, 08 Sep 2021 11:49:48 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=GCJthlJZ; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 3228F68A75A; Wed, 8 Sep 2021 21:49:44 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qk1-f175.google.com (mail-qk1-f175.google.com [209.85.222.175]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 6654A688093 for ; Wed, 8 Sep 2021 21:49:38 +0300 (EEST) Received: by mail-qk1-f175.google.com with SMTP id t4so3430005qkb.9 for ; Wed, 08 Sep 2021 11:49:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=1eLK/FeW8vMF/WfE5LKTayC40ZFju5zoYM1d1/WuSXo=; b=GCJthlJZ7V4TnshVTRx3yp/xFa2xKoyt31f/iqhjr9EDRfWMVksvqd/KdWcaEbpf0u eBPtJju3kJtzGl5RU9wU3GfALEpSw9q+dCH7pjjCEB79w0/Sw8QjUJ5PblLqdHUAM/j0 eRGlGIYqIN9lLqhjLG7rMDLkpheZo5GUquknTF6mc7FZqeIK2llzQL7YoWo1KKX2N9jm QILKMzJxLoUBmoSOuMdH5cnJpAOIzcNg14jK7p5HuKCy3LbYyoIxKc5X4Z1Hwy7+vzWE 7sHjl4CpgVbkC4oKSa4ts4BHlui4pQhB2oF7u76HrZ3RGT7+Lx5WABowwIAB/jgPJ2kM HN5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=1eLK/FeW8vMF/WfE5LKTayC40ZFju5zoYM1d1/WuSXo=; b=yrjVWbi5ah5n04+PIlLTFnOLQEFUwUYhCEPaKBRfwTxBRW4fohEk8YVLiOJIp5pDyw FglTFn+adh4fBCU0jfBH6K7YjEQIfAHydfWYLasE3V5oDF6Xx2AX1hq4myQ8v9CL4egO WmlJDPXC0LkfonhYuBct4EGzvSb4z6ViXsvU7l36A5jtcwWBRsnO48dCW4sUAbfYm1rV AnBjpsXkqn7sCi1aXNgLRWLCaM9fI4dy+4BtzDBcQittNv0ABVnH0r3NXKXIuedGW2PG wfP9hbXRx8oQNz9XailT9s8ju6MM8hDaxX6VwW7hM48IkCM/+VM3uZBc4eh/Ob7WaHFz 2HcQ== X-Gm-Message-State: AOAM530Yjb/WZLyMHE3S6Z1Rq3MKKUMDBk+F05QK17fmDREW3LHY5HsE NXZNeLoybF/ro6ChfwXvs64qA6ZrkGdj7w== X-Received: by 2002:a05:620a:1454:: with SMTP id i20mr5015727qkl.383.1631126976842; Wed, 08 Sep 2021 11:49:36 -0700 (PDT) Received: from localhost.localdomain (static.218.11.itcsa.net. [190.15.218.11]) by smtp.gmail.com with ESMTPSA id g7sm2049737qtj.28.2021.09.08.11.49.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 08 Sep 2021 11:49:36 -0700 (PDT) From: yakoyoku@gmail.com To: ffmpeg-devel@ffmpeg.org Date: Wed, 8 Sep 2021 15:49:31 -0300 Message-Id: <20210908184931.3620755-1-yakoyoku@gmail.com> X-Mailer: git-send-email 2.32.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avformat/webpdec: WebP demuxer implementation X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Martin Reboredo Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: zckUIY18h0wj From: Martin Reboredo FFmpeg has the ability to mux encoded WebP packets, but it cannot demux the format. The purpose of this patch is to add a way to extract pictures from a WebP stream. Any other side data processing (mainly ICC profiles) is left up for later work. Although we have a demuxer with `image2`, it doesn't have support for animated frames like this patch. The WebP format is based on RIFF, and due to the charasteristics of the latter, I've took advantage from chunking for processing purposes. Package reading is done by taking chunks in a specific way. Starts by splitting the `RIFF`/`WEBP` header, then it goes by any of the three `VP8 ` (lossy)/`VP8L` (lossless)/`VP8X` (extended format). In the case of a `VP8X` chunk we check for relevant flags. We then follow by grabbing the `VP8 `/`ALPH` (alpha frame) + `VP8 `/`VP8L` chunks accourdingly. If the container specifies that is an animated package we take `ANIM` for the animation parameters and the many `ANMF` animation frames, which every of them contains an image chunk (`VP8 `/`ALPH` + `VP8 `/`VP8L`). Otherwise, if an unknown chunk is found, we just simply ignore it. Tested by remuxing WebP images (using `ffmpeg -i testa.webp -codec:v copy testb.webp`), viewed the images in my browser and compared the checksums. Mostly followed the WebP container specification [1] for the implementation, the VP8 bitstream [2] and the WebP lossless specs were used too. Partially fixes #4907. [1]: https://developers.google.com/speed/webp/docs/riff_container [2]: https://datatracker.ietf.org/doc/html/rfc6386 [3]: https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification Signed-off-by: Martin Reboredo --- .gitignore | 2 + MAINTAINERS | 1 + libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/riff.c | 1 + libavformat/webpdec.c | 333 +++++++++++++++++++++++++++++++++++++++ libavformat/webpenc.c | 13 +- 7 files changed, 349 insertions(+), 3 deletions(-) create mode 100644 libavformat/webpdec.c diff --git a/.gitignore b/.gitignore index 9ed24b542e..0e8334d227 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ *.ptx.c *.ptx.gz *_g +compile_commands.json \#* .\#* /.config @@ -34,6 +35,7 @@ /config.h /coverage.info /avversion.h +/.cache/ /lcov/ /src /mapfile diff --git a/MAINTAINERS b/MAINTAINERS index dcac46003e..f2d8f5eb17 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -505,6 +505,7 @@ Muxers/Demuxers: wav.c Michael Niedermayer wc3movie.c Mike Melanson webm dash (matroskaenc.c) Vignesh Venkatasubramanian + webp*.c Martin Reboredo webvtt* Matthew J Heaney westwood.c Mike Melanson wtv.c Peter Ross diff --git a/libavformat/Makefile b/libavformat/Makefile index f7e47563da..aec2833c52 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -581,6 +581,7 @@ OBJS-$(CONFIG_WEBM_MUXER) += matroskaenc.o matroska.o \ OBJS-$(CONFIG_WEBM_DASH_MANIFEST_MUXER) += webmdashenc.o OBJS-$(CONFIG_WEBM_CHUNK_MUXER) += webm_chunk.o OBJS-$(CONFIG_WEBP_MUXER) += webpenc.o +OBJS-$(CONFIG_WEBP_DEMUXER) += webpdec.o OBJS-$(CONFIG_WEBVTT_DEMUXER) += webvttdec.o subtitles.o OBJS-$(CONFIG_WEBVTT_MUXER) += webvttenc.o OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 5471f7c16f..55f3c9a956 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -473,6 +473,7 @@ extern const AVOutputFormat ff_webm_muxer; extern const AVInputFormat ff_webm_dash_manifest_demuxer; extern const AVOutputFormat ff_webm_dash_manifest_muxer; extern const AVOutputFormat ff_webm_chunk_muxer; +extern const AVInputFormat ff_webp_demuxer; extern const AVOutputFormat ff_webp_muxer; extern const AVInputFormat ff_webvtt_demuxer; extern const AVOutputFormat ff_webvtt_muxer; diff --git a/libavformat/riff.c b/libavformat/riff.c index 27a9706510..9bd940ba52 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -321,6 +321,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_VP7, MKTAG('V', 'P', '7', '1') }, { AV_CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') }, { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') }, + { AV_CODEC_ID_WEBP, MKTAG('W', 'E', 'B', 'P') }, { AV_CODEC_ID_ASV1, MKTAG('A', 'S', 'V', '1') }, { AV_CODEC_ID_ASV2, MKTAG('A', 'S', 'V', '2') }, { AV_CODEC_ID_VCR1, MKTAG('V', 'C', 'R', '1') }, diff --git a/libavformat/webpdec.c b/libavformat/webpdec.c new file mode 100644 index 0000000000..d2d95aea4e --- /dev/null +++ b/libavformat/webpdec.c @@ -0,0 +1,333 @@ +/* + * webp demuxer + * Copyright (c) 2021 Martin Reboredo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/intreadwrite.h" +#include "libavutil/mathematics.h" +#include "libavutil/opt.h" +#include "avformat.h" +#include "internal.h" + +typedef struct WebpDemuxContext { + AVClass *class; + int width; + int height; + AVPacket last_pkt; + int size; + int loop; + int read_webp_header; + int using_webp_anim_decoder; + int vp8x; + int lossless; + int alpha; + int icc; +} WebpDemuxContext; + +static int webpdec_read_probe(const AVProbeData * p) +{ + if (AV_RL32(p->buf) != AV_RL32("RIFF")) + return 0; + + if (AV_RL32(&p->buf[8]) != AV_RL32("WEBP")) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static int parse_animation_frame_duration(AVFormatContext * s, AVPacket * pkt) +{ + pkt->duration = av_rescale_q(AV_RL24(pkt->data + 20), + (AVRational) { 1, 1000 }, + s->streams[0]->time_base); + + return 0; +} + +static int parse_vp8x_chunk(AVFormatContext * s, AVPacket * pkt) +{ + WebpDemuxContext *w = s->priv_data; + AVIOContext *pb = s->pb; + int bgcolor = 0xFFFFFFFF; + int cont = 1, anim_frame = 0, alpha_frame = 0; + int64_t ret = 0; + + s->packet_size = 0; + + while (cont && ret >= 0) { + int skip = 0, rewind = 1; + int fourcc = avio_rl32(pb); + int size = avio_rl32(pb); + int padded_size = size + (size & 1); + int chunk_size = padded_size + 8; + s->packet_size += chunk_size; + + if (padded_size == 0) + return AVERROR_EOF; + + switch (fourcc) { + case MKTAG('V', 'P', '8', 'X'): + return AVERROR_INVALIDDATA; + /* case MKTAG('I', 'C', 'C', 'P'): + avio_read(pb, w->iccp_data, padded_size); */ + case MKTAG('A', 'L', 'P', 'H'): + if (!w->alpha || alpha_frame == 1) + return AVERROR_INVALIDDATA; + if (w->using_webp_anim_decoder && anim_frame == 0) + return AVERROR_INVALIDDATA; + + alpha_frame = 1; + break; + case MKTAG('V', 'P', '8', 'L'): + alpha_frame = 1; + case MKTAG('V', 'P', '8', ' '): + if (w->alpha && alpha_frame == 0) + return AVERROR_INVALIDDATA; + if (w->using_webp_anim_decoder && anim_frame == 0) + return AVERROR_INVALIDDATA; + + cont = 0; + break; + case MKTAG('A', 'N', 'I', 'M'): + if (w->loop == -1) { + bgcolor = avio_rl32(pb); + w->loop = avio_rl16(pb); + + ret = avio_seek(pb, -14, SEEK_CUR); + if (ret < 0) + return ret; + + ret = av_get_packet(pb, pkt, s->packet_size); + if (ret < 0) + return ret; + + return 0; + } + cont = 0; + break; + case MKTAG('A', 'N', 'M', 'F'): + if (!w->using_webp_anim_decoder || anim_frame == 1) + return AVERROR_INVALIDDATA; + + ret = avio_seek(pb, -8, SEEK_CUR); + if (ret < 0) + return ret; + + ret = av_get_packet(pb, pkt, s->packet_size); + if (ret < 0) + return ret; + + ret = parse_animation_frame_duration(s, pkt); + if (ret < 0) + return ret; + + anim_frame = 1; + rewind = 0; + return 0; + default: + s->packet_size -= chunk_size; + skip = 1; + rewind = 0; + break; + } + + if (skip) { + ret = avio_skip(pb, padded_size); + } + if (rewind) { + ret = avio_seek(pb, -8, SEEK_CUR); + if (ret < 0) + return ret; + ret = av_append_packet(pb, pkt, chunk_size); + } + } + + return ret; +} + +static int parse_header(AVFormatContext * s) +{ + WebpDemuxContext *w = s->priv_data; + AVIOContext *pb = s->pb; + int size; + unsigned int flags = 0; + int ret = 0; + + if (avio_rl32(pb) != AV_RL32("RIFF")) + return AVERROR_INVALIDDATA; + w->size = avio_rl32(pb) + 8; + if (avio_rl32(pb) != AV_RL32("WEBP")) + return AVERROR_INVALIDDATA; + + if (avio_rl24(pb) != AV_RL24("VP8")) + return AVERROR_INVALIDDATA; + switch (avio_r8(pb)) { + case 'X': + w->vp8x = 1; + break; + case 'L': + w->lossless = 1; + case ' ': + break; + default: + return AVERROR_INVALIDDATA; + } + size = avio_rl32(pb); + if (w->vp8x) { + flags = avio_r8(pb); + + if (flags & 0x02) + w->using_webp_anim_decoder = 1; + if (flags & 0x10) + w->alpha = 1; + if (flags & 0x20) + w->icc = 1; + + ret = avio_skip(pb, 3); + if (ret < 0) + return ret; + + w->width = avio_rl24(pb) + 1; + w->height = avio_rl24(pb) + 1; + + ret = avio_seek(pb, -30, SEEK_CUR); + } else if (w->lossless) { + avio_r8(pb); + flags = avio_rl32(pb); + w->width = (flags & 0x3FFF) + 1; + w->height = ((flags >> 14) & 0x3FFF) + 1; + w->alpha = (flags >> 28) & 0x01; + + ret = avio_seek(pb, -25, SEEK_CUR); + } else { + ret = avio_skip(pb, 6); + if (ret < 0) + return ret; + + w->width = (avio_rl16(pb) & 0x3FFF); + w->height = (avio_rl16(pb) & 0x3FFF); + + ret = avio_seek(pb, -30, SEEK_CUR); + } + + return ret; +} + +static int webpdec_read_header(AVFormatContext * s) +{ + WebpDemuxContext *w = s->priv_data; + AVStream *st; + int ret; + + w->width = -1; + w->height = -1; + w->loop = -1; + w->read_webp_header = 0; + + ret = parse_header(s); + if (ret < 0) + return ret; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_WEBP; + st->codecpar->width = w->width; + st->codecpar->height = w->height; + st->codecpar->format = w->alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P; + + st->start_time = 0; + + avpriv_set_pts_info(st, 24, 1, 1000); + + return 0; +} + +static int webpdec_read_packet(AVFormatContext * s, AVPacket * pkt) +{ + WebpDemuxContext *w = s->priv_data; + AVIOContext *pb = s->pb; + int ret; + + ret = avio_feof(pb); + if (ret < 0) + return ret; + else if (ret > 0) + return AVERROR_EOF; + + if (!w->read_webp_header) { + s->packet_size = w->vp8x ? 30 : 12; + + ret = av_get_packet(pb, pkt, s->packet_size); + if (ret < 0) + return ret; + + w->read_webp_header = 1; + + return 0; + } + + if (!w->using_webp_anim_decoder) + pkt->duration = + av_rescale_q(33, (AVRational) { 1, 1000 }, + s->streams[0]->time_base); + + if (w->vp8x) { + ret = parse_vp8x_chunk(s, pkt); + if (ret < 0) + return ret; + } else { + int fourcc = avio_rl32(pb); + int size = avio_rl32(pb) + 8; + size = size + (size & 1); + if (fourcc != AV_RL32("VP8 ") && fourcc != AV_RL32("VP8L")) + return AVERROR_INVALIDDATA; + ret = avio_seek(pb, -8, SEEK_CUR); + if (ret < 0) + return ret; + ret = av_get_packet(pb, pkt, size); + if (ret < 0) + return ret; + } + + pkt->stream_index = 0; + + return 0; +} + +static const AVClass webp_demuxer_class = { + .class_name = "WebP demuxer", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVInputFormat ff_webp_demuxer = { + .name = "webp", + .long_name = NULL_IF_CONFIG_SMALL("WebP"), + .extensions = "webp", + .mime_type = "image/webp", + .priv_data_size = sizeof(WebpDemuxContext), + .read_probe = webpdec_read_probe, + .read_header = webpdec_read_header, + .read_packet = webpdec_read_packet, + .priv_class = &webp_demuxer_class, + .flags = AVFMT_VARIABLE_FPS, +}; diff --git a/libavformat/webpenc.c b/libavformat/webpenc.c index 9599fe7b85..47c28437ff 100644 --- a/libavformat/webpenc.c +++ b/libavformat/webpenc.c @@ -55,13 +55,18 @@ static int is_animated_webp_packet(AVPacket *pkt) { int skip = 0; unsigned flags = 0; + int fourcc = AV_RL32(pkt->data); if (pkt->size < 4) return AVERROR_INVALIDDATA; - if (AV_RL32(pkt->data) == AV_RL32("RIFF")) + if (fourcc == AV_RL32("RIFF")) skip = 12; + else if (fourcc == AV_RL32("ANIM")) + return 1; + else if (fourcc == AV_RL32("ANMF")) + return 1; // Safe to do this as a valid WebP bitstream is >=30 bytes. - if (pkt->size < skip + 4) + if (pkt->size < skip + 4 && pkt->size != 12) return AVERROR_INVALIDDATA; if (AV_RL32(pkt->data + skip) == AV_RL32("VP8X")) { flags |= pkt->data[skip + 4 + 4]; @@ -143,6 +148,7 @@ static int flush(AVFormatContext *s, int trailer, int64_t pts) static int webp_write_packet(AVFormatContext *s, AVPacket *pkt) { WebpContext *w = s->priv_data; + int fourcc = AV_RL32(pkt->data); int ret; if (!pkt->size) @@ -161,7 +167,8 @@ static int webp_write_packet(AVFormatContext *s, AVPacket *pkt) return ret; av_packet_ref(&w->last_pkt, pkt); } - ++w->frame_count; + if (fourcc == AV_RL32("ANMF") || fourcc == AV_RL32("VP8 ") || fourcc == AV_RL32("VP8L")) + ++w->frame_count; return 0; }