X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fdfa.c;h=6fa4edc4005c32cf0595831e4ec4147efdd4402e;hb=a4edaeb50fc7510f28a5d79349a7926a182c9930;hp=788e9ca90a148d4bb1b98882a18cee362ef9081b;hpb=00c3b67b8ac6bfdc5a01535173dc537824a53d6e;p=ffmpeg diff --git a/libavcodec/dfa.c b/libavcodec/dfa.c index 788e9ca90a1..6fa4edc4005 100644 --- a/libavcodec/dfa.c +++ b/libavcodec/dfa.c @@ -20,13 +20,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "avcodec.h" #include "bytestream.h" -#include "libavutil/lzo.h" // for av_memcpy_backptr +#include "internal.h" -typedef struct DfaContext { - AVFrame pic; +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +typedef struct DfaContext { uint32_t pal[256]; uint8_t *frame_buf; } DfaContext; @@ -34,10 +37,14 @@ typedef struct DfaContext { static av_cold int dfa_decode_init(AVCodecContext *avctx) { DfaContext *s = avctx->priv_data; + int ret; + + avctx->pix_fmt = AV_PIX_FMT_PAL8; - avctx->pix_fmt = PIX_FMT_PAL8; + if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0) + return ret; - s->frame_buf = av_mallocz(avctx->width * avctx->height + AV_LZO_OUTPUT_PADDING); + s->frame_buf = av_mallocz(avctx->width * avctx->height); if (!s->frame_buf) return AVERROR(ENOMEM); @@ -49,7 +56,7 @@ static int decode_copy(GetByteContext *gb, uint8_t *frame, int width, int height const int size = width * height; if (bytestream2_get_buffer(gb, frame, size) != size) - return -1; + return AVERROR_INVALIDDATA; return 0; } @@ -64,23 +71,23 @@ static int decode_tsw1(GetByteContext *gb, uint8_t *frame, int width, int height segments = bytestream2_get_le32(gb); offset = bytestream2_get_le32(gb); if (frame_end - frame <= offset) - return -1; + return AVERROR_INVALIDDATA; frame += offset; while (segments--) { if (bytestream2_get_bytes_left(gb) < 2) - return -1; + return AVERROR_INVALIDDATA; if (mask == 0x10000) { bitbuf = bytestream2_get_le16u(gb); mask = 1; } if (frame_end - frame < 2) - return -1; + return AVERROR_INVALIDDATA; if (bitbuf & mask) { v = bytestream2_get_le16(gb); offset = (v & 0x1FFF) << 1; count = ((v >> 13) + 2) << 1; if (frame - frame_start < offset || frame_end - frame < count) - return -1; + return AVERROR_INVALIDDATA; av_memcpy_backptr(frame, offset, count); frame += count; } else { @@ -103,22 +110,20 @@ static int decode_dsw1(GetByteContext *gb, uint8_t *frame, int width, int height segments = bytestream2_get_le16(gb); while (segments--) { if (bytestream2_get_bytes_left(gb) < 2) - return -1; + return AVERROR_INVALIDDATA; if (mask == 0x10000) { bitbuf = bytestream2_get_le16u(gb); mask = 1; } if (frame_end - frame < 2) - return -1; + return AVERROR_INVALIDDATA; if (bitbuf & mask) { v = bytestream2_get_le16(gb); offset = (v & 0x1FFF) << 1; count = ((v >> 13) + 2) << 1; if (frame - frame_start < offset || frame_end - frame < count) - return -1; - // can't use av_memcpy_backptr() since it can overwrite following pixels - for (v = 0; v < count; v++) - frame[v] = frame[v - offset]; + return AVERROR_INVALIDDATA; + av_memcpy_backptr(frame, offset, count); frame += count; } else if (bitbuf & (mask << 1)) { frame += bytestream2_get_le16(gb); @@ -142,19 +147,18 @@ static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height segments = bytestream2_get_le16(gb); while (segments--) { if (bytestream2_get_bytes_left(gb) < 2) - return -1; + return AVERROR_INVALIDDATA; if (mask == 0x10000) { bitbuf = bytestream2_get_le16u(gb); mask = 1; } - if (frame_end - frame < 2) - return -1; + if (bitbuf & mask) { v = bytestream2_get_le16(gb); offset = (v & 0x1FFF) << 2; count = ((v >> 13) + 2) << 1; if (frame - frame_start < offset || frame_end - frame < count*2 + width) - return -1; + return AVERROR_INVALIDDATA; for (i = 0; i < count; i++) { frame[0] = frame[1] = frame[width] = frame[width + 1] = frame[-offset]; @@ -162,8 +166,13 @@ static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height frame += 2; } } else if (bitbuf & (mask << 1)) { - frame += bytestream2_get_le16(gb) * 2; + v = bytestream2_get_le16(gb)*2; + if (frame - frame_end < v) + return AVERROR_INVALIDDATA; + frame += v; } else { + if (frame_end - frame < width + 3) + return AVERROR_INVALIDDATA; frame[0] = frame[1] = frame[width] = frame[width + 1] = bytestream2_get_byte(gb); frame += 2; @@ -184,32 +193,32 @@ static int decode_bdlt(GetByteContext *gb, uint8_t *frame, int width, int height count = bytestream2_get_le16(gb); if (count >= height) - return -1; + return AVERROR_INVALIDDATA; frame += width * count; lines = bytestream2_get_le16(gb); if (count + lines > height) - return -1; + return AVERROR_INVALIDDATA; while (lines--) { if (bytestream2_get_bytes_left(gb) < 1) - return -1; + return AVERROR_INVALIDDATA; line_ptr = frame; frame += width; segments = bytestream2_get_byteu(gb); while (segments--) { if (frame - line_ptr <= bytestream2_peek_byte(gb)) - return -1; + return AVERROR_INVALIDDATA; line_ptr += bytestream2_get_byte(gb); count = (int8_t)bytestream2_get_byte(gb); if (count >= 0) { if (frame - line_ptr < count) - return -1; + return AVERROR_INVALIDDATA; if (bytestream2_get_buffer(gb, line_ptr, count) != count) - return -1; + return AVERROR_INVALIDDATA; } else { count = -count; if (frame - line_ptr < count) - return -1; + return AVERROR_INVALIDDATA; memset(line_ptr, bytestream2_get_byte(gb), count); } line_ptr += count; @@ -224,20 +233,23 @@ static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height const uint8_t *frame_end = frame + width * height; uint8_t *line_ptr; int count, i, v, lines, segments; + int y = 0; lines = bytestream2_get_le16(gb); if (lines > height) - return -1; + return AVERROR_INVALIDDATA; while (lines--) { if (bytestream2_get_bytes_left(gb) < 2) - return -1; + return AVERROR_INVALIDDATA; segments = bytestream2_get_le16u(gb); while ((segments & 0xC000) == 0xC000) { + unsigned skip_lines = -(int16_t)segments; unsigned delta = -((int16_t)segments * width); - if (frame_end - frame <= delta) - return -1; + if (frame_end - frame <= delta || y + lines + skip_lines > height) + return AVERROR_INVALIDDATA; frame += delta; + y += skip_lines; segments = bytestream2_get_le16(gb); } if (segments & 0x8000) { @@ -245,22 +257,25 @@ static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height segments = bytestream2_get_le16(gb); } line_ptr = frame; + if (frame_end - frame < width) + return AVERROR_INVALIDDATA; frame += width; + y++; while (segments--) { if (frame - line_ptr <= bytestream2_peek_byte(gb)) - return -1; + return AVERROR_INVALIDDATA; line_ptr += bytestream2_get_byte(gb); count = (int8_t)bytestream2_get_byte(gb); if (count >= 0) { if (frame - line_ptr < count * 2) - return -1; + return AVERROR_INVALIDDATA; if (bytestream2_get_buffer(gb, line_ptr, count * 2) != count * 2) - return -1; + return AVERROR_INVALIDDATA; line_ptr += count * 2; } else { count = -count; if (frame - line_ptr < count * 2) - return -1; + return AVERROR_INVALIDDATA; v = bytestream2_get_le16(gb); for (i = 0; i < count; i++) bytestream_put_le16(&line_ptr, v); @@ -271,9 +286,26 @@ static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height return 0; } -static int decode_unk6(GetByteContext *gb, uint8_t *frame, int width, int height) +static int decode_tdlt(GetByteContext *gb, uint8_t *frame, int width, int height) { - return -1; + const uint8_t *frame_end = frame + width * height; + int segments = bytestream2_get_le32(gb); + int skip, copy; + + while (segments--) { + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; + copy = bytestream2_get_byteu(gb) * 2; + skip = bytestream2_get_byteu(gb) * 2; + if (frame_end - frame < copy + skip || + bytestream2_get_bytes_left(gb) < copy) + return AVERROR_INVALIDDATA; + frame += skip; + bytestream2_get_buffer(gb, frame, copy); + frame += copy; + } + + return 0; } static int decode_blck(GetByteContext *gb, uint8_t *frame, int width, int height) @@ -287,17 +319,18 @@ typedef int (*chunk_decoder)(GetByteContext *gb, uint8_t *frame, int width, int static const chunk_decoder decoder[8] = { decode_copy, decode_tsw1, decode_bdlt, decode_wdlt, - decode_unk6, decode_dsw1, decode_blck, decode_dds1, + decode_tdlt, decode_dsw1, decode_blck, decode_dds1, }; static const char* chunk_name[8] = { - "COPY", "TSW1", "BDLT", "WDLT", "????", "DSW1", "BLCK", "DDS1" + "COPY", "TSW1", "BDLT", "WDLT", "TDLT", "DSW1", "BLCK", "DDS1" }; static int dfa_decode_frame(AVCodecContext *avctx, - void *data, int *data_size, + void *data, int *got_frame, AVPacket *avpkt) { + AVFrame *frame = data; DfaContext *s = avctx->priv_data; GetByteContext gb; const uint8_t *buf = avpkt->data; @@ -306,10 +339,7 @@ static int dfa_decode_frame(AVCodecContext *avctx, int ret; int i, pal_elems; - if (s->pic.data[0]) - avctx->release_buffer(avctx, &s->pic); - - if ((ret = avctx->get_buffer(avctx, &s->pic))) { + if ((ret = ff_get_buffer(avctx, frame, 0))) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); return ret; } @@ -327,31 +357,31 @@ static int dfa_decode_frame(AVCodecContext *avctx, s->pal[i] = bytestream2_get_be24(&gb) << 2; s->pal[i] |= (s->pal[i] >> 6) & 0x333; } - s->pic.palette_has_changed = 1; + frame->palette_has_changed = 1; } else if (chunk_type <= 9) { if (decoder[chunk_type - 2](&gb, s->frame_buf, avctx->width, avctx->height)) { av_log(avctx, AV_LOG_ERROR, "Error decoding %s chunk\n", chunk_name[chunk_type - 2]); - return -1; + return AVERROR_INVALIDDATA; } } else { - av_log(avctx, AV_LOG_WARNING, "Ignoring unknown chunk type %d\n", + av_log(avctx, AV_LOG_WARNING, + "Ignoring unknown chunk type %"PRIu32"\n", chunk_type); } buf += chunk_size; } buf = s->frame_buf; - dst = s->pic.data[0]; + dst = frame->data[0]; for (i = 0; i < avctx->height; i++) { memcpy(dst, buf, avctx->width); - dst += s->pic.linesize[0]; + dst += frame->linesize[0]; buf += avctx->width; } - memcpy(s->pic.data[1], s->pal, sizeof(s->pal)); + memcpy(frame->data[1], s->pal, sizeof(s->pal)); - *data_size = sizeof(AVFrame); - *(AVFrame*)data = s->pic; + *got_frame = 1; return avpkt->size; } @@ -360,9 +390,6 @@ static av_cold int dfa_decode_end(AVCodecContext *avctx) { DfaContext *s = avctx->priv_data; - if (s->pic.data[0]) - avctx->release_buffer(avctx, &s->pic); - av_freep(&s->frame_buf); return 0; @@ -370,12 +397,12 @@ static av_cold int dfa_decode_end(AVCodecContext *avctx) AVCodec ff_dfa_decoder = { .name = "dfa", + .long_name = NULL_IF_CONFIG_SMALL("Chronomaster DFA"), .type = AVMEDIA_TYPE_VIDEO, - .id = CODEC_ID_DFA, + .id = AV_CODEC_ID_DFA, .priv_data_size = sizeof(DfaContext), .init = dfa_decode_init, .close = dfa_decode_end, .decode = dfa_decode_frame, .capabilities = CODEC_CAP_DR1, - .long_name = NULL_IF_CONFIG_SMALL("Chronomaster DFA"), };