1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-11-26 19:01:44 +02:00

avcodec/clearvideo: Avoid allocations when decoding tiles

Up until now, the ClearVideo decoder separates parsing tiles
and actually using the parsed information: The information is
instead stored in structures which are constantly allocated
and freed. This commit changes this to use the information
immediately, avoiding said allocations. This e.g. reduced
the amount of allocations for [1] from 2,866,462 to 24,720.
For said sample decoding speed improved by 143%.

[1]: https://samples.ffmpeg.org/V-codecs/UCOD/AccordianDance-300.avi

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
This commit is contained in:
Andreas Rheinhardt 2022-11-07 01:36:57 +01:00
parent 165682a6d4
commit 65f3bc9e7e

View File

@ -59,13 +59,6 @@ typedef struct MVInfo {
MV *mv; MV *mv;
} MVInfo; } MVInfo;
typedef struct TileInfo {
uint16_t flags;
int16_t bias;
MV mv;
struct TileInfo *child[4];
} TileInfo;
typedef struct CLVContext { typedef struct CLVContext {
AVCodecContext *avctx; AVCodecContext *avctx;
IDCTDSPContext idsp; IDCTDSPContext idsp;
@ -383,12 +376,16 @@ static int tile_do_block(AVCodecContext *avctx, AVFrame *dst, const AVFrame *src
return ret; return ret;
} }
static TileInfo *decode_tile_info(GetBitContext *gb, const LevelCodes *lc) static int decode_tile(AVCodecContext *avctx, GetBitContext *gb,
const LevelCodes *lc,
AVFrame *dst, const AVFrame *src,
int plane, int x, int y, int size,
MV root_mv, MV *pred)
{ {
TileInfo *ti;
int i, flags = 0; int i, flags = 0;
int16_t bias = 0; int16_t bias = 0;
MV mv = { 0 }; MV mv = { 0 };
int err;
if (lc->flags_cb.table) if (lc->flags_cb.table)
flags = get_vlc2(gb, lc->flags_cb.table, CLV_VLC_BITS, 2); flags = get_vlc2(gb, lc->flags_cb.table, CLV_VLC_BITS, 2);
@ -403,7 +400,11 @@ static TileInfo *decode_tile_info(GetBitContext *gb, const LevelCodes *lc)
mv.x = get_sbits(gb, 8); mv.x = get_sbits(gb, 8);
mv.y = get_sbits(gb, 8); mv.y = get_sbits(gb, 8);
} }
if (pred)
mvi_update_prediction(pred, mv);
} }
mv.x += root_mv.x;
mv.y += root_mv.y;
if (lc->bias_cb.table) { if (lc->bias_cb.table) {
uint16_t bias_val = get_vlc2(gb, lc->bias_cb.table, CLV_VLC_BITS, 2); uint16_t bias_val = get_vlc2(gb, lc->bias_cb.table, CLV_VLC_BITS, 2);
@ -415,55 +416,29 @@ static TileInfo *decode_tile_info(GetBitContext *gb, const LevelCodes *lc)
} }
} }
ti = av_calloc(1, sizeof(*ti)); if (flags) {
if (!ti) int hsize = size >> 1;
return NULL;
ti->flags = flags;
ti->mv = mv;
ti->bias = bias;
if (ti->flags) {
for (i = 0; i < 4; i++) {
if (ti->flags & (1 << i)) {
TileInfo *subti = decode_tile_info(gb, lc + 1);
ti->child[i] = subti;
}
}
}
return ti;
}
static int restore_tree(AVCodecContext *avctx, AVFrame *dst, AVFrame *src,
int plane, int x, int y, int size,
TileInfo *tile, MV root_mv)
{
int ret;
MV mv;
mv.x = root_mv.x + tile->mv.x;
mv.y = root_mv.y + tile->mv.y;
if (!tile->flags) {
ret = tile_do_block(avctx, dst, src, plane, x, y, mv.x, mv.y, size, tile->bias);
} else {
int i, hsize = size >> 1;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
int xoff = (i & 2) == 0 ? 0 : hsize; int xoff = (i & 2) == 0 ? 0 : hsize;
int yoff = (i & 1) == 0 ? 0 : hsize; int yoff = (i & 1) == 0 ? 0 : hsize;
if (tile->child[i]) { if (flags & (1 << i)) {
ret = restore_tree(avctx, dst, src, plane, x + xoff, y + yoff, hsize, tile->child[i], root_mv); err = decode_tile(avctx, gb, lc + 1, dst, src, plane,
av_freep(&tile->child[i]); x + xoff, y + yoff, hsize, root_mv, NULL);
} else { } else {
ret = tile_do_block(avctx, dst, src, plane, x + xoff, y + yoff, mv.x, mv.y, hsize, tile->bias); err = tile_do_block(avctx, dst, src, plane, x + xoff, y + yoff,
mv.x, mv.y, hsize, bias);
} }
if (err < 0)
return err;
} }
} else {
err = tile_do_block(avctx, dst, src, plane, x, y, mv.x, mv.y, size, bias);
if (err < 0)
return err;
} }
return ret; return 0;
} }
static void extend_edges(AVFrame *buf, int tile_size) static void extend_edges(AVFrame *buf, int tile_size)
@ -604,38 +579,26 @@ static int clv_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
int x = i << c->tile_shift; int x = i << c->tile_shift;
int y = j << c->tile_shift; int y = j << c->tile_shift;
int size = 1 << c->tile_shift; int size = 1 << c->tile_shift;
TileInfo *tile;
MV cmv; MV cmv;
tile = decode_tile_info(&c->gb, &lev[0]); // Y ret = decode_tile(avctx, &c->gb, &lev[0], c->pic, c->prev, // Y
if (!tile) 0, x, y, size, mv, mvp);
return AVERROR(ENOMEM);
ret = restore_tree(avctx, c->pic, c->prev, 0, x, y, size, tile, mv);
if (ret < 0) if (ret < 0)
mb_ret = ret; mb_ret = ret;
mvi_update_prediction(mvp, tile->mv);
x = i << (c->tile_shift - 1); x = i << (c->tile_shift - 1);
y = j << (c->tile_shift - 1); y = j << (c->tile_shift - 1);
size = 1 << (c->tile_shift - 1); size = 1 << (c->tile_shift - 1);
cmv.x = mv.x + tile->mv.x; cmv = *mvp;
cmv.y = mv.y + tile->mv.y;
cmv.x /= 2; cmv.x /= 2;
cmv.y /= 2; cmv.y /= 2;
av_freep(&tile); ret = decode_tile(avctx, &c->gb, &lev[4], c->pic, c->prev, // U
tile = decode_tile_info(&c->gb, &lev[4]); // U 1, x, y, size, cmv, NULL);
if (!tile)
return AVERROR(ENOMEM);
ret = restore_tree(avctx, c->pic, c->prev, 1, x, y, size, tile, cmv);
if (ret < 0) if (ret < 0)
mb_ret = ret; mb_ret = ret;
av_freep(&tile); ret = decode_tile(avctx, &c->gb, &lev[7], c->pic, c->prev, // U
tile = decode_tile_info(&c->gb, &lev[7]); // V 2, x, y, size, cmv, NULL);
if (!tile)
return AVERROR(ENOMEM);
ret = restore_tree(avctx, c->pic, c->prev, 2, x, y, size, tile, cmv);
if (ret < 0) if (ret < 0)
mb_ret = ret; mb_ret = ret;
av_freep(&tile);
} }
} }
mvi_update_row(&c->mvi); mvi_update_row(&c->mvi);