avcodec/mjpegdec: postpone calling ff_get_buffer() until the SOS marker

With JPEG-LS PAL8 samples, the JPEG-LS extension parameters signaled with
the LSE marker show up after SOF but before SOS. For those, the pixel format
chosen by get_format() in SOF is GRAY8, and then replaced by PAL8 in LSE.
This has not been an issue given both pixel formats allocate the second data
plane for the palette, but after the upcoming soname bump, GRAY8 will no longer
do that. This will result in segfauls when ff_jpegls_decode_lse() attempts to
write the palette on a buffer originally allocated as a GRAY8 one.

Work around this by calling ff_get_buffer() after the actual pixel format is
known.

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer 2021-04-21 13:33:33 -03:00
parent bc27269694
commit c8197f73e6
5 changed files with 56 additions and 39 deletions

View File

@ -108,9 +108,8 @@ int ff_jpegls_decode_lse(MJpegDecodeContext *s)
if (s->palette_index > maxtab)
return AVERROR_INVALIDDATA;
if ((s->avctx->pix_fmt == AV_PIX_FMT_GRAY8 || s->avctx->pix_fmt == AV_PIX_FMT_PAL8) &&
(s->picture_ptr->format == AV_PIX_FMT_GRAY8 || s->picture_ptr->format == AV_PIX_FMT_PAL8)) {
uint32_t *pal = (uint32_t *)s->picture_ptr->data[1];
if (s->avctx->pix_fmt == AV_PIX_FMT_GRAY8 || s->avctx->pix_fmt == AV_PIX_FMT_PAL8) {
uint32_t *pal = s->palette;
int shift = 0;
if (s->avctx->bits_per_raw_sample > 0 && s->avctx->bits_per_raw_sample < 8) {
@ -118,7 +117,6 @@ int ff_jpegls_decode_lse(MJpegDecodeContext *s)
shift = 8 - s->avctx->bits_per_raw_sample;
}
s->picture_ptr->format =
s->avctx->pix_fmt = AV_PIX_FMT_PAL8;
for (i=s->palette_index; i<=maxtab; i++) {
uint8_t k = i << shift;

View File

@ -55,6 +55,7 @@ static int mjpegb_decode_frame(AVCodecContext *avctx,
buf_ptr = buf;
buf_end = buf + buf_size;
s->seen_sof = 0;
s->got_picture = 0;
s->adobe_transform = -1;

View File

@ -138,6 +138,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx)
s->buffer = NULL;
s->start_code = -1;
s->first_picture = 1;
s->seen_sof = 0;
s->got_picture = 0;
s->orig_height = avctx->coded_height;
avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
@ -429,6 +430,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
memcpy(s->h_count, h_count, sizeof(h_count));
memcpy(s->v_count, v_count, sizeof(v_count));
s->interlaced = 0;
s->seen_sof = 0;
s->got_picture = 0;
/* test interlaced mode */
@ -681,11 +683,13 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
} 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
} else if (s->bits <= 8) {
avpriv_set_systematic_pal2(s->palette, s->avctx->pix_fmt);
if (s->palette_index)
s->avctx->pix_fmt = AV_PIX_FMT_PAL8;
else
s->avctx->pix_fmt = AV_PIX_FMT_GRAY8;
} else
s->avctx->pix_fmt = AV_PIX_FMT_GRAY16;
}
@ -719,26 +723,13 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
if (s->avctx->skip_frame == AVDISCARD_ALL) {
s->picture_ptr->pict_type = AV_PICTURE_TYPE_I;
s->picture_ptr->key_frame = 1;
s->got_picture = 1;
s->seen_sof = 1;
return 0;
}
av_frame_unref(s->picture_ptr);
if (ff_get_buffer(s->avctx, s->picture_ptr, AV_GET_BUFFER_FLAG_REF) < 0)
return -1;
s->picture_ptr->pict_type = AV_PICTURE_TYPE_I;
s->picture_ptr->key_frame = 1;
s->got_picture = 1;
for (i = 0; i < 4; i++)
s->linesize[i] = s->picture_ptr->linesize[i] << s->interlaced;
ff_dlog(s->avctx, "%d %d %d %d %d %d\n",
s->width, s->height, s->linesize[0], s->linesize[1],
s->interlaced, s->avctx->height);
}
s->seen_sof = 1;
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)
@ -764,18 +755,6 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
memset(s->coefs_finished, 0, sizeof(s->coefs_finished));
}
if (s->avctx->hwaccel) {
s->hwaccel_picture_private =
av_mallocz(s->avctx->hwaccel->frame_priv_data_size);
if (!s->hwaccel_picture_private)
return AVERROR(ENOMEM);
ret = s->avctx->hwaccel->start_frame(s->avctx, s->raw_image_buffer,
s->raw_image_buffer_size);
if (ret < 0)
return ret;
}
return 0;
}
@ -1630,12 +1609,44 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask,
const int block_size = s->lossless ? 1 : 8;
int ilv, prev_shift;
if (!s->got_picture) {
if (!s->seen_sof) {
av_log(s->avctx, AV_LOG_WARNING,
"Can not process SOS before SOF, skipping\n");
return -1;
}
if (!s->got_picture || !s->interlaced || !(s->bottom_field == !s->interlace_polarity)) {
av_frame_unref(s->picture_ptr);
if (ff_get_buffer(s->avctx, s->picture_ptr, AV_GET_BUFFER_FLAG_REF) < 0)
return -1;
s->picture_ptr->pict_type = AV_PICTURE_TYPE_I;
s->picture_ptr->key_frame = 1;
for (i = 0; i < 4; i++)
s->linesize[i] = s->picture_ptr->linesize[i] << s->interlaced;
if (s->picture_ptr->format == AV_PIX_FMT_PAL8)
memcpy(s->picture_ptr->data[1], s->palette, sizeof(s->palette));
s->got_picture = 1;
ff_dlog(s->avctx, "%d %d %d %d %d %d\n",
s->width, s->height, s->linesize[0], s->linesize[1],
s->interlaced, s->avctx->height);
if (s->avctx->hwaccel && !s->hwaccel_picture_private) {
s->hwaccel_picture_private =
av_mallocz(s->avctx->hwaccel->frame_priv_data_size);
if (!s->hwaccel_picture_private)
return AVERROR(ENOMEM);
ret = s->avctx->hwaccel->start_frame(s->avctx, s->raw_image_buffer,
s->raw_image_buffer_size);
if (ret < 0)
return ret;
}
}
if (reference) {
if (reference->width != s->picture_ptr->width ||
reference->height != s->picture_ptr->height ||
@ -2561,6 +2572,7 @@ eoi_parser:
break;
}
if (avctx->skip_frame == AVDISCARD_ALL) {
s->seen_sof = 0;
s->got_picture = 0;
ret = AVERROR(EAGAIN);
goto the_end_no_picture;
@ -2574,6 +2586,7 @@ eoi_parser:
}
if ((ret = av_frame_ref(frame, s->picture_ptr)) < 0)
return ret;
s->seen_sof = 0;
s->got_picture = 0;
frame->pkt_dts = s->pkt->dts;
@ -2634,6 +2647,7 @@ skip:
av_log(avctx, AV_LOG_FATAL, "No JPEG data found in image\n");
return AVERROR_INVALIDDATA;
fail:
s->seen_sof = 0;
s->got_picture = 0;
return ret;
the_end:
@ -2924,6 +2938,7 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx)
static void decode_flush(AVCodecContext *avctx)
{
MJpegDecodeContext *s = avctx->priv_data;
s->seen_sof = 0;
s->got_picture = 0;
s->smv_next_frame = 0;

View File

@ -109,6 +109,7 @@ typedef struct MJpegDecodeContext {
int last_dc[MAX_COMPONENTS]; /* last DEQUANTIZED dc (XXX: am I right to do that ?) */
AVFrame *picture; /* picture structure */
AVFrame *picture_ptr; /* pointer to picture structure */
int seen_sof; ///< we found a SOF.
int got_picture; ///< we found a SOF and picture is valid, too.
int linesize[MAX_COMPONENTS]; ///< linesize << interlaced
int8_t *qscale_table;
@ -165,7 +166,9 @@ typedef struct MJpegDecodeContext {
enum AVPixelFormat hwaccel_sw_pix_fmt;
enum AVPixelFormat hwaccel_pix_fmt;
void *hwaccel_picture_private;
struct JLSState *jls_state;
uint32_t palette[AVPALETTE_COUNT];
} MJpegDecodeContext;
int ff_mjpeg_build_vlc(VLC *vlc, const uint8_t *bits_table,

View File

@ -197,7 +197,7 @@ static int mxpeg_decode_frame(AVCodecContext *avctx,
buf_end = buf + buf_size;
jpg->got_picture = 0;
s->got_mxm_bitmask = 0;
s->got_sof_data = !!s->got_sof_data;
jpg->seen_sof = s->got_sof_data = !!s->got_sof_data;
while (buf_ptr < buf_end) {
start_code = ff_mjpeg_find_marker(jpg, &buf_ptr, buf_end,
&unescaped_buf_ptr, &unescaped_buf_size);