X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fdfa.c;h=2654118fad0c7bfe2f729662ad63411009b7a4f3;hb=57ec83e4246b21c2f0c068b9151d806737d4497f;hp=b149791136cf96267f4d0080251b3b882640c395;hpb=d38345878cbb89e4d8d33bd79f47836d4e9cd637;p=ffmpeg diff --git a/libavcodec/dfa.c b/libavcodec/dfa.c index b149791136c..2654118fad0 100644 --- a/libavcodec/dfa.c +++ b/libavcodec/dfa.c @@ -20,14 +20,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "avcodec.h" -#include "libavutil/intreadwrite.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; @@ -35,59 +37,62 @@ 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); return 0; } -static int decode_copy(uint8_t *frame, int width, int height, - const uint8_t *src, const uint8_t *src_end) +static int decode_copy(GetByteContext *gb, uint8_t *frame, int width, int height) { const int size = width * height; - if (src_end - src < size) - return -1; - bytestream_get_buffer(&src, frame, size); + if (bytestream2_get_buffer(gb, frame, size) != size) + return AVERROR_INVALIDDATA; return 0; } -static int decode_tsw1(uint8_t *frame, int width, int height, - const uint8_t *src, const uint8_t *src_end) +static int decode_tsw1(GetByteContext *gb, uint8_t *frame, int width, int height) { const uint8_t *frame_start = frame; const uint8_t *frame_end = frame + width * height; int mask = 0x10000, bitbuf = 0; - int v, offset, count, segments; - - segments = bytestream_get_le32(&src); - frame += bytestream_get_le32(&src); - if (frame < frame_start || frame > frame_end) - return -1; + int v, count, segments; + unsigned offset; + + segments = bytestream2_get_le32(gb); + offset = bytestream2_get_le32(gb); + if (frame_end - frame <= offset) + return AVERROR_INVALIDDATA; + frame += offset; while (segments--) { + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; if (mask == 0x10000) { - if (src >= src_end) - return -1; - bitbuf = bytestream_get_le16(&src); + bitbuf = bytestream2_get_le16u(gb); mask = 1; } - if (src_end - src < 2 || frame_end - frame < 2) - return -1; + if (frame_end - frame < 2) + return AVERROR_INVALIDDATA; if (bitbuf & mask) { - v = bytestream_get_le16(&src); + 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 { - *frame++ = *src++; - *frame++ = *src++; + *frame++ = bytestream2_get_byte(gb); + *frame++ = bytestream2_get_byte(gb); } mask <<= 1; } @@ -95,39 +100,36 @@ static int decode_tsw1(uint8_t *frame, int width, int height, return 0; } -static int decode_dsw1(uint8_t *frame, int width, int height, - const uint8_t *src, const uint8_t *src_end) +static int decode_dsw1(GetByteContext *gb, uint8_t *frame, int width, int height) { const uint8_t *frame_start = frame; const uint8_t *frame_end = frame + width * height; int mask = 0x10000, bitbuf = 0; int v, offset, count, segments; - segments = bytestream_get_le16(&src); + segments = bytestream2_get_le16(gb); while (segments--) { + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; if (mask == 0x10000) { - if (src >= src_end) - return -1; - bitbuf = bytestream_get_le16(&src); + bitbuf = bytestream2_get_le16u(gb); mask = 1; } - if (src_end - src < 2 || frame_end - frame < 2) - return -1; + if (frame_end - frame < 2) + return AVERROR_INVALIDDATA; if (bitbuf & mask) { - v = bytestream_get_le16(&src); + 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 += bytestream_get_le16(&src); + frame += bytestream2_get_le16(gb); } else { - *frame++ = *src++; - *frame++ = *src++; + *frame++ = bytestream2_get_byte(gb); + *frame++ = bytestream2_get_byte(gb); } mask <<= 2; } @@ -135,30 +137,28 @@ static int decode_dsw1(uint8_t *frame, int width, int height, return 0; } -static int decode_dds1(uint8_t *frame, int width, int height, - const uint8_t *src, const uint8_t *src_end) +static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height) { const uint8_t *frame_start = frame; const uint8_t *frame_end = frame + width * height; int mask = 0x10000, bitbuf = 0; int i, v, offset, count, segments; - segments = bytestream_get_le16(&src); + segments = bytestream2_get_le16(gb); while (segments--) { + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; if (mask == 0x10000) { - if (src >= src_end) - return -1; - bitbuf = bytestream_get_le16(&src); + bitbuf = bytestream2_get_le16u(gb); mask = 1; } - if (src_end - src < 2 || frame_end - frame < 2) - return -1; + if (bitbuf & mask) { - v = bytestream_get_le16(&src); + 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]; @@ -166,13 +166,18 @@ static int decode_dds1(uint8_t *frame, int width, int height, frame += 2; } } else if (bitbuf & (mask << 1)) { - frame += bytestream_get_le16(&src) * 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] = *src++; + frame[width] = frame[width + 1] = bytestream2_get_byte(gb); frame += 2; frame[0] = frame[1] = - frame[width] = frame[width + 1] = *src++; + frame[width] = frame[width + 1] = bytestream2_get_byte(gb); frame += 2; } mask <<= 2; @@ -181,41 +186,40 @@ static int decode_dds1(uint8_t *frame, int width, int height, return 0; } -static int decode_bdlt(uint8_t *frame, int width, int height, - const uint8_t *src, const uint8_t *src_end) +static int decode_bdlt(GetByteContext *gb, uint8_t *frame, int width, int height) { - const uint8_t *frame_end = frame + width * height; uint8_t *line_ptr; int count, lines, segments; - count = bytestream_get_le16(&src); - if (count >= height || width * count < 0) - return -1; + count = bytestream2_get_le16(gb); + if (count >= height) + return AVERROR_INVALIDDATA; frame += width * count; - lines = bytestream_get_le16(&src); - if (frame + lines * width > frame_end || src >= src_end) - return -1; + lines = bytestream2_get_le16(gb); + if (count + lines > height) + return AVERROR_INVALIDDATA; while (lines--) { + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; line_ptr = frame; frame += width; - segments = *src++; + segments = bytestream2_get_byteu(gb); while (segments--) { - if (src_end - src < 3) - return -1; - line_ptr += *src++; - if (line_ptr >= frame) - return -1; - count = (int8_t)*src++; + if (frame - line_ptr <= bytestream2_peek_byte(gb)) + return AVERROR_INVALIDDATA; + line_ptr += bytestream2_get_byte(gb); + count = (int8_t)bytestream2_get_byte(gb); if (count >= 0) { - if (line_ptr + count > frame || src_end - src < count) - return -1; - bytestream_get_buffer(&src, line_ptr, count); + if (frame - line_ptr < count) + return AVERROR_INVALIDDATA; + if (bytestream2_get_buffer(gb, line_ptr, count) != count) + return AVERROR_INVALIDDATA; } else { count = -count; - if (line_ptr + count > frame || src >= src_end) - return -1; - memset(line_ptr, *src++, count); + if (frame - line_ptr < count) + return AVERROR_INVALIDDATA; + memset(line_ptr, bytestream2_get_byte(gb), count); } line_ptr += count; } @@ -224,48 +228,55 @@ static int decode_bdlt(uint8_t *frame, int width, int height, return 0; } -static int decode_wdlt(uint8_t *frame, int width, int height, - const uint8_t *src, const uint8_t *src_end) +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 = bytestream_get_le16(&src); - if (frame + lines * width > frame_end || src >= src_end) - return -1; + lines = bytestream2_get_le16(gb); + if (lines > height) + return AVERROR_INVALIDDATA; while (lines--) { - segments = bytestream_get_le16(&src); + if (bytestream2_get_bytes_left(gb) < 2) + return AVERROR_INVALIDDATA; + segments = bytestream2_get_le16u(gb); while ((segments & 0xC000) == 0xC000) { - frame -= (int16_t)segments * width; - if (frame >= frame_end) - return -1; - segments = bytestream_get_le16(&src); + unsigned skip_lines = -(int16_t)segments; + unsigned delta = -((int16_t)segments * width); + 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) { frame[width - 1] = segments & 0xFF; - segments = bytestream_get_le16(&src); + segments = bytestream2_get_le16(gb); } line_ptr = frame; + if (frame_end - frame < width) + return AVERROR_INVALIDDATA; frame += width; + y++; while (segments--) { - if (src_end - src < 2) - return -1; - line_ptr += *src++; - if (line_ptr >= frame) - return -1; - count = (int8_t)*src++; + if (frame - line_ptr <= bytestream2_peek_byte(gb)) + return AVERROR_INVALIDDATA; + line_ptr += bytestream2_get_byte(gb); + count = (int8_t)bytestream2_get_byte(gb); if (count >= 0) { - if (line_ptr + count*2 > frame || src_end - src < count*2) - return -1; - bytestream_get_buffer(&src, line_ptr, count*2); + if (frame - line_ptr < count * 2) + return AVERROR_INVALIDDATA; + if (bytestream2_get_buffer(gb, line_ptr, count * 2) != count * 2) + return AVERROR_INVALIDDATA; line_ptr += count * 2; } else { count = -count; - if (line_ptr + count*2 > frame || src_end - src < 2) - return -1; - v = bytestream_get_le16(&src); + if (frame - line_ptr < count * 2) + return AVERROR_INVALIDDATA; + v = bytestream2_get_le16(gb); for (i = 0; i < count; i++) bytestream_put_le16(&line_ptr, v); } @@ -275,96 +286,102 @@ static int decode_wdlt(uint8_t *frame, int width, int height, return 0; } -static int decode_unk6(uint8_t *frame, int width, int height, - const uint8_t *src, const uint8_t *src_end) +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(uint8_t *frame, int width, int height, - const uint8_t *src, const uint8_t *src_end) +static int decode_blck(GetByteContext *gb, uint8_t *frame, int width, int height) { memset(frame, 0, width * height); return 0; } -typedef int (*chunk_decoder)(uint8_t *frame, int width, int height, - const uint8_t *src, const uint8_t *src_end); +typedef int (*chunk_decoder)(GetByteContext *gb, uint8_t *frame, int width, int height); 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" +static const char * const chunk_name[8] = { + "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; - const uint8_t *buf_end = avpkt->data + avpkt->size; - const uint8_t *tmp_buf; uint32_t chunk_type, chunk_size; uint8_t *dst; 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; } - while (buf < buf_end) { - chunk_size = AV_RL32(buf + 4); - chunk_type = AV_RL32(buf + 8); - buf += 12; - if (buf_end - buf < chunk_size) { - av_log(avctx, AV_LOG_ERROR, "Chunk size is too big (%d bytes)\n", chunk_size); - return -1; - } + bytestream2_init(&gb, avpkt->data, avpkt->size); + while (bytestream2_get_bytes_left(&gb) > 0) { + bytestream2_skip(&gb, 4); + chunk_size = bytestream2_get_le32(&gb); + chunk_type = bytestream2_get_le32(&gb); if (!chunk_type) break; if (chunk_type == 1) { pal_elems = FFMIN(chunk_size / 3, 256); - tmp_buf = buf; for (i = 0; i < pal_elems; i++) { - s->pal[i] = bytestream_get_be24(&tmp_buf) << 2; + 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](s->frame_buf, avctx->width, avctx->height, - buf, buf + chunk_size)) { + 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; } @@ -373,23 +390,19 @@ 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; } AVCodec ff_dfa_decoder = { - "dfa", - AVMEDIA_TYPE_VIDEO, - CODEC_ID_DFA, - sizeof(DfaContext), - dfa_decode_init, - NULL, - dfa_decode_end, - dfa_decode_frame, - CODEC_CAP_DR1, - .long_name = NULL_IF_CONFIG_SMALL("Chronomaster DFA"), + .name = "dfa", + .long_name = NULL_IF_CONFIG_SMALL("Chronomaster DFA"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_DFA, + .priv_data_size = sizeof(DfaContext), + .init = dfa_decode_init, + .close = dfa_decode_end, + .decode = dfa_decode_frame, + .capabilities = AV_CODEC_CAP_DR1, };