From patchwork Fri Mar 11 10:17:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 34684 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6838:3486:0:0:0:0 with SMTP id ek6csp1555288nkb; Fri, 11 Mar 2022 02:18:30 -0800 (PST) X-Google-Smtp-Source: ABdhPJzZwVCiMFU1ckUcjCuxMPsPDV/+uOtgJTduhYXRuPWONhZVgRvsMAiSNXwuJfiugVYaM+qv X-Received: by 2002:a05:6402:51cd:b0:416:a841:22a0 with SMTP id r13-20020a05640251cd00b00416a84122a0mr8161788edd.292.1646993910168; Fri, 11 Mar 2022 02:18:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1646993910; cv=none; d=google.com; s=arc-20160816; b=WFz39dzpT0hDfbuwYvbMm+2AhvBsYXOWZpZXAbpUi/GaX7S5d1kZ89VG9AN/g0voac qQO1KglfIb8yyPPGnB3Bb4Hfmmf3hq4cSeeLPZ/0E+lMXElYBIdseiuErpxqXEa2u1a2 OpgSpQX1RTLxdKrq1eiyjhrar9xNDOFcfkac2+pI/4+eLe27uvtFolFoPXKm4iR+/OSl /Rgxv3UYIkcNf4Le3oljWnB2acHT6XYxFdED3GNPw/NwfasuudTN9KT9ajM4adAyR1+K kxCJjfzjStN/cplybtFYWcNPs1Piagp3OXHyN8BGxMtTXxuw8tV1CaVyYCekaBV9QZLO G04Q== 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:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=/mb8CLmbWd2z5IATvS0qV9xpScuxPtJDrMWqIjUz044=; b=YF0akyEtywhQuZ/cUkr+AOn+tKu79LtGn7CwBXzvheblNQm5Vz6JqfLO0Ig1MR+7bL xNaGIrmROoo26Z3Oz00NKNB1qiTHPpwP0dP+WbPy+7jNUAZyS0mkERUYQBqKfgMSBd5L RukWiyVSGc2Il13dG3sv3PnAu3Q+RL4vm8IZ4DFHTTDIB6/bpZyCb8ICOYBV0MM6dspI xxvtJhzFdILPBzrT6iKHjo1e8+iElDfhx4U7mAoE7yaTtfHRiBPbZNvctMdpeYQSxvQb pCokKFrVFtKtVEZkJD0YBl/1Q4uqE1EJL+JIDtqs0Ie4zWdicHMVnX1W6ehB77g3T41S SAkA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=nbEXp3Lq; 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 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id o3-20020a170906600300b006af868c7e8dsi4278092ejj.536.2022.03.11.02.18.29; Fri, 11 Mar 2022 02:18:30 -0800 (PST) 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=@haasn.xyz header.s=mail header.b=nbEXp3Lq; 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 Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4764E68B155; Fri, 11 Mar 2022 12:18:27 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4E6D268ADDE for ; Fri, 11 Mar 2022 12:18:20 +0200 (EET) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 014DC49890; Fri, 11 Mar 2022 11:18:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1646993900; bh=mKXH4GWaO34srX0qq1nIVMyGwPSkCnFDp3byrNfFWC8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nbEXp3LquXt7U6ByXUnGvVN1pv9lQGbzTQ6YFkW8PjJhpl2+Jn+lFYkTi9d3QLNH/ 7J1GBl/mpCHO7ISHDBPwMgRF5qSrBS30cNeRLPrGJVgjriVBzx1Eh9pD6BA2qekznh GEDGEpnXhjqs5BlUHcfvx1LiG9n60L1bhS4MJXi4= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 11 Mar 2022 11:17:42 +0100 Message-Id: <20220311101741.104545-1-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311101413.92878-1-ffmpeg@haasn.xyz> References: <20220311101413.92878-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v2] avcodec/pngenc: support writing iCCP chunks 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: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: gJaEiESCs5ih From: Niklas Haas encode_zbuf is mostly a mirror image of decode_zbuf. Other than that, the code is pretty straightforward. Special care needs to be taken to avoid writing more than 79 characters of the profile description (the maximum supported). Also add a FATE transcode test to ensure that the ICC profile gets encoded correctly. --- Oops. `-c copy` doesn't actually test the PNG writing code. Need to use `-c png` instead. Fixed in v2. --- libavcodec/pngenc.c | 77 +++++++++++++++++++++++++++++++++++++++++- tests/fate/image.mak | 3 ++ tests/ref/fate/png-icc | 8 +++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 tests/ref/fate/png-icc diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c index 3ebcc1e571..24530bb62f 100644 --- a/libavcodec/pngenc.c +++ b/libavcodec/pngenc.c @@ -28,6 +28,7 @@ #include "apng.h" #include "libavutil/avassert.h" +#include "libavutil/bprint.h" #include "libavutil/crc.h" #include "libavutil/libm.h" #include "libavutil/opt.h" @@ -343,6 +344,65 @@ static int png_get_gama(enum AVColorTransferCharacteristic trc, uint8_t *buf) return 1; } +static int encode_zbuf(AVBPrint *bp, const uint8_t *data, size_t size) +{ + z_stream zstream; + unsigned char *buf; + unsigned buf_size; + int ret; + + zstream.zalloc = ff_png_zalloc, + zstream.zfree = ff_png_zfree, + zstream.opaque = NULL; + if (deflateInit(&zstream, Z_DEFAULT_COMPRESSION) != Z_OK) + return AVERROR_EXTERNAL; + zstream.next_in = data; + zstream.avail_in = size; + + for (;;) { + av_bprint_get_buffer(bp, 2, &buf, &buf_size); + if (buf_size < 2) { + deflateEnd(&zstream); + return AVERROR(ENOMEM); + } + + zstream.next_out = buf; + zstream.avail_out = buf_size - 1; + ret = deflate(&zstream, Z_FINISH); + if (ret != Z_OK && ret != Z_STREAM_END) { + deflateEnd(&zstream); + return AVERROR_EXTERNAL; + } + + bp->len += zstream.next_out - buf; + if (ret == Z_STREAM_END) { + deflateEnd(&zstream); + return 0; + } + } +} + +static int png_get_iccp(AVBPrint *bp, const AVFrameSideData *sd, char **buf_out) +{ + const AVDictionaryEntry *name; + int ret; + + av_bprint_init(bp, 0, AV_BPRINT_SIZE_UNLIMITED); + + /* profile header */ + name = av_dict_get(sd->metadata, "name", NULL, 0); + av_bprintf(bp, "%.79s", (name && name->value[0]) ? name->value : "icc"); + av_bprint_chars(bp, 0, 2); /* terminating \0 and compression method */ + + /* profile data */ + if ((ret = encode_zbuf(bp, sd->data, sd->size))) { + av_bprint_finalize(bp, NULL); + return ret; + } + + return av_bprint_finalize(bp, buf_out); +} + static int encode_headers(AVCodecContext *avctx, const AVFrame *pict) { AVFrameSideData *side_data; @@ -399,7 +459,22 @@ static int encode_headers(AVCodecContext *avctx, const AVFrame *pict) if (png_get_gama(pict->color_trc, s->buf)) png_write_chunk(&s->bytestream, MKTAG('g', 'A', 'M', 'A'), s->buf, 4); - /* put the palette if needed */ + side_data = av_frame_get_side_data(pict, AV_FRAME_DATA_ICC_PROFILE); + if (side_data && side_data->size) { + AVBPrint bp; + char *buf; + int ret; + + if ((ret = png_get_iccp(&bp, side_data, &buf))) { + av_log(avctx, AV_LOG_WARNING, "Failed writing iCCP chunk: %s\n", + av_err2str(ret)); + } else { + png_write_chunk(&s->bytestream, MKTAG('i', 'C', 'C', 'P'), buf, bp.size); + av_free(buf); + } + } + + /* put the palette if needed, must be after colorspace information */ if (s->color_type == PNG_COLOR_TYPE_PALETTE) { int has_alpha, alpha, i; unsigned int v; diff --git a/tests/fate/image.mak b/tests/fate/image.mak index 573d398915..da4f3709e9 100644 --- a/tests/fate/image.mak +++ b/tests/fate/image.mak @@ -385,6 +385,9 @@ FATE_PNG_PROBE += fate-png-side-data fate-png-side-data: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_frames \ -i $(TARGET_SAMPLES)/png1/lena-int_rgb24.png +FATE_PNG_PROBE += fate-png-icc +fate-png-icc: CMD = transcode png_pipe $(TARGET_SAMPLES)/png1/lena-int_rgb24.png image2 "-c png" + FATE_PNG-$(call DEMDEC, IMAGE2, PNG) += $(FATE_PNG) FATE_PNG_PROBE-$(call DEMDEC, IMAGE2, PNG) += $(FATE_PNG_PROBE) FATE_IMAGE += $(FATE_PNG-yes) diff --git a/tests/ref/fate/png-icc b/tests/ref/fate/png-icc new file mode 100644 index 0000000000..d3cf55263e --- /dev/null +++ b/tests/ref/fate/png-icc @@ -0,0 +1,8 @@ +7e412f6a9e2c7fcb674336e5c104518d *tests/data/fate/png-icc.image2 +49398 tests/data/fate/png-icc.image2 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x128 +#sar 0: 2835/2835 +0, 0, 0, 1, 49152, 0xe0013dee