X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fqtrle.c;h=4ad224e37d3aac191dd087b28c7fb1f9228a7de7;hb=bd96c54fe4819b3ca9a975e2083d67f4443c559b;hp=6155b4f3e3c979fcae1eb0ca6ac92421c4041992;hpb=b2f32d60eeaf883bb7d9e1b8cc2fb9a983d08f72;p=ffmpeg diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c index 6155b4f3e3c..4ad224e37d3 100644 --- a/libavcodec/qtrle.c +++ b/libavcodec/qtrle.c @@ -36,6 +36,7 @@ #include #include "avcodec.h" +#include "decode.h" #include "bytestream.h" #include "internal.h" @@ -297,10 +298,11 @@ static void qtrle_decode_16bpp(QtrleContext *s, int row_ptr, int lines_to_change static void qtrle_decode_24bpp(QtrleContext *s, int row_ptr, int lines_to_change) { - int rle_code; + int rle_code, rle_code_half; int pixel_ptr; int row_inc = s->frame->linesize[0]; - uint8_t r, g, b; + uint8_t b; + uint16_t rg; uint8_t *rgb = s->frame->data[0]; int pixel_limit = s->frame->linesize[0] * s->avctx->height; @@ -318,25 +320,31 @@ static void qtrle_decode_24bpp(QtrleContext *s, int row_ptr, int lines_to_change } else if (rle_code < 0) { /* decode the run length code */ rle_code = -rle_code; - r = bytestream2_get_byte(&s->g); - g = bytestream2_get_byte(&s->g); + rg = bytestream2_get_ne16(&s->g); b = bytestream2_get_byte(&s->g); CHECK_PIXEL_PTR(rle_code * 3); while (rle_code--) { - rgb[pixel_ptr++] = r; - rgb[pixel_ptr++] = g; - rgb[pixel_ptr++] = b; + AV_WN16(rgb + pixel_ptr, rg); + rgb[pixel_ptr + 2] = b; + pixel_ptr += 3; } } else { CHECK_PIXEL_PTR(rle_code * 3); - /* copy pixels directly to output */ - while (rle_code--) { - rgb[pixel_ptr++] = bytestream2_get_byte(&s->g); - rgb[pixel_ptr++] = bytestream2_get_byte(&s->g); - rgb[pixel_ptr++] = bytestream2_get_byte(&s->g); + rle_code_half = rle_code / 2; + + while (rle_code_half--) { /* copy 2 raw rgb value at the same time */ + AV_WN32(rgb + pixel_ptr, bytestream2_get_ne32(&s->g)); /* rgbr */ + AV_WN16(rgb + pixel_ptr + 4, bytestream2_get_ne16(&s->g)); /* rgbr */ + pixel_ptr += 6; + } + + if (rle_code % 2 != 0){ /* not even raw value */ + AV_WN16(rgb + pixel_ptr, bytestream2_get_ne16(&s->g)); + rgb[pixel_ptr + 2] = bytestream2_get_byte(&s->g); + pixel_ptr += 3; } } } @@ -346,7 +354,7 @@ static void qtrle_decode_24bpp(QtrleContext *s, int row_ptr, int lines_to_change static void qtrle_decode_32bpp(QtrleContext *s, int row_ptr, int lines_to_change) { - int rle_code; + int rle_code, rle_code_half; int pixel_ptr; int row_inc = s->frame->linesize[0]; unsigned int argb; @@ -367,7 +375,7 @@ static void qtrle_decode_32bpp(QtrleContext *s, int row_ptr, int lines_to_change } else if (rle_code < 0) { /* decode the run length code */ rle_code = -rle_code; - argb = bytestream2_get_be32(&s->g); + argb = bytestream2_get_ne32(&s->g); CHECK_PIXEL_PTR(rle_code * 4); @@ -379,10 +387,15 @@ static void qtrle_decode_32bpp(QtrleContext *s, int row_ptr, int lines_to_change CHECK_PIXEL_PTR(rle_code * 4); /* copy pixels directly to output */ - while (rle_code--) { - argb = bytestream2_get_be32(&s->g); - AV_WN32A(rgb + pixel_ptr, argb); - pixel_ptr += 4; + rle_code_half = rle_code / 2; + while (rle_code_half--) { /* copy 2 argb raw value at the same time */ + AV_WN64(rgb + pixel_ptr, bytestream2_get_ne64(&s->g)); + pixel_ptr += 8; + } + + if (rle_code % 2 != 0){ /* not even raw value */ + AV_WN32A(rgb + pixel_ptr, bytestream2_get_ne32(&s->g)); + pixel_ptr += 4; } } } @@ -416,7 +429,7 @@ static av_cold int qtrle_decode_init(AVCodecContext *avctx) break; case 32: - avctx->pix_fmt = AV_PIX_FMT_RGB32; + avctx->pix_fmt = AV_PIX_FMT_ARGB; break; default: @@ -440,35 +453,45 @@ static int qtrle_decode_frame(AVCodecContext *avctx, int header, start_line; int height, row_ptr; int has_palette = 0; - int ret; + int duplicate = 0; + int ret, size; bytestream2_init(&s->g, avpkt->data, avpkt->size); /* check if this frame is even supposed to change */ - if (avpkt->size < 8) - return avpkt->size; + if (avpkt->size < 8) { + duplicate = 1; + goto done; + } /* start after the chunk size */ - bytestream2_seek(&s->g, 4, SEEK_SET); + size = bytestream2_get_be32(&s->g) & 0x3FFFFFFF; + if (size - avpkt->size > size * (int64_t)avctx->discard_damaged_percentage / 100) + return AVERROR_INVALIDDATA; + /* fetch the header */ header = bytestream2_get_be16(&s->g); /* if a header is present, fetch additional decoding parameters */ if (header & 0x0008) { - if (avpkt->size < 14) - return avpkt->size; + if (avpkt->size < 14) { + duplicate = 1; + goto done; + } start_line = bytestream2_get_be16(&s->g); bytestream2_skip(&s->g, 2); height = bytestream2_get_be16(&s->g); bytestream2_skip(&s->g, 2); - if (height > s->avctx->height - start_line) - return avpkt->size; + if (height > s->avctx->height - start_line) { + duplicate = 1; + goto done; + } } else { start_line = 0; height = s->avctx->height; } - if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) + if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) return ret; row_ptr = s->frame->linesize[0] * start_line; @@ -517,20 +540,23 @@ static int qtrle_decode_frame(AVCodecContext *avctx, } if(has_palette) { - int size; - const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size); - - if (pal && size == AVPALETTE_SIZE) { - s->frame->palette_has_changed = 1; - memcpy(s->pal, pal, AVPALETTE_SIZE); - } else if (pal) { - av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", size); - } + s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx); /* make the palette available on the way out */ memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); } +done: + if (!s->frame->data[0]) + return AVERROR_INVALIDDATA; + if (duplicate) { + // ff_reget_buffer() isn't needed when frames don't change, so just update + // frame props. + ret = ff_decode_frame_props(avctx, s->frame); + if (ret < 0) + return ret; + } + if ((ret = av_frame_ref(data, s->frame)) < 0) return ret; *got_frame = 1; @@ -539,6 +565,13 @@ static int qtrle_decode_frame(AVCodecContext *avctx, return avpkt->size; } +static void qtrle_decode_flush(AVCodecContext *avctx) +{ + QtrleContext *s = avctx->priv_data; + + av_frame_unref(s->frame); +} + static av_cold int qtrle_decode_end(AVCodecContext *avctx) { QtrleContext *s = avctx->priv_data; @@ -548,7 +581,7 @@ static av_cold int qtrle_decode_end(AVCodecContext *avctx) return 0; } -AVCodec ff_qtrle_decoder = { +const AVCodec ff_qtrle_decoder = { .name = "qtrle", .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"), .type = AVMEDIA_TYPE_VIDEO, @@ -557,5 +590,6 @@ AVCodec ff_qtrle_decoder = { .init = qtrle_decode_init, .close = qtrle_decode_end, .decode = qtrle_decode_frame, + .flush = qtrle_decode_flush, .capabilities = AV_CODEC_CAP_DR1, };