avcodec/utvideodec: add vlc multi support

Faster decoding, by average 50% faster overall.
This commit is contained in:
Christophe Gisquet 2017-07-09 12:56:35 +00:00 committed by Paul B Mahol
parent 8b7391cb5f
commit da888b790a
2 changed files with 46 additions and 47 deletions

View File

@ -81,6 +81,7 @@ typedef struct UtvideoContext {
ptrdiff_t slice_stride;
uint8_t *slice_bits, *slice_buffer[4];
int slice_bits_size;
void *buffer;
const uint8_t *packed_stream[4][256];
size_t packed_stream_size[4][256];

View File

@ -46,7 +46,7 @@ typedef struct HuffEntry {
} HuffEntry;
static int build_huff(UtvideoContext *c, const uint8_t *src, VLC *vlc,
int *fsym, unsigned nb_elems)
VLC_MULTI *multi, int *fsym, unsigned nb_elems)
{
int i;
HuffEntry he[1024];
@ -82,11 +82,35 @@ static int build_huff(UtvideoContext *c, const uint8_t *src, VLC *vlc,
he[--codes_count[bits[i]]] = (HuffEntry) { bits[i], i };
#define VLC_BITS 11
return ff_init_vlc_from_lengths(vlc, VLC_BITS, codes_count[0],
return ff_init_vlc_multi_from_lengths(vlc, multi, VLC_BITS, nb_elems, codes_count[0],
&he[0].len, sizeof(*he),
&he[0].sym, sizeof(*he), 2, 0, 0, c->avctx);
}
#define READ_PLANE(b, end) \
{ \
buf = !use_pred ? dest : c->buffer; \
i = 0; \
for (; CACHED_BITSTREAM_READER && i < width-end && get_bits_left(&gb) > 0;) {\
ret = get_vlc_multi(&gb, (uint8_t *)buf + i * b, multi.table, \
vlc.table, VLC_BITS, 3); \
if (ret > 0) \
i += ret; \
if (ret <= 0) \
goto fail; \
} \
for (; i < width && get_bits_left(&gb) > 0; i++) \
buf[i] = get_vlc2(&gb, vlc.table, VLC_BITS, 3); \
if (use_pred) { \
if (b == 2) \
c->llviddsp.add_left_pred_int16((uint16_t *)dest, (const uint16_t *)buf, 0x3ff, width, prev); \
else \
c->llviddsp.add_left_pred((uint8_t *)dest, (const uint8_t *)buf, width, prev); \
} \
prev = dest[width-1]; \
dest += stride; \
}
static int decode_plane10(UtvideoContext *c, int plane_no,
uint16_t *dst, ptrdiff_t stride,
int width, int height,
@ -95,11 +119,12 @@ static int decode_plane10(UtvideoContext *c, int plane_no,
{
int i, j, slice, pix, ret;
int sstart, send;
VLC_MULTI multi;
VLC vlc;
GetBitContext gb;
int prev, fsym;
if ((ret = build_huff(c, huff, &vlc, &fsym, 1024)) < 0) {
if ((ret = build_huff(c, huff, &vlc, &multi, &fsym, 1024)) < 0) {
av_log(c->avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n");
return ret;
}
@ -131,7 +156,7 @@ static int decode_plane10(UtvideoContext *c, int plane_no,
send = 0;
for (slice = 0; slice < c->slices; slice++) {
uint16_t *dest;
uint16_t *dest, *buf;
int slice_data_start, slice_data_end, slice_size;
sstart = send;
@ -156,37 +181,20 @@ static int decode_plane10(UtvideoContext *c, int plane_no,
init_get_bits(&gb, c->slice_bits, slice_size * 8);
prev = 0x200;
for (j = sstart; j < send; j++) {
for (i = 0; i < width; i++) {
pix = get_vlc2(&gb, vlc.table, VLC_BITS, 3);
if (pix < 0) {
av_log(c->avctx, AV_LOG_ERROR, "Decoding error\n");
goto fail;
}
if (use_pred) {
prev += pix;
prev &= 0x3FF;
pix = prev;
}
dest[i] = pix;
}
dest += stride;
if (get_bits_left(&gb) < 0) {
av_log(c->avctx, AV_LOG_ERROR,
"Slice decoding ran out of bits\n");
goto fail;
}
}
for (j = sstart; j < send; j++)
READ_PLANE(2, 3)
if (get_bits_left(&gb) > 32)
av_log(c->avctx, AV_LOG_WARNING,
"%d bits left after decoding slice\n", get_bits_left(&gb));
}
ff_free_vlc(&vlc);
ff_free_vlc_multi(&multi);
return 0;
fail:
ff_free_vlc(&vlc);
ff_free_vlc_multi(&multi);
return AVERROR_INVALIDDATA;
}
@ -207,6 +215,7 @@ static int decode_plane(UtvideoContext *c, int plane_no,
{
int i, j, slice, pix;
int sstart, send;
VLC_MULTI multi;
VLC vlc;
GetBitContext gb;
int ret, prev, fsym;
@ -259,7 +268,7 @@ static int decode_plane(UtvideoContext *c, int plane_no,
return 0;
}
if (build_huff(c, src, &vlc, &fsym, 256)) {
if (build_huff(c, src, &vlc, &multi, &fsym, 256)) {
av_log(c->avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n");
return AVERROR_INVALIDDATA;
}
@ -292,7 +301,7 @@ static int decode_plane(UtvideoContext *c, int plane_no,
send = 0;
for (slice = 0; slice < c->slices; slice++) {
uint8_t *dest;
uint8_t *dest, *buf;
int slice_data_start, slice_data_end, slice_size;
sstart = send;
@ -317,36 +326,20 @@ static int decode_plane(UtvideoContext *c, int plane_no,
init_get_bits(&gb, c->slice_bits, slice_size * 8);
prev = 0x80;
for (j = sstart; j < send; j++) {
for (i = 0; i < width; i++) {
pix = get_vlc2(&gb, vlc.table, VLC_BITS, 3);
if (pix < 0) {
av_log(c->avctx, AV_LOG_ERROR, "Decoding error\n");
goto fail;
}
if (use_pred) {
prev += pix;
pix = prev;
}
dest[i] = pix;
}
if (get_bits_left(&gb) < 0) {
av_log(c->avctx, AV_LOG_ERROR,
"Slice decoding ran out of bits\n");
goto fail;
}
dest += stride;
}
for (j = sstart; j < send; j++)
READ_PLANE(1, 5)
if (get_bits_left(&gb) > 32)
av_log(c->avctx, AV_LOG_WARNING,
"%d bits left after decoding slice\n", get_bits_left(&gb));
}
ff_free_vlc(&vlc);
ff_free_vlc_multi(&multi);
return 0;
fail:
ff_free_vlc(&vlc);
ff_free_vlc_multi(&multi);
return AVERROR_INVALIDDATA;
}
@ -992,6 +985,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
c->buffer = av_calloc(avctx->width, c->pro?2:1);
if (!c->buffer)
return AVERROR(ENOMEM);
av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &h_shift, &v_shift);
if ((avctx->width & ((1<<h_shift)-1)) ||
(avctx->height & ((1<<v_shift)-1))) {
@ -1047,6 +1044,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
UtvideoContext * const c = avctx->priv_data;
av_freep(&c->slice_bits);
av_freep(&c->buffer);
return 0;
}