Commit 33cd32b3 authored by Ronald S. Bultje's avatar Ronald S. Bultje

kgv1: use avctx->get/release_buffer().

Also fixes crashes on corrupt bitstreams.

Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind
CC: libav-stable@libav.org
parent d6a77e2b
...@@ -30,10 +30,17 @@ ...@@ -30,10 +30,17 @@
typedef struct { typedef struct {
AVCodecContext *avctx; AVCodecContext *avctx;
AVFrame pic; AVFrame prev, cur;
uint16_t *prev, *cur;
} KgvContext; } KgvContext;
static void decode_flush(AVCodecContext *avctx)
{
KgvContext * const c = avctx->priv_data;
if (c->prev.data[0])
avctx->release_buffer(avctx, &c->prev);
}
static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt)
{ {
const uint8_t *buf = avpkt->data; const uint8_t *buf = avpkt->data;
...@@ -42,7 +49,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac ...@@ -42,7 +49,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac
int offsets[8]; int offsets[8];
uint16_t *out, *prev; uint16_t *out, *prev;
int outcnt = 0, maxcnt; int outcnt = 0, maxcnt;
int w, h, i; int w, h, i, res;
if (avpkt->size < 2) if (avpkt->size < 2)
return -1; return -1;
...@@ -59,15 +66,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac ...@@ -59,15 +66,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac
maxcnt = w * h; maxcnt = w * h;
out = av_realloc(c->cur, w * h * 2); c->cur.reference = 3;
if (!out) if ((res = avctx->get_buffer(avctx, &c->cur)) < 0)
return -1; return res;
c->cur = out; out = (uint16_t *) c->cur.data[0];
if (c->prev.data[0]) {
prev = av_realloc(c->prev, w * h * 2); prev = (uint16_t *) c->prev.data[0];
if (!prev) } else {
return -1; prev = NULL;
c->prev = prev; }
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
offsets[i] = -1; offsets[i] = -1;
...@@ -80,6 +87,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac ...@@ -80,6 +87,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac
out[outcnt++] = code; // rgb555 pixel coded directly out[outcnt++] = code; // rgb555 pixel coded directly
} else { } else {
int count; int count;
int inp_off;
uint16_t *inp; uint16_t *inp;
if ((code & 0x6000) == 0x6000) { if ((code & 0x6000) == 0x6000) {
...@@ -101,7 +109,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac ...@@ -101,7 +109,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac
if (maxcnt - start < count) if (maxcnt - start < count)
break; break;
inp = prev + start; if (!prev) {
av_log(avctx, AV_LOG_ERROR,
"Frame reference does not exist\n");
break;
}
inp = prev;
inp_off = start;
} else { } else {
// copy from earlier in this frame // copy from earlier in this frame
int offset = (code & 0x1FFF) + 1; int offset = (code & 0x1FFF) + 1;
...@@ -119,27 +134,28 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac ...@@ -119,27 +134,28 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac
if (outcnt < offset) if (outcnt < offset)
break; break;
inp = out + outcnt - offset; inp = out;
inp_off = outcnt - offset;
} }
if (maxcnt - outcnt < count) if (maxcnt - outcnt < count)
break; break;
for (i = 0; i < count; i++) for (i = inp_off; i < count + inp_off; i++) {
out[outcnt++] = inp[i]; out[outcnt++] = inp[i];
} }
} }
}
if (outcnt - maxcnt) if (outcnt - maxcnt)
av_log(avctx, AV_LOG_DEBUG, "frame finished with %d diff\n", outcnt - maxcnt); av_log(avctx, AV_LOG_DEBUG, "frame finished with %d diff\n", outcnt - maxcnt);
c->pic.data[0] = (uint8_t *)c->cur;
c->pic.linesize[0] = w * 2;
*data_size = sizeof(AVFrame); *data_size = sizeof(AVFrame);
*(AVFrame*)data = c->pic; *(AVFrame*)data = c->cur;
FFSWAP(uint16_t *, c->cur, c->prev); if (c->prev.data[0])
avctx->release_buffer(avctx, &c->prev);
FFSWAP(AVFrame, c->cur, c->prev);
return avpkt->size; return avpkt->size;
} }
...@@ -150,17 +166,14 @@ static av_cold int decode_init(AVCodecContext *avctx) ...@@ -150,17 +166,14 @@ static av_cold int decode_init(AVCodecContext *avctx)
c->avctx = avctx; c->avctx = avctx;
avctx->pix_fmt = PIX_FMT_RGB555; avctx->pix_fmt = PIX_FMT_RGB555;
avctx->flags |= CODEC_FLAG_EMU_EDGE;
return 0; return 0;
} }
static av_cold int decode_end(AVCodecContext *avctx) static av_cold int decode_end(AVCodecContext *avctx)
{ {
KgvContext * const c = avctx->priv_data; decode_flush(avctx);
av_freep(&c->cur);
av_freep(&c->prev);
return 0; return 0;
} }
...@@ -172,5 +185,6 @@ AVCodec ff_kgv1_decoder = { ...@@ -172,5 +185,6 @@ AVCodec ff_kgv1_decoder = {
.init = decode_init, .init = decode_init,
.close = decode_end, .close = decode_end,
.decode = decode_frame, .decode = decode_frame,
.flush = decode_flush,
.long_name = NULL_IF_CONFIG_SMALL("Kega Game Video"), .long_name = NULL_IF_CONFIG_SMALL("Kega Game Video"),
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment