From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id AC26F40CEC for ; Thu, 10 Mar 2022 13:19:28 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 098FC68AD46; Thu, 10 Mar 2022 15:19:26 +0200 (EET) Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 35CA768AB48 for ; Thu, 10 Mar 2022 15:19:20 +0200 (EET) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id A14E3434B4; Thu, 10 Mar 2022 14:19:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1646918359; bh=FI2l9EPoEeb16EyoJsI0A4qMeNbZ9lo3hL4roUGPj/s=; h=From:To:Cc:Subject:Date:From; b=Z9CQaJIg4i1m638QcaXi3EGUcCmkTg537Z/E8J1OI/2+/Txs74x9WMgRLRn265EXv h2+f3yvX/6Pm9CJ4i80Ii+yIBDAmU2+h2Clla5JLj+hjmBw+OGsKwcR0CKCPV0Zj3a tEM1uMPF07kW0+mDV3LbuPQdh7zz2SvipeugZLEM= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Thu, 10 Mar 2022 14:15:43 +0100 Message-Id: <20220310131542.58255-1-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.35.1 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avcodec/mjpegenc: support writing ICC profiles 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 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: From: Niklas Haas This is mostly straightforward. The major complication is that, as a result of the 16-bit chunk size limitation, ICC profiles may need to be split up into multiple chunks. We also need to make sure to allocate enough extra space in the packet to fit the ICC profile, so modify both mpegvideo_enc.c and ljpegenc.c to take into account this extra overhead. Signed-off-by: Niklas Haas --- I will submit a FATE patch and test separately. (We do not currently have any JPGs with embedded ICC profiles in the test suite) --- libavcodec/ljpegenc.c | 6 +++++- libavcodec/mjpegenc.c | 3 ++- libavcodec/mjpegenc_common.c | 41 +++++++++++++++++++++++++++++++++--- libavcodec/mjpegenc_common.h | 2 +- libavcodec/mpegvideo_enc.c | 3 +++ 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/libavcodec/ljpegenc.c b/libavcodec/ljpegenc.c index e15f448f90..c54450c338 100644 --- a/libavcodec/ljpegenc.c +++ b/libavcodec/ljpegenc.c @@ -216,6 +216,7 @@ static int ljpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, { LJpegEncContext *s = avctx->priv_data; PutBitContext pb; + const AVFrameSideData *sd; const int width = avctx->width; const int height = avctx->height; const int mb_width = (width + s->hsample[0] - 1) / s->hsample[0]; @@ -233,12 +234,15 @@ static int ljpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, * s->hsample[0] * s->vsample[0]; } + if ((sd = av_frame_get_side_data(pict, AV_FRAME_DATA_ICC_PROFILE))) + max_pkt_size += sd->size; + if ((ret = ff_alloc_packet(avctx, pkt, max_pkt_size)) < 0) return ret; init_put_bits(&pb, pkt->data, pkt->size); - ff_mjpeg_encode_picture_header(avctx, &pb, NULL, &s->scantable, + ff_mjpeg_encode_picture_header(avctx, &pb, pict, NULL, &s->scantable, s->pred, s->matrix, s->matrix); header_bits = put_bits_count(&pb); diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c index 08671b0df7..d7c0c763a1 100644 --- a/libavcodec/mjpegenc.c +++ b/libavcodec/mjpegenc.c @@ -77,7 +77,8 @@ static av_cold void init_uni_ac_vlc(const uint8_t huff_size_ac[256], static void mjpeg_encode_picture_header(MpegEncContext *s) { - ff_mjpeg_encode_picture_header(s->avctx, &s->pb, s->mjpeg_ctx, + const AVFrame *frame = s->picture->f; + ff_mjpeg_encode_picture_header(s->avctx, &s->pb, frame, s->mjpeg_ctx, &s->intra_scantable, 0, s->intra_matrix, s->chroma_intra_matrix); diff --git a/libavcodec/mjpegenc_common.c b/libavcodec/mjpegenc_common.c index 995e2b7670..099ed3fce3 100644 --- a/libavcodec/mjpegenc_common.c +++ b/libavcodec/mjpegenc_common.c @@ -130,8 +130,10 @@ static void jpeg_table_header(AVCodecContext *avctx, PutBitContext *p, AV_WB16(ptr, size); } -static void jpeg_put_comments(AVCodecContext *avctx, PutBitContext *p) +static void jpeg_put_comments(AVCodecContext *avctx, PutBitContext *p, + const AVFrame *frame) { + const AVFrameSideData *sd; int size; uint8_t *ptr; @@ -161,6 +163,39 @@ static void jpeg_put_comments(AVCodecContext *avctx, PutBitContext *p) put_bits(p, 8, 0); /* thumbnail height */ } + /* ICC profile */ + if ((sd = av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE))) { + static const uint8_t hdr_size = strlen("ICC_PROFILE")+5; + static const uint16_t max_chunk_size = UINT16_MAX - hdr_size; + const uint8_t *data = sd->data; + size_t remaining = sd->size; + size_t nb_chunks = (remaining + max_chunk_size - 1) / max_chunk_size; + if (nb_chunks > 255) { + av_log(avctx, AV_LOG_WARNING, + "Cannot store %zu byte ICC profile: too large for JPEG\n", + sd->size); + nb_chunks = remaining = 0; + } + + for (int i = 0; i < nb_chunks; i++) { + size = FFMIN(remaining, max_chunk_size); + av_assert1(size > 0); + put_marker(p, APP2); + put_bits(p, 16, size + hdr_size); + ff_put_string(p, "ICC_PROFILE", 1); + put_bits(p, 8, i+1); + put_bits(p, 8, nb_chunks); + flush_put_bits(p); + ptr = put_bits_ptr(p); + skip_put_bytes(p, size); + memcpy(ptr, data, size); + remaining -= size; + data += size; + } + + av_assert1(!remaining); + } + /* comment */ if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { put_marker(p, COM); @@ -213,7 +248,7 @@ void ff_mjpeg_init_hvsample(AVCodecContext *avctx, int hsample[4], int vsample[4 } void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, - MJpegContext *m, + const AVFrame *frame, struct MJpegContext *m, ScanTable *intra_scantable, int pred, uint16_t luma_intra_matrix[64], uint16_t chroma_intra_matrix[64]) @@ -233,7 +268,7 @@ void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, if (avctx->codec_id == AV_CODEC_ID_AMV) return; - jpeg_put_comments(avctx, pb); + jpeg_put_comments(avctx, pb, frame); jpeg_table_header(avctx, pb, m, intra_scantable, luma_intra_matrix, chroma_intra_matrix, hsample); diff --git a/libavcodec/mjpegenc_common.h b/libavcodec/mjpegenc_common.h index ac753bf153..3c0a7addac 100644 --- a/libavcodec/mjpegenc_common.h +++ b/libavcodec/mjpegenc_common.h @@ -30,7 +30,7 @@ struct MJpegContext; void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, - struct MJpegContext *m, + const AVFrame *frame, struct MJpegContext *m, ScanTable *intra_scantable, int pred, uint16_t luma_intra_matrix[64], uint16_t chroma_intra_matrix[64]); diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index c69114ea15..932dfa34f7 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -1686,10 +1686,13 @@ int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, /* output? */ if (s->new_picture.f->data[0]) { + const AVFrameSideData *sd; int growing_buffer = context_count == 1 && !pkt->data && !s->data_partitioning; int pkt_size = growing_buffer ? FFMAX(s->mb_width*s->mb_height*64+10000, avctx->internal->byte_buffer_size) - AV_INPUT_BUFFER_PADDING_SIZE : s->mb_width*s->mb_height*(MAX_MB_BYTES+100)+10000; + if ((sd = av_frame_get_side_data(s->new_picture.f, AV_FRAME_DATA_ICC_PROFILE))) + pkt_size += sd->size; if ((ret = ff_alloc_packet(avctx, pkt, pkt_size)) < 0) return ret; if (s->mb_info) { -- 2.35.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".