X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fqtrle.c;h=52394f526404bf79a3910531f32b7a8a2e006bd2;hb=b8a0be93528187721a2414f66abbc252a258afa3;hp=bb55ba8a86aac100a664451792904fd12d2bb975;hpb=5496a734882cad54fda2c3528f16488dcac3b0a1;p=ffmpeg diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c index bb55ba8a86a..52394f52640 100644 --- a/libavcodec/qtrle.c +++ b/libavcodec/qtrle.c @@ -297,10 +297,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 +319,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 +353,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; @@ -379,10 +386,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_ne32(&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; } } } @@ -440,35 +452,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; @@ -531,6 +553,17 @@ static int qtrle_decode_frame(AVCodecContext *avctx, 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 +572,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; @@ -557,5 +597,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, };