From patchwork Sat Apr 10 12:33:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Spyros Theoharis X-Patchwork-Id: 26835 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 5B41744B5FC for ; Sat, 10 Apr 2021 15:34:55 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 42CD46804B7; Sat, 10 Apr 2021 15:34:55 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from host.alma-technologies.com (host.alma-technologies.com [162.255.161.220]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0EA956804FC for ; Sat, 10 Apr 2021 15:34:47 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=alma-technologies.com; s=default; h=Content-Transfer-Encoding:Content-Type: MIME-Version:Message-ID:Date:Subject:To:From:Reply-To:Sender:Cc:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=LZTZ+InXrQZ+LqRXfHSf8PJQLjvyeHKsgsBuIGFOkBs=; b=OFLxWWJoW9bzBDyxWjh7Ifv4D/ AFezTvrqeS4hjpN6qOWjgAPjW9w6PLmUWfPS1+BhZWeBxPKbKsEGs311Sj+aJtP660VcjTB6AxnGq oTedL5///pznuMCGMYm7DxOKwwmvSCv7gNJ8mDag21JujFcwW3RI2fAsHTrMul4mmCl+xUEeB6aBb Dw4EFon9jMcu0FtK/vFrm+e3oNXpX5lEgscrfNG7BXyxL/jpeS6NOnA3GZ8EZrdZfdMXBrPqDzvAv 40qd56vRicUVwohkS9aHV6lKPET5oz8qo6HJhDrgT9nr6O5T/qUI+t7p8YLtiMkZYV4egJ5VTQd9/ dqnXs/Vg==; Received: from alma-t.static.otenet.gr ([94.70.251.174]:59243 helo=THEOHARIWIN10) by host.alma-technologies.com with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94) (envelope-from ) id 1lVCp3-00064n-Go for ffmpeg-devel@ffmpeg.org; Sat, 10 Apr 2021 15:34:45 +0300 From: "Spyros Theoharis" To: Date: Sat, 10 Apr 2021 15:33:46 +0300 Organization: ALMA Technolgies S.A. Message-ID: <000001d72e05$c334ca90$499e5fb0$@alma-tech.com> MIME-Version: 1.0 X-Mailer: Microsoft Outlook 16.0 Thread-Index: AdcuBaL/YB7v8ga4QaW1Eu14hri1rg== Content-Language: el X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - host.alma-technologies.com X-AntiAbuse: Original Domain - ffmpeg.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - alma-tech.com X-Get-Message-Sender-Via: host.alma-technologies.com: authenticated_id: s.theoharis@alma-technologies.com X-Authenticated-Sender: host.alma-technologies.com: s.theoharis@alma-technologies.com X-Source: X-Source-Args: X-Source-Dir: Subject: [FFmpeg-devel] [PATCH] JPEG-LS Decoder: Update 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" - 8 up to 16 bits - 444/422/420/411 - fixed restart mechanism support - RGB/YUV 444 images (via -rgb444 input option) --- libavcodec/jpegls.c | 5 + libavcodec/jpegls.h | 2 +- libavcodec/jpeglsdec.c | 268 +++++++++++++++++++++++++++++++++---------------- libavcodec/mjpegdec.c | 77 ++++++++++---- 4 files changed, 244 insertions(+), 108 deletions(-) if (len != 8 + 3 * nb_components) { @@ -399,7 +398,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) && s->component_id[3] == 'K' - 1) s->adobe_transform = 0; - if (s->ls && (s->h_max > 1 || s->v_max > 1)) { + if (s->ls && (s->h_max > 4 || s->v_max > 2)) { avpriv_report_missing_feature(s->avctx, "Subsampling in JPEG-LS"); return AVERROR_PATCHWELCOME; } @@ -469,9 +468,9 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) return AVERROR_INVALIDDATA; } } else { - if (s->v_max == 1 && s->h_max == 1 && s->lossless==1 && (nb_components==3 || nb_components==4)) - s->rgb = 1; - else if (!s->lossless) + if (s->v_max == 1 && s->h_max == 1 && s->lossless==1 && (nb_components==3 || nb_components==4)) { + if (!s->ls) s->rgb = 1; + } else if (!s->lossless) s->rgb = 0; /* XXX: not complete test ! */ pix_fmt_id = ((unsigned)s->h_count[0] << 28) | (s->v_count[0] << 24) | @@ -677,16 +676,51 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) memset(s->upscale_h, 0, sizeof(s->upscale_h)); memset(s->upscale_v, 0, sizeof(s->upscale_v)); if (s->nb_components == 3) { - s->avctx->pix_fmt = AV_PIX_FMT_RGB24; + switch (pix_fmt_id) { + case 0x11111100: /* 444 */ + if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_YUV444P; + else if (s->bits <= 10) s->avctx->pix_fmt = AV_PIX_FMT_YUV444P10; + else if (s->bits <= 12) s->avctx->pix_fmt = AV_PIX_FMT_YUV444P12; + else if (s->bits <= 14) s->avctx->pix_fmt = AV_PIX_FMT_YUV444P14; + else /*if (s->bits <= 16)*/ s->avctx->pix_fmt = AV_PIX_FMT_YUV444P16; + + if (s->rgb) s->avctx->pix_fmt = s->bits <= 8 ? AV_PIX_FMT_RGB24 : AV_PIX_FMT_RGB48; + + break; + case 0x21111100: /* 422 */ + if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_YUV422P; + else if (s->bits <= 10) s->avctx->pix_fmt = AV_PIX_FMT_YUV422P10; + else if (s->bits <= 12) s->avctx->pix_fmt = AV_PIX_FMT_YUV422P12; + else if (s->bits <= 14) s->avctx->pix_fmt = AV_PIX_FMT_YUV422P14; + else /*if (s->bits <= 16)*/ s->avctx->pix_fmt = AV_PIX_FMT_YUV422P16; + break; + case 0x41111100: /* 411 */ + if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_YUV411P; + else goto unk_pixfmt; + break; + case 0x22111100: /* 420 */ + if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_YUV420P; + else if (s->bits <= 10) s->avctx->pix_fmt = AV_PIX_FMT_YUV420P10; + else if (s->bits <= 12) s->avctx->pix_fmt = AV_PIX_FMT_YUV420P12; + else if (s->bits <= 14) s->avctx->pix_fmt = AV_PIX_FMT_YUV420P14; + else /*if (s->bits <= 16)*/ s->avctx->pix_fmt = AV_PIX_FMT_YUV420P16; + break; + default: + goto unk_pixfmt; + break; + } } else if (s->nb_components != 1) { av_log(s->avctx, AV_LOG_ERROR, "Unsupported number of components %d\n", s->nb_components); return AVERROR_PATCHWELCOME; } else if (s->palette_index && s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_PAL8; - else if (s->bits <= 8) - s->avctx->pix_fmt = AV_PIX_FMT_GRAY8; - else - s->avctx->pix_fmt = AV_PIX_FMT_GRAY16; + else { /* Grayscale */ + if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_GRAY8; + else if (s->bits <= 10) s->avctx->pix_fmt = AV_PIX_FMT_GRAY10; + else if (s->bits <= 12) s->avctx->pix_fmt = AV_PIX_FMT_GRAY12; + else if (s->bits <= 14) s->avctx->pix_fmt = AV_PIX_FMT_GRAY14; + else /*if (s->bits <= 16)*/ s->avctx->pix_fmt = AV_PIX_FMT_GRAY16; + } } s->pix_desc = av_pix_fmt_desc_get(s->avctx->pix_fmt); @@ -740,7 +774,6 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) } if ((s->rgb && !s->lossless && !s->ls) || - (!s->rgb && s->ls && s->nb_components > 1) || (s->avctx->pix_fmt == AV_PIX_FMT_PAL8 && !s->ls) ) { av_log(s->avctx, AV_LOG_ERROR, "Unsupported coding and pixel format combination\n"); @@ -2275,7 +2308,7 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s, if (x == 0xff) { while ((src + t < buf_end) && x == 0xff) x = src[t++]; - if (x & 0x80) { + if (x == SOS || x == EOI) { t -= FFMIN(2, t); break; } @@ -2288,14 +2321,18 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s, while (b < t) { uint8_t x = src[b++]; put_bits(&pb, 8, x); - if (x == 0xFF && b < t) { + if (x == 0xff && b < t) { x = src[b++]; - if (x & 0x80) { - av_log(s->avctx, AV_LOG_WARNING, "Invalid escape sequence\n"); - x &= 0x7f; + if (x >= RST0 && x <= RST7) { + put_bits(&pb, 8, x); + } else { + if (x & 0x80) { + av_log(s->avctx, AV_LOG_WARNING, "Invalid escape sequence\n"); + x &= 0x7f; + } + put_bits(&pb, 7, x); + bit_count--; } - put_bits(&pb, 7, x); - bit_count--; } } flush_put_bits(&pb); diff --git a/libavcodec/jpegls.c b/libavcodec/jpegls.c index 7f9fa8d..2b4f601 100644 --- a/libavcodec/jpegls.c +++ b/libavcodec/jpegls.c @@ -45,7 +45,12 @@ void ff_jpegls_init_state(JLSState *state) for (i = 0; i < 367; i++) { state->A[i] = FFMAX(state->range + 32 >> 6, 2); state->N[i] = 1; + state->B[i] = + state->C[i] = 0; } + for (i = 0; i < 4; i++) { + state->run_index[i] = 0; + } } /** diff --git a/libavcodec/jpegls.h b/libavcodec/jpegls.h index aac67bb..e9ca664 100644 --- a/libavcodec/jpegls.h +++ b/libavcodec/jpegls.h @@ -36,7 +36,7 @@ typedef struct JLSState { int T1, T2, T3; - int A[367], B[367], C[365], N[367]; + int A[367], B[367], C[367], N[367]; int limit, reset, bpp, qbpp, maxval, range; int near, twonear; int run_index[4]; diff --git a/libavcodec/jpeglsdec.c b/libavcodec/jpeglsdec.c index 69980ea..6d4b53e 100644 --- a/libavcodec/jpeglsdec.c +++ b/libavcodec/jpeglsdec.c @@ -25,6 +25,7 @@ * JPEG-LS decoder. */ +#include "libavutil/opt.h" #include "avcodec.h" #include "get_bits.h" #include "golomb.h" @@ -220,6 +221,33 @@ static inline int ls_get_code_runterm(GetBitContext *gb, JLSState *state, } /** + * Skip bitstream for the next restart marker + */ +static int exp_mk = 0; +static inline int ls_decode_skip_restart_marker(MJpegDecodeContext *s, int init) +{ + int mk = 0, t = 0; + + if (init) exp_mk = 0; + + while (mk != 0xff && t++ < 16) { /* skip 0xFF */ + mk = (mk<<1) + get_bits1(&s->gb); + } + mk &= 0xff; + mk <<= 8; + mk += get_bits(&s->gb, 8); /* skip RSTn */ + + if (mk != 0xffd0 + (exp_mk % 8)) { + av_log(s->avctx, AV_LOG_WARNING, "ERROR: Invalid restart marker 0x%.4X, expected is 0x%.4X\n", mk, 0xffd0 + (exp_mk % 8)); + return -1; + } + + exp_mk++; + + return mk; +} + +/** * Decode one line of image */ static inline int ls_decode_line(JLSState *state, MJpegDecodeContext *s, @@ -348,17 +376,18 @@ static inline int ls_decode_line(JLSState *state, MJpegDecodeContext *s, int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, int point_transform, int ilv) { - int i, t = 0; - uint8_t *zero, *last, *cur; + int i, m, cmp = 0; + int Rc[3] = { 0, 0, 0 }; + int x, w, is_last_cmp; + + uint8_t *zero, *last[3], *cur[3]; JLSState *state; - int off = 0, stride = 1, width, shift, ret = 0; + int shift, ret = 0; int decoded_height = 0; zero = av_mallocz(s->picture_ptr->linesize[0]); if (!zero) return AVERROR(ENOMEM); - last = zero; - cur = s->picture_ptr->data[0]; state = av_mallocz(sizeof(JLSState)); if (!state) { @@ -376,12 +405,9 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, ff_jpegls_reset_coding_parameters(state, 0); ff_jpegls_init_state(state); - if (s->bits <= 8) - shift = point_transform + (8 - s->bits); - else - shift = point_transform + (16 - s->bits); + shift = point_transform; - if (shift >= 16) { + if (shift > s->bits) { ret = AVERROR_INVALIDDATA; goto end; } @@ -400,59 +426,106 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, ret = AVERROR_INVALIDDATA; goto end; } + + s->restart_count = s->restart_interval; + if (ilv == 0) { /* separate planes */ + int init_RSTn = 1; if (s->cur_scan > s->nb_components) { ret = AVERROR_INVALIDDATA; goto end; } - stride = (s->nb_components > 1) ? 3 : 1; - off = av_clip(s->cur_scan - 1, 0, stride - 1); - width = s->width * stride; - cur += off; + cmp = av_clip(s->cur_scan - 1, 0, s->nb_components - 1); + cur[cmp] = s->picture_ptr->data[cmp]; + last[cmp] = zero; for (i = 0; i < s->height; i++) { - int ret; - if (s->bits <= 8) { - ret = ls_decode_line(state, s, last, cur, t, width, stride, off, 8); - t = last[0]; - } else { - ret = ls_decode_line(state, s, last, cur, t, width, stride, off, 16); - t = *((uint16_t *)last); - } + ret = ls_decode_line(state, s, last[cmp], cur[cmp], Rc[cmp], s->width, 1, cmp, s->bits); + Rc[cmp] = (s->bits <= 8 ? last[cmp][0] : ((uint16_t *)(last[cmp]))[0]); if (ret < 0) break; - last = cur; - cur += s->picture_ptr->linesize[0]; + last[cmp] = cur[cmp]; + cur[cmp] += s->picture_ptr->linesize[cmp]; - if (s->restart_interval && !--s->restart_count) { - align_get_bits(&s->gb); - skip_bits(&s->gb, 16); /* skip RSTn */ + if (s->restart_interval && !--s->restart_count && i != s->height - 1) { + ret = ls_decode_skip_restart_marker(s, init_RSTn); + if (ret < 0) + break; + + /* Reset decoder, skip RSTn */ + s->restart_count = s->restart_interval; + ff_jpegls_init_state(state); + init_RSTn = 0; + last[cmp] = zero; + Rc[cmp] = 0; } } decoded_height = i; } else if (ilv == 1) { /* line interleaving */ - int j; - int Rc[3] = { 0, 0, 0 }; - stride = (s->nb_components > 1) ? 3 : 1; - memset(cur, 0, s->picture_ptr->linesize[0]); - width = s->width * stride; - for (i = 0; i < s->height; i++) { - int ret; - for (j = 0; j < stride; j++) { - ret = ls_decode_line(state, s, last + j, cur + j, - Rc[j], width, stride, j, 8); + int init_RSTn = 1; + if (s->rgb && s->nb_components == 3 && s->v_max == 1 && s->h_max == 1) /* RGB 444 */ + { + cur[0] = s->picture_ptr->data[0]; + last[0] = zero; + + for (i = 0; i < s->height; i++) { + for (cmp = 0; cmp < s->nb_components; cmp++) { + ret = ls_decode_line(state, s, last[0] + cmp, cur[0] + cmp, Rc[cmp], s->width * s->nb_components, s->nb_components, cmp, s->bits); + if (ret < 0) + break; + Rc[cmp] = (s->bits <= 8 ? last[0][cmp] : ((uint16_t *)(last[0]))[cmp]); + } + if (ret < 0) + break; + last[0] = cur[0]; + cur[0] += s->picture_ptr->linesize[0]; + + if (s->restart_interval && !--s->restart_count && i != s->height - 1) { + ret = ls_decode_skip_restart_marker(s, init_RSTn); + if (ret < 0) + break; + + /* Reset decoder, skip RSTn */ + s->restart_count = s->restart_interval; + ff_jpegls_init_state(state); + init_RSTn = 0; + last[0] = zero; + Rc[0] = 0; + } + } + } else { /* YUV 444, 422, 420, 411 */ + for (cmp = 0; cmp < s->nb_components; cmp++) { + cur[cmp] = s->picture_ptr->data[cmp]; + last[cmp] = zero; + } + for (i = 0; i < s->height; i += s->v_max) { + for (cmp = 0; cmp < s->nb_components; cmp++) { + for (m = 0; m < (cmp ? 1 : s->v_max) ; m++) { + ret = ls_decode_line(state, s, last[cmp], cur[cmp], Rc[cmp], s->width / (cmp ? s->h_max : 1), 1, cmp, s->bits); + Rc[cmp] = (s->bits <= 8 ? last[cmp][0] : ((uint16_t *)(last[cmp]))[0]); + if (ret < 0) + break; + last[cmp] = cur[cmp]; + cur[cmp] += s->picture_ptr->linesize[cmp]; + } + } if (ret < 0) break; - Rc[j] = last[j]; - if (s->restart_interval && !--s->restart_count) { - align_get_bits(&s->gb); - skip_bits(&s->gb, 16); /* skip RSTn */ + if (s->restart_interval && !--s->restart_count && i != s->height - s->v_max) { + ret = ls_decode_skip_restart_marker(s, init_RSTn); + if (ret < 0) + break; + + /* Reset decoder, skip RSTn */ + s->restart_count = s->restart_interval; + ff_jpegls_init_state(state); + init_RSTn = 0; + for (cmp = 0; cmp < s->nb_components; cmp++) { + Rc[cmp] = 0; + last[cmp] = zero; + } } } - if (ret < 0) - break; - last = cur; - cur += s->picture_ptr->linesize[0]; } decoded_height = i; } else if (ilv == 2) { /* sample interleaving */ @@ -465,73 +538,78 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, goto end; } - if (s->xfrm && s->nb_components == 3) { - int x, w; - - w = s->width * s->nb_components; + w = s->width; + cmp = (ilv == 0 ? av_clip(s->cur_scan, 0, s->nb_components) : s->nb_components); /* end component */ + is_last_cmp = (cmp == 3 || s->nb_components == 1 ? 1 : 0); + if (s->xfrm && s->nb_components == 3 && is_last_cmp) { if (s->bits <= 8) { - uint8_t *src = s->picture_ptr->data[0]; + uint8_t *src[3]; + src[0] = s->picture_ptr->data[0]; + src[1] = s->picture_ptr->data[1]; + src[2] = s->picture_ptr->data[2]; - for (i = 0; i < s->height; i++) { + for (i = 0; i < decoded_height; i++) { switch(s->xfrm) { case 1: - for (x = off; x < w; x += 3) { - src[x ] += src[x+1] + 128; - src[x+2] += src[x+1] + 128; + for (x = 0; x < w; x++) { + src[0][x] += src[1][x] + 128; + src[2][x] += src[1][x] + 128; } break; case 2: - for (x = off; x < w; x += 3) { - src[x ] += src[x+1] + 128; - src[x+2] += ((src[x ] + src[x+1])>>1) + 128; + for (x = 0; x < w; x++) { + src[0][x] += src[1][x] + 128; + src[2][x] += ((src[0][x] + src[1][x])>>1) + 128; } break; case 3: - for (x = off; x < w; x += 3) { - int g = src[x+0] - ((src[x+2]+src[x+1])>>2) + 64; - src[x+0] = src[x+2] + g + 128; - src[x+2] = src[x+1] + g + 128; - src[x+1] = g; + for (x = 0; x < w; x++) { + int g = src[0][x] - ((src[2][x]+src[1][x])>>2) + 64; + src[0][x] = src[2][x] + g + 128; + src[2][x] = src[1][x] + g + 128; + src[1][x] = g; } break; case 4: - for (x = off; x < w; x += 3) { - int r = src[x+0] - (( 359 * (src[x+2]-128) + 490) >> 8); - int g = src[x+0] - (( 88 * (src[x+1]-128) - 183 * (src[x+2]-128) + 30) >> 8); - int b = src[x+0] + ((454 * (src[x+1]-128) + 574) >> 8); - src[x+0] = av_clip_uint8(r); - src[x+1] = av_clip_uint8(g); - src[x+2] = av_clip_uint8(b); + for (x = 0; x < w; x++) { + int r = src[0][x] - (( 359 * (src[2][x]-128) + 490) >> 8); + int g = src[0][x] - (( 88 * (src[1][x]-128) - 183 * (src[2][x]-128) + 30) >> 8); + int b = src[0][x] + ((454 * (src[1][x]-128) + 574) >> 8); + src[0][x] = av_clip_uint8(r); + src[1][x] = av_clip_uint8(g); + src[2][x] = av_clip_uint8(b); } break; } - src += s->picture_ptr->linesize[0]; + src[0] += s->picture_ptr->linesize[0]; + src[1] += s->picture_ptr->linesize[1]; + src[2] += s->picture_ptr->linesize[2]; } - }else + } else avpriv_report_missing_feature(s->avctx, "16bit xfrm"); } - if (shift) { /* we need to do point transform or normalize samples */ - int x, w; + if (shift && is_last_cmp) { /* we need to do point transform or normalize samples */ - w = s->width * s->nb_components; - if (s->bits <= 8) { - uint8_t *src = s->picture_ptr->data[0]; + for (cmp = 0; cmp < s->nb_components; cmp++) { + if (s->bits <= 8) { + uint8_t *src = s->picture_ptr->data[cmp]; - for (i = 0; i < decoded_height; i++) { - for (x = off; x < w; x += stride) - src[x] <<= shift; - src += s->picture_ptr->linesize[0]; - } - } else { - uint16_t *src = (uint16_t *)s->picture_ptr->data[0]; + for (i = 0; i < decoded_height / (cmp ? s->v_max : 1); i++) { + for (x = 0; x < w / (cmp ? s->h_max : 1); x++) + src[x] <<= shift; + src += s->picture_ptr->linesize[cmp]; + } + } else { + uint16_t *src = (uint16_t *)s->picture_ptr->data[cmp]; - for (i = 0; i < decoded_height; i++) { - for (x = 0; x < w; x++) - src[x] <<= shift; - src += s->picture_ptr->linesize[0] / 2; + for (i = 0; i < decoded_height / (cmp ? s->v_max : 1); i++) { + for (x = 0; x < w / (cmp ? s->h_max : 1); x++) + src[x] <<= shift; + src += s->picture_ptr->linesize[cmp] / 2; + } } } } @@ -543,12 +621,28 @@ end: return ret; } +#define OFFSET(x) offsetof(MJpegDecodeContext, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + { "rgb444", "Are RGB 444 JPEG-LS input images?", + OFFSET(rgb), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VD }, + { NULL }, +}; + +static const AVClass jpeglsdec_class = { + .class_name = "JPEG-LS decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_jpegls_decoder = { .name = "jpegls", .long_name = NULL_IF_CONFIG_SMALL("JPEG-LS"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_JPEGLS, .priv_data_size = sizeof(MJpegDecodeContext), + .priv_class = &jpeglsdec_class, .init = ff_mjpeg_decode_init, .close = ff_mjpeg_decode_end, .receive_frame = ff_mjpeg_receive_frame, diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index f3d9e99..952c5c4 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -352,10 +352,9 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) return AVERROR_INVALIDDATA; } } - if (s->ls && !(bits <= 8 || nb_components == 1)) { + if (s->ls && (bits < 8 || bits > 16)) { avpriv_report_missing_feature(s->avctx, - "JPEG-LS that is not <= 8 " - "bits/component or 16-bit gray"); + "JPEG-LS that is < 8 or > 16 bits/component"); return AVERROR_PATCHWELCOME; }