diff --git a/libavcodec/dxtory.c b/libavcodec/dxtory.c index 23a3c6f..0a6f331 100644 --- a/libavcodec/dxtory.c +++ b/libavcodec/dxtory.c @@ -192,6 +192,56 @@ static inline uint8_t decode_sym(GetBitContext *gb, uint8_t lru[8]) return val; } +static int check_slice_size(AVCodecContext *avctx, + const uint8_t *src, int src_size, + int slice_size, int off) +{ + int cur_slice_size; + + if (slice_size > src_size - off) { + av_log(avctx, AV_LOG_ERROR, + "invalid slice size %"PRIu32" (only %"PRIu32" bytes left)\n", + slice_size, src_size - off); + return AVERROR_INVALIDDATA; + } + if (slice_size <= 16) { + av_log(avctx, AV_LOG_ERROR, "invalid slice size %"PRIu32"\n", + slice_size); + return AVERROR_INVALIDDATA; + } + + cur_slice_size = AV_RL32(src + off); + if (cur_slice_size != slice_size - 16) { + av_log(avctx, AV_LOG_ERROR, + "Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n", + cur_slice_size, slice_size - 16); + } + + return 0; +} + +static int load_buffer(AVCodecContext *avctx, + const uint8_t *src, int src_size, + GetByteContext *gb, + int *nslices, int *off) +{ + bytestream2_init(gb, src, src_size); + *nslices = bytestream2_get_le16(gb); + *off = FFALIGN(*nslices * 4 + 2, 16); + if (src_size < *off) { + av_log(avctx, AV_LOG_ERROR, "no slice data\n"); + return AVERROR_INVALIDDATA; + } + + if (!*nslices) { + avpriv_request_sample(avctx, "%d slices for %dx%d", *nslices, + avctx->width, avctx->height); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + static inline uint8_t decode_sym_565(GetBitContext *gb, uint8_t lru[8], int bits) { @@ -210,185 +260,182 @@ static inline uint8_t decode_sym_565(GetBitContext *gb, uint8_t lru[8], return val; } -static int dx2_decode_slice_565(GetBitContext *gb, int width, int height, - uint8_t *dst, int stride, int is_565) -{ - int x, y; - int r, g, b; - uint8_t lru[3][8]; - - memcpy(lru[0], def_lru_555, 8 * sizeof(*def_lru)); - memcpy(lru[1], is_565 ? def_lru_565 : def_lru_555, 8 * sizeof(*def_lru)); - memcpy(lru[2], def_lru_555, 8 * sizeof(*def_lru)); - - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - b = decode_sym_565(gb, lru[0], 5); - g = decode_sym_565(gb, lru[1], is_565 ? 6 : 5); - r = decode_sym_565(gb, lru[2], 5); - dst[x * 3 + 0] = (r << 3) | (r >> 2); - dst[x * 3 + 1] = is_565 ? (g << 2) | (g >> 4) : (g << 3) | (g >> 2); - dst[x * 3 + 2] = (b << 3) | (b >> 2); - } - - dst += stride; - } +typedef int (*decode_slice_func)(GetBitContext *gb, AVFrame *frame, + int line, int height, uint8_t lru[3][8]); - return 0; -} +typedef void (*setup_lru_func)(uint8_t lru[3][8]); -static int dxtory_decode_v2_565(AVCodecContext *avctx, AVFrame *pic, - const uint8_t *src, int src_size, int is_565) +static int dxtory_decode_v2(AVCodecContext *avctx, AVFrame *pic, + const uint8_t *src, int src_size, + decode_slice_func decode_slice, + setup_lru_func setup_lru, + enum AVPixelFormat fmt) { GetByteContext gb; GetBitContext gb2; - int nslices, slice, slice_height; + int nslices, slice, line = 0; uint32_t off, slice_size; - uint8_t *dst; + uint8_t lru[3][8]; int ret; - bytestream2_init(&gb, src, src_size); - nslices = bytestream2_get_le16(&gb); - off = FFALIGN(nslices * 4 + 2, 16); - if (src_size < off) { - av_log(avctx, AV_LOG_ERROR, "no slice data\n"); - return AVERROR_INVALIDDATA; - } - - if (!nslices || avctx->height % nslices) { - avpriv_request_sample(avctx, "%d slices for %dx%d", nslices, - avctx->width, avctx->height); - return AVERROR_PATCHWELCOME; - } + ret = load_buffer(avctx, src, src_size, &gb, &nslices, &off); + if (ret < 0) + return ret; - slice_height = avctx->height / nslices; - avctx->pix_fmt = AV_PIX_FMT_RGB24; + avctx->pix_fmt = fmt; if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; - dst = pic->data[0]; for (slice = 0; slice < nslices; slice++) { slice_size = bytestream2_get_le32(&gb); - if (slice_size > src_size - off) { - av_log(avctx, AV_LOG_ERROR, - "invalid slice size %"PRIu32" (only %"PRIu32" bytes left)\n", - slice_size, src_size - off); - return AVERROR_INVALIDDATA; - } - if (slice_size <= 16) { - av_log(avctx, AV_LOG_ERROR, "invalid slice size %"PRIu32"\n", slice_size); - return AVERROR_INVALIDDATA; - } - if (AV_RL32(src + off) != slice_size - 16) { - av_log(avctx, AV_LOG_ERROR, - "Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n", - AV_RL32(src + off), slice_size - 16); - } + setup_lru(lru); + + ret = check_slice_size(avctx, src, src_size, slice_size, off); + if (ret < 0) + return ret; + init_get_bits(&gb2, src + off + 16, (slice_size - 16) * 8); - dx2_decode_slice_565(&gb2, avctx->width, slice_height, dst, - pic->linesize[0], is_565); - dst += pic->linesize[0] * slice_height; + line += decode_slice(&gb2, pic, line, avctx->height - line, lru); + off += slice_size; } + if (avctx->height - line) { + av_log(avctx, AV_LOG_VERBOSE, + "Not enough slice data available, " + "cropping the frame by %d pixels\n", + avctx->height - line); + avctx->height = line; + } + return 0; } -static int dx2_decode_slice_rgb(GetBitContext *gb, int width, int height, - uint8_t *dst, int stride) +av_always_inline +static int dx2_decode_slice_5x5(GetBitContext *gb, AVFrame *frame, + int line, int left, uint8_t lru[3][8], + int is_565) { - int x, y, i; - uint8_t lru[3][8]; - - for (i = 0; i < 3; i++) - memcpy(lru[i], def_lru, 8 * sizeof(*def_lru)); + int x, y; + int r, g, b; + int width = frame->width; + int stride = frame->linesize[0]; + uint8_t *dst = frame->data[0] + stride * line; - for (y = 0; y < height; y++) { + for (y = 0; y < left && get_bits_left(gb) > 16; y++) { for (x = 0; x < width; x++) { - dst[x * 3 + 0] = decode_sym(gb, lru[0]); - dst[x * 3 + 1] = decode_sym(gb, lru[1]); - dst[x * 3 + 2] = decode_sym(gb, lru[2]); + b = decode_sym_565(gb, lru[0], 5); + g = decode_sym_565(gb, lru[1], is_565 ? 6 : 5); + r = decode_sym_565(gb, lru[2], 5); + dst[x * 3 + 0] = (r << 3) | (r >> 2); + dst[x * 3 + 1] = is_565 ? (g << 2) | (g >> 4) : (g << 3) | (g >> 2); + dst[x * 3 + 2] = (b << 3) | (b >> 2); } dst += stride; } - return 0; + return y; } -static int dxtory_decode_v2_rgb(AVCodecContext *avctx, AVFrame *pic, - const uint8_t *src, int src_size) +static void setup_lru_555(uint8_t lru[3][8]) { - GetByteContext gb; - GetBitContext gb2; - int nslices, slice, slice_height; - uint32_t off, slice_size; - uint8_t *dst; - int ret; + memcpy(lru[0], def_lru_555, 8 * sizeof(*def_lru)); + memcpy(lru[1], def_lru_555, 8 * sizeof(*def_lru)); + memcpy(lru[2], def_lru_555, 8 * sizeof(*def_lru)); +} - bytestream2_init(&gb, src, src_size); - nslices = bytestream2_get_le16(&gb); - off = FFALIGN(nslices * 4 + 2, 16); - if (src_size < off) { - av_log(avctx, AV_LOG_ERROR, "no slice data\n"); - return AVERROR_INVALIDDATA; - } +static void setup_lru_565(uint8_t lru[3][8]) +{ + memcpy(lru[0], def_lru_555, 8 * sizeof(*def_lru)); + memcpy(lru[1], def_lru_565, 8 * sizeof(*def_lru)); + memcpy(lru[2], def_lru_555, 8 * sizeof(*def_lru)); +} - if (!nslices || avctx->height % nslices) { - avpriv_request_sample(avctx, "%d slices for %dx%d", nslices, - avctx->width, avctx->height); - return AVERROR_PATCHWELCOME; - } +static int dx2_decode_slice_555(GetBitContext *gb, AVFrame *frame, + int line, int left, uint8_t lru[3][8]) +{ + return dx2_decode_slice_5x5(gb, frame, line, left, lru, 0); +} - slice_height = avctx->height / nslices; - avctx->pix_fmt = AV_PIX_FMT_BGR24; - if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) - return ret; +static int dx2_decode_slice_565(GetBitContext *gb, AVFrame *frame, + int line, int left, uint8_t lru[3][8]) +{ + return dx2_decode_slice_5x5(gb, frame, line, left, lru, 1); +} - dst = pic->data[0]; - for (slice = 0; slice < nslices; slice++) { - slice_size = bytestream2_get_le32(&gb); - if (slice_size > src_size - off) { - av_log(avctx, AV_LOG_ERROR, - "invalid slice size %"PRIu32" (only %"PRIu32" bytes left)\n", - slice_size, src_size - off); - return AVERROR_INVALIDDATA; - } - if (slice_size <= 16) { - av_log(avctx, AV_LOG_ERROR, "invalid slice size %"PRIu32"\n", - slice_size); - return AVERROR_INVALIDDATA; - } +static int dxtory_decode_v2_565(AVCodecContext *avctx, AVFrame *pic, + const uint8_t *src, int src_size, int is_565) +{ + enum AVPixelFormat fmt = AV_PIX_FMT_RGB24; + if (is_565) + return dxtory_decode_v2(avctx, pic, src, src_size, + dx2_decode_slice_565, + setup_lru_565, + fmt); + else + return dxtory_decode_v2(avctx, pic, src, src_size, + dx2_decode_slice_555, + setup_lru_555, + fmt); +} + +static int dx2_decode_slice_rgb(GetBitContext *gb, AVFrame *frame, + int line, int left, uint8_t lru[3][8]) +{ + int x, y; + int width = frame->width; + int stride = frame->linesize[0]; + uint8_t *dst = frame->data[0] + stride * line; - if (AV_RL32(src + off) != slice_size - 16) { - av_log(avctx, AV_LOG_ERROR, - "Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n", - AV_RL32(src + off), slice_size - 16); + for (y = 0; y < left && get_bits_left(gb) > 16; y++) { + for (x = 0; x < width; x++) { + dst[x * 3 + 0] = decode_sym(gb, lru[0]); + dst[x * 3 + 1] = decode_sym(gb, lru[1]); + dst[x * 3 + 2] = decode_sym(gb, lru[2]); } - init_get_bits(&gb2, src + off + 16, (slice_size - 16) * 8); - dx2_decode_slice_rgb(&gb2, avctx->width, slice_height, dst, - pic->linesize[0]); - dst += pic->linesize[0] * slice_height; - off += slice_size; + dst += stride; } - return 0; + return y; } -static int dx2_decode_slice_410(GetBitContext *gb, int width, int height, - uint8_t *Y, uint8_t *U, uint8_t *V, - int ystride, int ustride, int vstride) +static void default_setup_lru(uint8_t lru[3][8]) { - int x, y, i, j; - uint8_t lru[3][8]; + int i; for (i = 0; i < 3; i++) memcpy(lru[i], def_lru, 8 * sizeof(*def_lru)); +} - for (y = 0; y < height; y += 4) { +static int dxtory_decode_v2_rgb(AVCodecContext *avctx, AVFrame *pic, + const uint8_t *src, int src_size) +{ + return dxtory_decode_v2(avctx, pic, src, src_size, + dx2_decode_slice_rgb, + default_setup_lru, + AV_PIX_FMT_BGR24); +} + +static int dx2_decode_slice_410(GetBitContext *gb, AVFrame *frame, + int line, int left, + uint8_t lru[3][8]) +{ + int x, y, i, j; + int width = frame->width; + + int ystride = frame->linesize[0]; + int ustride = frame->linesize[1]; + int vstride = frame->linesize[2]; + + uint8_t *Y = frame->data[0] + ystride * line; + uint8_t *U = frame->data[1] + (ustride >> 2) * line; + uint8_t *V = frame->data[2] + (vstride >> 2) * line; + + for (y = 0; y < left - 3 && get_bits_left(gb) > 16; y += 4) { for (x = 0; x < width; x += 4) { for (j = 0; j < 4; j++) for (i = 0; i < 4; i++) @@ -402,96 +449,37 @@ static int dx2_decode_slice_410(GetBitContext *gb, int width, int height, V += vstride; } - return 0; + return y; } + static int dxtory_decode_v2_410(AVCodecContext *avctx, AVFrame *pic, const uint8_t *src, int src_size) { - GetByteContext gb; - GetBitContext gb2; - int nslices, slice, slice_height, ref_slice_height; - int cur_y, next_y; - uint32_t off, slice_size; - uint8_t *Y, *U, *V; - int ret; - - bytestream2_init(&gb, src, src_size); - nslices = bytestream2_get_le16(&gb); - off = FFALIGN(nslices * 4 + 2, 16); - if (src_size < off) { - av_log(avctx, AV_LOG_ERROR, "no slice data\n"); - return AVERROR_INVALIDDATA; - } - - if (!nslices || avctx->height % nslices) { - avpriv_request_sample(avctx, "%d slices for %dx%d", nslices, - avctx->width, avctx->height); - return AVERROR_PATCHWELCOME; - } - - ref_slice_height = avctx->height / nslices; - if ((avctx->width & 3) || (avctx->height & 3)) { - avpriv_request_sample(avctx, "Frame dimensions %dx%d", - avctx->width, avctx->height); - } - - avctx->pix_fmt = AV_PIX_FMT_YUV410P; - if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) - return ret; - - Y = pic->data[0]; - U = pic->data[1]; - V = pic->data[2]; + return dxtory_decode_v2(avctx, pic, src, src_size, + dx2_decode_slice_410, + default_setup_lru, + AV_PIX_FMT_YUV410P); +} - cur_y = 0; - next_y = ref_slice_height; - for (slice = 0; slice < nslices; slice++) { - slice_size = bytestream2_get_le32(&gb); - slice_height = (next_y & ~3) - (cur_y & ~3); - if (slice_size > src_size - off) { - av_log(avctx, AV_LOG_ERROR, - "invalid slice size %"PRIu32" (only %"PRIu32" bytes left)\n", - slice_size, src_size - off); - return AVERROR_INVALIDDATA; - } - if (slice_size <= 16) { - av_log(avctx, AV_LOG_ERROR, "invalid slice size %"PRIu32"\n", slice_size); - return AVERROR_INVALIDDATA; - } +static int dx2_decode_slice_420(GetBitContext *gb, AVFrame *frame, + int line, int left, + uint8_t lru[3][8]) +{ + int x, y; - if (AV_RL32(src + off) != slice_size - 16) { - av_log(avctx, AV_LOG_ERROR, - "Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n", - AV_RL32(src + off), slice_size - 16); - } - init_get_bits(&gb2, src + off + 16, (slice_size - 16) * 8); - dx2_decode_slice_410(&gb2, avctx->width, slice_height, Y, U, V, - pic->linesize[0], pic->linesize[1], - pic->linesize[2]); + int width = frame->width; - Y += pic->linesize[0] * slice_height; - U += pic->linesize[1] * (slice_height >> 2); - V += pic->linesize[2] * (slice_height >> 2); - off += slice_size; - cur_y = next_y; - next_y += ref_slice_height; - } + int ystride = frame->linesize[0]; + int ustride = frame->linesize[1]; + int vstride = frame->linesize[2]; - return 0; -} + uint8_t *Y = frame->data[0] + ystride * line; + uint8_t *U = frame->data[1] + (ustride >> 1) * line; + uint8_t *V = frame->data[2] + (vstride >> 1) * line; -static int dx2_decode_slice_420(GetBitContext *gb, int width, int height, - uint8_t *Y, uint8_t *U, uint8_t *V, - int ystride, int ustride, int vstride) -{ - int x, y, i; - uint8_t lru[3][8]; - for (i = 0; i < 3; i++) - memcpy(lru[i], def_lru, 8 * sizeof(*def_lru)); - - for (y = 0; y < height; y+=2) { + for (y = 0; y < left - 1 && get_bits_left(gb) > 16; y += 2) { for (x = 0; x < width; x += 2) { Y[x + 0 + 0 * ystride] = decode_sym(gb, lru[0]); Y[x + 1 + 0 * ystride] = decode_sym(gb, lru[0]); @@ -506,96 +494,35 @@ static int dx2_decode_slice_420(GetBitContext *gb, int width, int height, V += vstride; } - return 0; + return y; } static int dxtory_decode_v2_420(AVCodecContext *avctx, AVFrame *pic, const uint8_t *src, int src_size) { - GetByteContext gb; - GetBitContext gb2; - int nslices, slice, slice_height, ref_slice_height; - int cur_y, next_y; - uint32_t off, slice_size; - uint8_t *Y, *U, *V; - int ret; - - bytestream2_init(&gb, src, src_size); - nslices = bytestream2_get_le16(&gb); - off = FFALIGN(nslices * 4 + 2, 16); - if (src_size < off) { - av_log(avctx, AV_LOG_ERROR, "no slice data\n"); - return AVERROR_INVALIDDATA; - } - - if (!nslices || avctx->height % nslices) { - avpriv_request_sample(avctx, "%d slices for %dx%d", nslices, - avctx->width, avctx->height); - return AVERROR_PATCHWELCOME; - } - - ref_slice_height = avctx->height / nslices; - if ((avctx->width & 1) || (avctx->height & 1)) { - avpriv_request_sample(avctx, "Frame dimensions %dx%d", - avctx->width, avctx->height); - } - - avctx->pix_fmt = AV_PIX_FMT_YUV420P; - if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) - return ret; - - Y = pic->data[0]; - U = pic->data[1]; - V = pic->data[2]; - - cur_y = 0; - next_y = ref_slice_height; - for (slice = 0; slice < nslices; slice++) { - slice_size = bytestream2_get_le32(&gb); - slice_height = (next_y & ~1) - (cur_y & ~1); - if (slice_size > src_size - off) { - av_log(avctx, AV_LOG_ERROR, - "invalid slice size %"PRIu32" (only %"PRIu32" bytes left)\n", - slice_size, src_size - off); - return AVERROR_INVALIDDATA; - } - if (slice_size <= 16) { - av_log(avctx, AV_LOG_ERROR, "invalid slice size %"PRIu32"\n", slice_size); - return AVERROR_INVALIDDATA; - } - - if (AV_RL32(src + off) != slice_size - 16) { - av_log(avctx, AV_LOG_ERROR, - "Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n", - AV_RL32(src + off), slice_size - 16); - } - init_get_bits(&gb2, src + off + 16, (slice_size - 16) * 8); - dx2_decode_slice_420(&gb2, avctx->width, slice_height, Y, U, V, - pic->linesize[0], pic->linesize[1], - pic->linesize[2]); - - Y += pic->linesize[0] * slice_height; - U += pic->linesize[1] * (slice_height >> 1); - V += pic->linesize[2] * (slice_height >> 1); - off += slice_size; - cur_y = next_y; - next_y += ref_slice_height; - } - - return 0; + return dxtory_decode_v2(avctx, pic, src, src_size, + dx2_decode_slice_420, + default_setup_lru, + AV_PIX_FMT_YUV420P); } -static int dx2_decode_slice_444(GetBitContext *gb, int width, int height, - uint8_t *Y, uint8_t *U, uint8_t *V, - int ystride, int ustride, int vstride) +static int dx2_decode_slice_444(GetBitContext *gb, AVFrame *frame, + int line, int left, + uint8_t lru[3][8]) { - int x, y, i; - uint8_t lru[3][8]; + int x, y; - for (i = 0; i < 3; i++) - memcpy(lru[i], def_lru, 8 * sizeof(*def_lru)); + int width = frame->width; + + int ystride = frame->linesize[0]; + int ustride = frame->linesize[1]; + int vstride = frame->linesize[2]; + + uint8_t *Y = frame->data[0] + ystride * line; + uint8_t *U = frame->data[1] + ustride * line; + uint8_t *V = frame->data[2] + vstride * line; - for (y = 0; y < height; y++) { + for (y = 0; y < left && get_bits_left(gb) > 16; y++) { for (x = 0; x < width; x++) { Y[x] = decode_sym(gb, lru[0]); U[x] = decode_sym(gb, lru[1]) ^ 0x80; @@ -607,73 +534,16 @@ static int dx2_decode_slice_444(GetBitContext *gb, int width, int height, V += vstride; } - return 0; + return y; } static int dxtory_decode_v2_444(AVCodecContext *avctx, AVFrame *pic, const uint8_t *src, int src_size) { - GetByteContext gb; - GetBitContext gb2; - int nslices, slice, slice_height; - uint32_t off, slice_size; - uint8_t *Y, *U, *V; - int ret; - - bytestream2_init(&gb, src, src_size); - nslices = bytestream2_get_le16(&gb); - off = FFALIGN(nslices * 4 + 2, 16); - if (src_size < off) { - av_log(avctx, AV_LOG_ERROR, "no slice data\n"); - return AVERROR_INVALIDDATA; - } - - if (!nslices || avctx->height % nslices) { - avpriv_request_sample(avctx, "%d slices for %dx%d", nslices, - avctx->width, avctx->height); - return AVERROR_PATCHWELCOME; - } - - slice_height = avctx->height / nslices; - - avctx->pix_fmt = AV_PIX_FMT_YUV444P; - if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) - return ret; - - Y = pic->data[0]; - U = pic->data[1]; - V = pic->data[2]; - - for (slice = 0; slice < nslices; slice++) { - slice_size = bytestream2_get_le32(&gb); - if (slice_size > src_size - off) { - av_log(avctx, AV_LOG_ERROR, - "invalid slice size %"PRIu32" (only %"PRIu32" bytes left)\n", - slice_size, src_size - off); - return AVERROR_INVALIDDATA; - } - if (slice_size <= 16) { - av_log(avctx, AV_LOG_ERROR, "invalid slice size %"PRIu32"\n", slice_size); - return AVERROR_INVALIDDATA; - } - - if (AV_RL32(src + off) != slice_size - 16) { - av_log(avctx, AV_LOG_ERROR, - "Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n", - AV_RL32(src + off), slice_size - 16); - } - init_get_bits(&gb2, src + off + 16, (slice_size - 16) * 8); - dx2_decode_slice_444(&gb2, avctx->width, slice_height, Y, U, V, - pic->linesize[0], pic->linesize[1], - pic->linesize[2]); - - Y += pic->linesize[0] * slice_height; - U += pic->linesize[1] * slice_height; - V += pic->linesize[2] * slice_height; - off += slice_size; - } - - return 0; + return dxtory_decode_v2(avctx, pic, src, src_size, + dx2_decode_slice_444, + default_setup_lru, + AV_PIX_FMT_YUV444P); } static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,