From patchwork Wed Aug 23 16:12:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derek Buitenhuis X-Patchwork-Id: 4808 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.137.29 with SMTP id o29csp2145395jaj; Wed, 23 Aug 2017 09:21:34 -0700 (PDT) X-Received: by 10.223.133.67 with SMTP id 61mr2044712wrh.100.1503505294440; Wed, 23 Aug 2017 09:21:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503505294; cv=none; d=google.com; s=arc-20160816; b=tH2nuMjuN4OUr6iJqARpe6VbqJWlKgJ3ZJL/b73B1MU74sLwye20fZhvdrQ1I8v7aO V+vT550ndU7DIP7AtY3/0q1nxkeuNriLO7TkJDrTrI1bIwdhpHWP0Pa1j3MlQE7dh3jm LgIofgbEkAEfZavb9jQuYMhDPUBviUAow56rQZwXrjYDGAMzImsasdNiydQu+79VQoHG uUe/Wq9wsNiDLXEu9WtyCBKy/x8HbsYDyu2sjhZ5MbC/MoBTNkSj3fOmkhxHghWZ7O4w f3yM0hbS2n9Wwfc41xcTPxeQJBIwaGDGUNYh50gE+fuUm6S+F8EbAYKbyo6wNbezpA/L wLig== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:message-id:date:to:from:dkim-signature :delivered-to:arc-authentication-results; bh=jEGZl1TyY5DwZO+VzKj78kY6JS8OTP18b9m/p+3mZFM=; b=BtsvSvkf9UR024YkJG3z3tkf+qLeHYfhyBul1Gt2hqQsfphr3MyyBIBM1KM8wCfs5+ h3UNf2W+JEcvTkSinrJW2vJV6ysaQVDPFjdOYo6YFOgoWMaAgdZH/8eFkucdUFR93E+v YZO8XIgzqPUoTTxSIx/vGFuidt4TObztmJxkcVTnFaDSAH6OAAMdg9mW0okDSrG80g+P oyHss/ocC8A4Rz0WA4jD5Artdoq5qSHIcqT1DIoBOsrJqHInMWiLMtJjvNnSrwKDveNw ds3/D17irG3pCGNyZMCZ0gK3uBPOCeJCkmjDM9nYg9p9fKjscTz3d1WzvgJNy+Efdps7 Z+wQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=fCuKqnKB; 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=NONE 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 j37si1554705wrj.331.2017.08.23.09.21.33; Wed, 23 Aug 2017 09:21:34 -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=20161025 header.b=fCuKqnKB; 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=NONE 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 1E45D68071F; Wed, 23 Aug 2017 19:21:25 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f67.google.com (mail-wm0-f67.google.com [74.125.82.67]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2C1FB6806AF for ; Wed, 23 Aug 2017 19:21:18 +0300 (EEST) Received: by mail-wm0-f67.google.com with SMTP id t138so598251wmt.4 for ; Wed, 23 Aug 2017 09:21:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=hnM2ppaS5WiwCEPOa9YYs0pkw+uE4Fe1p/iKzRVF39I=; b=fCuKqnKBEoAGCMJ5FMAIQthe7ajjoz1XcdNYc9BhG5xy7MrKB+tqm5YJM1mUiuOLIa 4BRG0cGByOmITjy0GkiBQBCdD0srhocRcVAGzRNUaUtMMFhZU6+mckJiCO7ahzkRdQ5B +gJKudtjGzIBcp8GeVHu8jGUehRJHC7vW9K74/B5iw261Vd9MqwEX/hjbSfz2t7WkceH cSIATe7gSgngSYljLNiuUOuZyA/CnKVNDWxwXQKGJedfB5PdaCIRFlDJ02pwnKyDQUj5 HyqUNLR+2JDW0HRCoqE/OV4jLS697agzmqnzdq1oxqMIhfWb60WghTuDasIsMrkbLf9p P3MQ== 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=hnM2ppaS5WiwCEPOa9YYs0pkw+uE4Fe1p/iKzRVF39I=; b=D5YgRJvXx/dn2lPuB0FcEfxPdGO4RPG7+mtWS/LyATIpnJZ6+bwDlgfPiVaSLhfJ1s y+1+2WFNi2Ob5b6FVkA/g6B61vBqRwVl2VNwniHPCJFwCodyMZqGyW//pcqCdaD+Hj8X aXrSd5H4GI4xgwpOU5lM9M9B4LNkVhqtz7T6GiDo8YQsCk5v3gPNWIzJpHjEq/Pz4rTr LLxSQgKNuld67YMRGddm+4h2OpBCxeUM7pffucB5bgr7B2z3zUaZ6VhP+r5KA37MpJlj IOVdaN5ZuYC9H8oW0S1FwE9iTqIkqTDvq1NeilSV0mW2XUOx4fJOtjN/qz5YRhOj5lZ5 YMqg== X-Gm-Message-State: AHYfb5g7Db+q+d0zk3ooTcq/u2CBnlaJLuTNw3JOy2gmx2Pb1zs9JQpT 8Dd8scFEIyKWpWKdRhg= X-Received: by 10.28.172.4 with SMTP id v4mr1891867wme.72.1503504809649; Wed, 23 Aug 2017 09:13:29 -0700 (PDT) Received: from vimeo-vm.localdomain ([82.129.104.219]) by smtp.gmail.com with ESMTPSA id q141sm1828473wmb.11.2017.08.23.09.13.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 23 Aug 2017 09:13:29 -0700 (PDT) From: Derek Buitenhuis To: ffmpeg-devel@ffmpeg.org Date: Wed, 23 Aug 2017 17:12:34 +0100 Message-Id: <1503504754-48942-1-git-send-email-derek.buitenhuis@gmail.com> X-Mailer: git-send-email 1.8.3.1 Subject: [FFmpeg-devel] [PATCH] mjpeg: Add support for ICC side data 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" JPEGs store embedded profiles under the APP2 marker, signified with a "ICC_PROFILE" null-terminated string header, and can be split across multiple APP2 markers, out of order. This patch currently assumes one single ICC profile for the whole context, i.e. a single JPEG input file. This likely does not work for MJPEG files with embedded ICC profiles, but I could not find a real, exisiting file, that had that. Signed-off-by: Derek Buitenhuis --- libavcodec/mjpegdec.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/mjpegdec.h | 5 +++ 2 files changed, 95 insertions(+) diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index 387ceadf..8be5e01 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -1901,6 +1901,67 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) } } + if (s->start_code == APP2 && id == AV_RB32("ICC_") && len >= 10) { + int id2; + unsigned seqno; + unsigned nummarkers; + + id = get_bits_long(&s->gb, 32); + id2 = get_bits_long(&s->gb, 24); + len -= 7; + if (id != AV_RB32("PROF") || id2 != AV_RB24("ILE")) { + av_log(s->avctx, AV_LOG_WARNING, "Invalid ICC_PROFILE header in APP2\n"); + goto out; + } + + skip_bits(&s->gb, 8); + seqno = get_bits(&s->gb, 8); + len -= 2; + if (seqno == 0) { + av_log(s->avctx, AV_LOG_WARNING, "Invalid sequence number in APP2\n"); + goto out; + } + + nummarkers = get_bits(&s->gb, 8); + len -= 1; + if (nummarkers == 0) { + av_log(s->avctx, AV_LOG_WARNING, "Invalid number of markers coded in APP2\n"); + goto out; + } else if (s->iccnum != 0 && nummarkers != s->iccnum) { + av_log(s->avctx, AV_LOG_WARNING, "Mistmatch in coded number of ICC markers between markers\n"); + goto out; + } else if (seqno > nummarkers) { + av_log(s->avctx, AV_LOG_WARNING, "Mismatching sequence number and coded number of ICC markers\n"); + goto out; + } + + /* Allocate if this is the first APP2 we've seen. */ + if (s->iccnum == 0) { + s->iccdata = av_mallocz(nummarkers * sizeof(*(s->iccdata))); + s->iccdatalens = av_mallocz(nummarkers * sizeof(*(s->iccdatalens))); + if (!s->iccdata || !s->iccdatalens) { + av_log(s->avctx, AV_LOG_ERROR, "Could not allocate ICC data arrays\n"); + return AVERROR(ENOMEM); + } + s->iccnum = nummarkers; + } + + s->iccdatalens[seqno - 1] = len; + s->iccdata[seqno - 1] = av_malloc(len); + if (!s->iccdata[seqno - 1]) { + av_log(s->avctx, AV_LOG_ERROR, "Could not allocate ICC data buffer\n"); + return AVERROR(ENOMEM); + } + + memcpy(s->iccdata[seqno - 1], align_get_bits(&s->gb), len); + skip_bits(&s->gb, len << 3); + len = 0; + s->iccread++; + + if (s->iccread > s->iccnum) + av_log(s->avctx, AV_LOG_WARNING, "Read more ICC markers than are supposed to be coded\n"); + } + out: /* slow but needed for extreme adobe jpegs */ if (len < 0) @@ -2509,6 +2570,29 @@ the_end: av_freep(&s->stereo3d); } + if (s->iccnum != 0 && s->iccnum == s->iccread) { + AVFrameSideData *sd; + size_t offset = 0; + int total_size = 0; + int i; + + /* Sum size of all parts. */ + for (i = 0; i < s->iccnum; i++) + total_size += s->iccdatalens[i]; + + sd = av_frame_new_side_data(data, AV_FRAME_DATA_ICC_PROFILE, total_size); + if (!sd) { + av_log(s->avctx, AV_LOG_ERROR, "Could not allocate frame side data\n"); + return AVERROR(ENOMEM); + } + + /* Reassemble the parts, which are now in-order. */ + for (i = 0; i < s->iccnum; i++) { + memcpy(sd->data + offset, s->iccdata[i], s->iccdatalens[i]); + offset += s->iccdatalens[i]; + } + } + av_dict_copy(&((AVFrame *) data)->metadata, s->exif_metadata, 0); av_dict_free(&s->exif_metadata); @@ -2548,6 +2632,12 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx) av_freep(&s->last_nnz[i]); } av_dict_free(&s->exif_metadata); + + if (s->iccdata) + for (i = 0; i < s->iccnum; i++) + av_freep(&s->iccdata[i]); + av_freep(&s->iccdata); + av_freep(&s->iccdatalens); return 0; } diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h index 024cedc..2bc69fa 100644 --- a/libavcodec/mjpegdec.h +++ b/libavcodec/mjpegdec.h @@ -130,6 +130,11 @@ typedef struct MJpegDecodeContext { AVStereo3D *stereo3d; ///!< stereoscopic information (cached, since it is read before frame allocation) const AVPixFmtDescriptor *pix_desc; + + uint8_t **iccdata; + int *iccdatalens; + int iccnum; + int iccread; } MJpegDecodeContext; int ff_mjpeg_decode_init(AVCodecContext *avctx);