From patchwork Wed Feb 17 13:30:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 25703 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 1E36444AE6F for ; Wed, 17 Feb 2021 15:38:50 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id E1E4F68A03E; Wed, 17 Feb 2021 15:38:49 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ed1-f51.google.com (mail-ed1-f51.google.com [209.85.208.51]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 297B3680352 for ; Wed, 17 Feb 2021 15:38:43 +0200 (EET) Received: by mail-ed1-f51.google.com with SMTP id q10so16463582edt.7 for ; Wed, 17 Feb 2021 05:38:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=w9bHPx2bANBu/c/P4LMNNGSAch2ZjntcOogDk2pWY44=; b=MbuB8dLPEtyQ3WqpVkymrO0WbIMaOY3O6yGcXKVGp36TqUCn8SacHAKzaQlgAJM2tl vpIeR1eoVLEiG1+sUMdOAFqU5gW7iPljsJjaOkAgKadCQI6ciS7n4LPmx0SoV5xjiAsk 1nICOWC7sFTbU+RrgSrLuHfUCLVlTd9ovtmKZiL8ojO6a741zTErzLHErSylIofPHXgg j4/ZorF8/d5CcxzsWzWEvt/wd1MMQjguf1sWWU4/qwJzbrsb7XzuygwvMHoZCZsNqRzl r5PcYO9+g4dN2eSY4C5ZIwJmI1If0pOt8VdEAt4lpw92bvGvHLtWeLXb2RYupYfVj7hG WMTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=w9bHPx2bANBu/c/P4LMNNGSAch2ZjntcOogDk2pWY44=; b=PFQvKQsKniz+46O2i2Mg94B5xOea0pVEPSBOCCRgWeEynMc35yEPvXngbhgzDkBn4u lmq2mdNy1I60jhOPG7wHpOy7mCDhz42sFXN3MvYyiXOHSgMZcH98hb6ayaAGxuFmtwHo hux4kQK0r7JtJFEX0mVIGws0BnPZuW/57qpAaXM5tb0lTkKiXZKCRJp3SK0GvdPEjNji wi5zdQKKiEaB1DpRdxPLcKvrOayaRuDUOalS8bPCQhzDJxc+w8cn8Dgk1r15v4spfOLP vHBnYeUFQEvcndPfIQfT4BYFHP6ADitD/3mX4s9BJcvEGNKzmGmnTATT7HXrhMVHQxNK S1Hg== X-Gm-Message-State: AOAM5313iyemRa+s+jdD7OMDx3UfoZu62So4RHsFRS9fOnYnran5wfsZ Kl6sxPOeONgSCL4elrAQPub16z9iJ3Vn3g== X-Google-Smtp-Source: ABdhPJxBU+NZY74Mg35n33iU599JaUKt5WIToNUKyMJsP1zOKMQtyEAE22Hv3CjIj65hooqzaWZ6cQ== X-Received: by 2002:aa7:c5d7:: with SMTP id h23mr15459699eds.38.1613568653267; Wed, 17 Feb 2021 05:30:53 -0800 (PST) Received: from localhost.localdomain ([94.250.162.225]) by smtp.gmail.com with ESMTPSA id f20sm1123027edd.47.2021.02.17.05.30.52 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 Feb 2021 05:30:52 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Wed, 17 Feb 2021 14:30:45 +0100 Message-Id: <20210217133045.21199-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] avcodec: add exr format parser X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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 MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- libavcodec/Makefile | 1 + libavcodec/exr_parser.c | 217 ++++++++++++++++++++++++++++++++++++++++ libavcodec/parsers.c | 1 + 3 files changed, 219 insertions(+) create mode 100644 libavcodec/exr_parser.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 5fb735f129..82d1f15b40 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1095,6 +1095,7 @@ OBJS-$(CONFIG_DVAUDIO_PARSER) += dvaudio_parser.o OBJS-$(CONFIG_DVBSUB_PARSER) += dvbsub_parser.o OBJS-$(CONFIG_DVD_NAV_PARSER) += dvd_nav_parser.o OBJS-$(CONFIG_DVDSUB_PARSER) += dvdsub_parser.o +OBJS-$(CONFIG_EXR_PARSER) += exr_parser.o OBJS-$(CONFIG_FLAC_PARSER) += flac_parser.o flacdata.o flac.o OBJS-$(CONFIG_G723_1_PARSER) += g723_1_parser.o OBJS-$(CONFIG_G729_PARSER) += g729_parser.o diff --git a/libavcodec/exr_parser.c b/libavcodec/exr_parser.c new file mode 100644 index 0000000000..93833cd23d --- /dev/null +++ b/libavcodec/exr_parser.c @@ -0,0 +1,217 @@ +/* + * EXR parser + * Copyright (c) 2020 Paul B Mahol + * + * 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 + */ + +/** + * @file + * EXR parser + */ + +#include "libavutil/bswap.h" +#include "libavutil/intreadwrite.h" +#include "parser.h" + +typedef struct EXRParseContext { + ParseContext pc; + + int flags; + uint32_t w, h; + uint32_t tile_w, tile_h; + int64_t skip_bytes; + uint64_t bytes_read; + int nb_offsets; + unsigned curr_offset; + unsigned offset_index; + uint64_t max_offset; + int compression; + + int exr_state; + uint8_t key[256]; + unsigned key_index; + uint8_t type[256]; + unsigned type_index; + uint32_t size; + unsigned size_index; + uint8_t value[256]; + uint32_t value_index; +} EXRParseContext; + +static int exr_parse(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + EXRParseContext *exr = s->priv_data; + uint64_t state = exr->pc.state64; + int next = END_NOT_FOUND, i = 0; + + s->pict_type = AV_PICTURE_TYPE_I; + s->key_frame = 1; + + *poutbuf_size = 0; + *poutbuf = NULL; + + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + for (; i < buf_size; i++) { + exr->bytes_read++; + state = (state << 8) | buf[i]; + + if (exr->skip_bytes > 0 && exr->exr_state == 0) { + exr->skip_bytes--; + if (exr->skip_bytes == 0) { + next = i + 1; + exr->bytes_read = 0; + break; + } + } else if (exr->exr_state == 1) { + exr->key[exr->key_index++] = buf[i]; + if (exr->key_index >= 255) { + exr->exr_state = 0; + exr->key_index = 0; + memset(exr->key, 0, sizeof(exr->key)); + goto new_state; + } + + if (!buf[i] && exr->key_index == 1) { + exr->exr_state = 5; + if (!(exr->flags & 0x020000)) { + switch (exr->compression) { + case 5: + case 3: + exr->nb_offsets = (exr->nb_offsets + 15) >> 4; + break; + case 4: + case 6: + case 7: + exr->nb_offsets = (exr->nb_offsets + 31) >> 5; + break; + default: + break; + } + } else if (exr->tile_w && exr->tile_h) { + exr->nb_offsets = ((exr->w + exr->tile_w - 1) / exr->tile_w) * + ((exr->h + exr->tile_h - 1) / exr->tile_h); + } + exr->curr_offset = 0; + exr->offset_index = 0; + exr->max_offset = 0; + } else if (!buf[i]) { + exr->exr_state = 2; + } + } else if (exr->exr_state == 2) { + exr->type[exr->type_index++] = buf[i]; + if (exr->type_index >= 255) { + exr->exr_state = 0; + exr->type_index = 0; + memset(exr->type, 0, sizeof(exr->type)); + exr->key_index = 0; + memset(exr->key, 0, sizeof(exr->key)); + goto new_state; + } + + if (!buf[i]) { + exr->exr_state = 3; + exr->size_index = 0; + exr->size = 0; + } + } else if (exr->exr_state == 3) { + exr->size = (exr->size << 8) | buf[i]; + exr->size_index++; + if (exr->size_index == 4) { + exr->exr_state = 4; + } + } else if (exr->exr_state == 4) { + if (exr->value_index < 255) + exr->value[exr->value_index] = buf[i]; + exr->value_index++; + if (exr->value_index == av_bswap32(exr->size)) { + if (!strcmp(exr->key, "dataWindow") && + !strcmp(exr->type, "box2i")) { + exr->w = AV_RL32(exr->value + 8) + 1 - AV_RL32(exr->value + 0); + exr->h = AV_RL32(exr->value + 12) + 1 - AV_RL32(exr->value + 4); + exr->nb_offsets = exr->h; + } else if (!strcmp(exr->key, "compression") && + !strcmp(exr->type, "compression")) { + exr->compression = exr->value[0]; + } else if (!strcmp(exr->key, "tiles") && + !strcmp(exr->type, "tiledesc")) { + exr->tile_w = AV_RL32(exr->value + 0); + exr->tile_h = AV_RL32(exr->value + 4); + } + exr->exr_state = 1; + exr->size = 0; + exr->key_index = 0; + exr->type_index = 0; + exr->value_index = 0; + memset(exr->key, 0, sizeof(exr->key)); + memset(exr->type, 0, sizeof(exr->type)); + } + } else if (exr->exr_state == 5) { + exr->offset_index++; + if (exr->offset_index == 8) { + uint64_t new_offset = av_bswap64(state); + + exr->curr_offset++; + exr->offset_index = 0; + if (exr->max_offset < new_offset) + exr->max_offset = new_offset; + if (exr->curr_offset >= exr->nb_offsets) { + exr->curr_offset = 0; + exr->exr_state = 6; + } + } + } else if (exr->exr_state == 6) { + if (exr->bytes_read == exr->max_offset + 8 + (!!(exr->flags & 0x020000)) * 12) { + exr->skip_bytes = av_bswap32(state & 0xFFFFFFFF); + exr->bytes_read = 0; + exr->exr_state = 0; + exr->max_offset = 0; + exr->nb_offsets = 0; + } + } + +new_state: + if (exr->exr_state == 0 && ((state & 0xFFFFFFFFFF000000LL) == 0x762F310102000000LL)) { + exr->flags = state & 0xFFFFFF; + exr->exr_state = 1; + } + } + + exr->pc.state64 = state; + if (ff_combine_frame(&exr->pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + } + + *poutbuf = buf; + *poutbuf_size = buf_size; + + return next; +} + +AVCodecParser ff_exr_parser = { + .codec_ids = { AV_CODEC_ID_EXR }, + .priv_data_size = sizeof(EXRParseContext), + .parser_parse = exr_parse, + .parser_close = ff_parse_close, +}; diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c index 61af22b2d5..e5b3f998df 100644 --- a/libavcodec/parsers.c +++ b/libavcodec/parsers.c @@ -43,6 +43,7 @@ extern AVCodecParser ff_dvaudio_parser; extern AVCodecParser ff_dvbsub_parser; extern AVCodecParser ff_dvdsub_parser; extern AVCodecParser ff_dvd_nav_parser; +extern AVCodecParser ff_exr_parser; extern AVCodecParser ff_flac_parser; extern AVCodecParser ff_g723_1_parser; extern AVCodecParser ff_g729_parser;