diff options
author | Ben Jackson <ben@ben.com> | 2012-09-15 10:32:43 -0700 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-09-15 20:26:47 +0200 |
commit | 39a3894ad50f97592ca68081095c5c2bcbcad841 (patch) | |
tree | fe3f9f40b82d01ac418c41f4797f65343b6d92d8 /libavcodec | |
parent | 1c20fcf0b0d30b63c33e4302c3d92b66b1665b33 (diff) | |
download | ffmpeg-39a3894ad50f97592ca68081095c5c2bcbcad841.tar.gz |
lavc/vp6: Implement "slice" threading for VP6A decode
The YUV channels of VP6 are encoded in a highly linear fashion which does
not have any slice-like concept to thread. The alpha channel of VP6A is
fairly independent of the YUV and comprises 40% of the work. This patch
uses the THREAD_SLICE capability to split the YUV and A decodes into
separate threads.
Two bugs are fixed by splitting YUV and alpha state:
- qscale_table from VP6A decode was for alpha channel instead of YUV
- alpha channel filtering settings were overwritten by YUV header parse
Signed-off-by: Ben Jackson <ben@ben.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/vp56.c | 103 | ||||
-rw-r--r-- | libavcodec/vp56.h | 5 | ||||
-rw-r--r-- | libavcodec/vp6.c | 21 |
3 files changed, 82 insertions, 47 deletions
diff --git a/libavcodec/vp56.c b/libavcodec/vp56.c index 7d771f31f7..0eb9314c48 100644 --- a/libavcodec/vp56.c +++ b/libavcodec/vp56.c @@ -449,9 +449,9 @@ static void vp56_decode_mb(VP56Context *s, int row, int col, int is_alpha) } } -static int vp56_size_changed(AVCodecContext *avctx) +static int vp56_size_changed(VP56Context *s) { - VP56Context *s = avctx->priv_data; + AVCodecContext *avctx = s->avctx; int stride = s->framep[VP56_FRAME_CURRENT]->linesize[0]; int i; @@ -483,9 +483,14 @@ static int vp56_size_changed(AVCodecContext *avctx) if (s->flip < 0) s->edge_emu_buffer += 15 * stride; + if (s->alpha_context) + return vp56_size_changed(s->alpha_context); + return 0; } +static int ff_vp56_decode_mbs(AVCodecContext *avctx, void *, int, int); + int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) { @@ -493,8 +498,8 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *data_size, VP56Context *s = avctx->priv_data; AVFrame *p = 0; int remaining_buf_size = avpkt->size; - int is_alpha, av_uninit(alpha_offset); - int i; + int av_uninit(alpha_offset); + int i, res; /* select a current frame from the unused frames */ for (i = 0; i < 4; ++i) { @@ -505,6 +510,8 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *data_size, } av_assert0(p != 0); s->framep[VP56_FRAME_CURRENT] = p; + if (s->alpha_context) + s->alpha_context->framep[VP56_FRAME_CURRENT] = p; if (s->has_alpha) { if (remaining_buf_size < 3) @@ -515,30 +522,17 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *data_size, return -1; } - for (is_alpha=0; is_alpha < 1+s->has_alpha; is_alpha++) { - int mb_row, mb_col, mb_row_flip, mb_offset = 0; - int block, y, uv, stride_y, stride_uv; - int res; - - s->modelp = &s->models[is_alpha]; - res = s->parse_header(s, buf, remaining_buf_size); if (!res) return -1; if (res == 2) { - int i; for (i = 0; i < 4; i++) { if (s->frames[i].data[0]) avctx->release_buffer(avctx, &s->frames[i]); } - if (is_alpha) { - avcodec_set_dimensions(avctx, 0, 0); - return -1; - } } - if (!is_alpha) { p->reference = 3; if (avctx->get_buffer(avctx, p) < 0) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); @@ -546,11 +540,53 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *data_size, } if (res == 2) - if (vp56_size_changed(avctx)) { + if (vp56_size_changed(s)) { avctx->release_buffer(avctx, p); return -1; } + + if (s->has_alpha) { + buf += alpha_offset; + remaining_buf_size -= alpha_offset; + + res = s->alpha_context->parse_header(s->alpha_context, buf, remaining_buf_size); + if (res != 1) { + avctx->release_buffer(avctx, p); + return -1; } + } + + avctx->execute2(avctx, ff_vp56_decode_mbs, 0, 0, s->has_alpha + 1); + + /* release frames that aren't in use */ + for (i = 0; i < 4; ++i) { + AVFrame *victim = &s->frames[i]; + if (!victim->data[0]) + continue; + if (victim != s->framep[VP56_FRAME_PREVIOUS] && + victim != s->framep[VP56_FRAME_GOLDEN] && + (!s->has_alpha || victim != s->alpha_context->framep[VP56_FRAME_GOLDEN])) + avctx->release_buffer(avctx, victim); + } + + p->qstride = 0; + p->qscale_table = s->qscale_table; + p->qscale_type = FF_QSCALE_TYPE_VP56; + *(AVFrame*)data = *p; + *data_size = sizeof(AVFrame); + + return avpkt->size; +} + +static int ff_vp56_decode_mbs(AVCodecContext *avctx, void *data, + int jobnr, int threadnr) +{ + VP56Context *s0 = avctx->priv_data; + int is_alpha = (jobnr == 1); + VP56Context *s = is_alpha ? s0->alpha_context : s0; + AVFrame *const p = s->framep[VP56_FRAME_CURRENT]; + int mb_row, mb_col, mb_row_flip, mb_offset = 0; + int block, y, uv, stride_y, stride_uv; if (p->key_frame) { p->pict_type = AV_PICTURE_TYPE_I; @@ -634,35 +670,9 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *data_size, s->framep[VP56_FRAME_GOLDEN] = p; } - if (s->has_alpha) { - FFSWAP(AVFrame *, s->framep[VP56_FRAME_GOLDEN], - s->framep[VP56_FRAME_GOLDEN2]); - buf += alpha_offset; - remaining_buf_size -= alpha_offset; - } - } - FFSWAP(AVFrame *, s->framep[VP56_FRAME_CURRENT], s->framep[VP56_FRAME_PREVIOUS]); - - /* release frames that aren't in use */ - for (i = 0; i < 4; ++i) { - AVFrame *victim = &s->frames[i]; - if (!victim->data[0]) - continue; - if (victim != s->framep[VP56_FRAME_PREVIOUS] && - victim != s->framep[VP56_FRAME_GOLDEN] && - (!s->has_alpha || victim != s->framep[VP56_FRAME_GOLDEN2])) - avctx->release_buffer(avctx, victim); - } - - p->qstride = 0; - p->qscale_table = s->qscale_table; - p->qscale_type = FF_QSCALE_TYPE_VP56; - *(AVFrame*)data = *p; - *data_size = sizeof(AVFrame); - - return avpkt->size; + return 0; } av_cold void ff_vp56_init(AVCodecContext *avctx, int flip, int has_alpha) @@ -702,6 +712,9 @@ av_cold void ff_vp56_init_context(AVCodecContext *avctx, VP56Context *s, s->filter = NULL; s->has_alpha = has_alpha; + + s->modelp = &s->model; + if (flip) { s->flip = -1; s->frbi = 2; diff --git a/libavcodec/vp56.h b/libavcodec/vp56.h index 7a32342aee..44bd229a6d 100644 --- a/libavcodec/vp56.h +++ b/libavcodec/vp56.h @@ -161,8 +161,11 @@ struct vp56_context { VP56ParseCoeffModels parse_coeff_models; VP56ParseHeader parse_header; + /* for "slice" parallelism between YUV and A */ + VP56Context *alpha_context; + VP56Model *modelp; - VP56Model models[2]; + VP56Model model; /* huffman decoding */ int use_huffman; diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c index c8a191799e..bafa2b4d0a 100644 --- a/libavcodec/vp6.c +++ b/libavcodec/vp6.c @@ -599,6 +599,18 @@ static av_cold int vp6_decode_init(AVCodecContext *avctx) ff_vp56_init(avctx, avctx->codec->id == AV_CODEC_ID_VP6, avctx->codec->id == AV_CODEC_ID_VP6A); vp6_decode_init_context(s); + + if (s->has_alpha) { + int i; + + s->alpha_context = av_mallocz(sizeof(VP56Context)); + ff_vp56_init_context(avctx, s->alpha_context, + s->flip == -1, s->has_alpha); + vp6_decode_init_context(s->alpha_context); + for (i = 0; i < 6; ++i) + s->alpha_context->framep[i] = s->framep[i]; + } + return 0; } @@ -622,6 +634,13 @@ static av_cold int vp6_decode_free(AVCodecContext *avctx) ff_vp56_free(avctx); vp6_decode_free_context(s); + + if (s->alpha_context) { + ff_vp56_free_context(s->alpha_context); + vp6_decode_free_context(s->alpha_context); + av_free(s->alpha_context); + } + return 0; } @@ -672,6 +691,6 @@ AVCodec ff_vp6a_decoder = { .init = vp6_decode_init, .close = vp6_decode_free, .decode = ff_vp56_decode_frame, - .capabilities = CODEC_CAP_DR1, + .capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS, .long_name = NULL_IF_CONFIG_SMALL("On2 VP6 (Flash version, with alpha channel)"), }; |