From patchwork Thu Aug 24 13:33:33 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derek Buitenhuis X-Patchwork-Id: 4819 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.15.201 with SMTP id 70csp451732jao; Thu, 24 Aug 2017 06:34:27 -0700 (PDT) X-Received: by 10.28.103.6 with SMTP id b6mr3516072wmc.28.1503581667756; Thu, 24 Aug 2017 06:34:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503581667; cv=none; d=google.com; s=arc-20160816; b=WDVONNhVk0F9nAqurI9EC9NkJlRySHShXZbEy83KOmdtcZy439iz3mukP2PVKPbmqQ 0DBqNILP6NdGQnlgw9KHwfjSZ9yTJwW0Zwj6hkOUnhno1LAKBFMGRgBNoo+9iShKSoje F7K5kSBqequzinU3IgG2saqNUL3EOW9JN6ucDAISjpjcm4HL9sT32vow42+LZgChB1lE e/ajx0cQfGNqlYHXe0mROrtVt7ch3VVujwzXLFgb80R587VaqXhxrL3Fgy9npyIGwAkD fTCDF3nrj/utlDqa2zPVOq8ihBhhDkRLgvlWaSvMBcvn9YJUooZXRMM1Nnavq5xQTLuj 3Ocg== 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=Wrk2K1eVu6Tz5XIlkmao0XpaikFCMRNPoZy3OrcgVCs=; b=xDIvXyPSL8TIhTD5FHyEy1TVmBXKVsQxmeJO61dAKmEGQC++1HhBzwdaMURcF7l/YU emZ95vxtGoIWdvWg2hn3jIIiaetrGB9mPULRy4Cd902dubLrvy+IJRkcR4WTw8xW9u5v cda/U0yCSNjcLx41TfghLb+MXVg2RZSjAA4jmAnuS9OzwOEluKz/TWfISK7FxRzemiqk LTIAze+RL30KGiR64AftWCN278of0c6z+Iq3+NtSC82gChCOGEjs3si7Wxnlew7edo9B G2iiLYIURo3O5fuFj9rEuhceU7iiiB4IfrBw0w1FZdaHMZHx1WK84g7uc8v6jvy5+PW+ xydA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=sieX05yY; 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 189si3334604wmi.20.2017.08.24.06.34.26; Thu, 24 Aug 2017 06:34:27 -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=sieX05yY; 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 968FD689BE5; Thu, 24 Aug 2017 16:34:15 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f65.google.com (mail-wm0-f65.google.com [74.125.82.65]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1EE28689B40 for ; Thu, 24 Aug 2017 16:34:09 +0300 (EEST) Received: by mail-wm0-f65.google.com with SMTP id x79so2820091wma.2 for ; Thu, 24 Aug 2017 06:34:17 -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=9MANzCrMpSHi/8yapgOqa3d8aKScKTjmF6lXBEpJDgo=; b=sieX05yYch5U+GSajiA39BCkzNOD3fU26wJhJCavMkR90WfIkmyFsWD4dNCug5PdS6 Qoogbj27OC7lQxaYvSmiYqizVqAxWV7CqzeW5ewvZutXL8f9ZFXBj72sp2l1NyU3rTk4 25Yku98platFnrfGAqJbxrmNIXANdyfUJi6mwfCTpWj2odmEY4jh2++Llg4jv/OP+c5d UqVnNZxeE3Q2H+UfH9HQK818V7xAivt7ZPgAwL7jR1IWFnVTLEMheXq2+hUO7vbOycBf 9EtwJcUcEQfdQQk22mHt/z++FbAG+X2Tnbj4g0sISWJDFi0jJe4NI+i7Oi5sx12uAeLj j6Ug== 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=9MANzCrMpSHi/8yapgOqa3d8aKScKTjmF6lXBEpJDgo=; b=hpnC0NQnKYsHzwD6FBcib0zKuu7q8BLYCVRAbS3NUwEU5wIBv/hkjOqnAgUdXOuIHs CbgWEzPN8uw3WtdibYqIOyld4VZZCNkRRveZqze+leV4CVKk70WSVoTbOQg82Ka/nivJ 0HhGRbhpZP0mgtebJYviAQRIWgiwDm/56oZxa898A08MiIJHqkQMT+7SWtE4EiGlwSIz JbFzPwnDknfxnWGR0+miL8Jano/V1oD7tkNX2P+ECNRlQg8cRBlgACP8im3tisuvorzj mB/RJvXojekNFycCdf6SUnl8L8b4Lt2UZbxKZaJ1mlvihFGsfFNKxo/ve8MIfWMr9sq5 8cPA== X-Gm-Message-State: AHYfb5iBnuaLiCb1KXXziSpaG669UZc144lzaOuhAhoaaJH/f3zcURHF tdBdGS7ADZBLIffmqQQ= X-Received: by 10.28.195.132 with SMTP id t126mr3336881wmf.65.1503581656682; Thu, 24 Aug 2017 06:34:16 -0700 (PDT) Received: from vimeo-vm.localdomain ([82.129.104.219]) by smtp.gmail.com with ESMTPSA id c9sm3210790wrd.54.2017.08.24.06.34.15 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 06:34:15 -0700 (PDT) From: Derek Buitenhuis To: ffmpeg-devel@ffmpeg.org Date: Thu, 24 Aug 2017 14:33:33 +0100 Message-Id: <1503581613-61817-1-git-send-email-derek.buitenhuis@gmail.com> X-Mailer: git-send-email 1.8.3.1 Subject: [FFmpeg-devel] [PATCH v2] 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. Signed-off-by: Derek Buitenhuis --- libavcodec/mjpegdec.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/mjpegdec.h | 5 +++ 2 files changed, 109 insertions(+) diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index 387ceadf..b08ae0a 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) @@ -2097,6 +2158,20 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s, return start_code; } +static void reset_icc_profile(MJpegDecodeContext *s) +{ + int i; + + if (s->iccdata) + for (i = 0; i < s->iccnum; i++) + av_freep(&s->iccdata[i]); + av_freep(&s->iccdata); + av_freep(&s->iccdatalens); + + s->iccread = 0; + s->iccnum = 0; +} + int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { @@ -2117,6 +2192,9 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, av_freep(&s->stereo3d); s->adobe_transform = -1; + if (s->iccnum != 0) + reset_icc_profile(s); + buf_ptr = buf; buf_end = buf + buf_size; while (buf_ptr < buf_end) { @@ -2509,6 +2587,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 +2649,9 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx) av_freep(&s->last_nnz[i]); } av_dict_free(&s->exif_metadata); + + reset_icc_profile(s); + 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);