@@ -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;
+ }
}
/**
@@ -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];
@@ -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,
@@ -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;
}