[FFmpeg-cvslog] avcodec/utvideodec: add SIMD support for median prediction for planar formats
Paul B Mahol
git at videolan.org
Fri Dec 23 18:44:22 EET 2016
ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Fri Dec 23 15:41:51 2016 +0100| [ea93052db3594f93f2d10be085a770184da0513d] | committer: Paul B Mahol
avcodec/utvideodec: add SIMD support for median prediction for planar formats
~10% faster overall.
Signed-off-by: Paul B Mahol <onemda at gmail.com>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=ea93052db3594f93f2d10be085a770184da0513d
---
configure | 2 +-
libavcodec/utvideo.h | 2 +
libavcodec/utvideodec.c | 164 +++++++++++++++++++++++++++++++++++++++---------
libavcodec/utvideoenc.c | 3 +
4 files changed, 140 insertions(+), 31 deletions(-)
diff --git a/configure b/configure
index e2e171e..d723b8e 100755
--- a/configure
+++ b/configure
@@ -2531,7 +2531,7 @@ truespeech_decoder_select="bswapdsp"
tscc_decoder_select="zlib"
twinvq_decoder_select="mdct lsp sinewin"
txd_decoder_select="texturedsp"
-utvideo_decoder_select="bswapdsp"
+utvideo_decoder_select="bswapdsp huffyuvdsp"
utvideo_encoder_select="bswapdsp huffman huffyuvencdsp"
vble_decoder_select="huffyuvdsp"
vc1_decoder_select="blockdsp h263_decoder h264qpel intrax8 mpegvideo vc1dsp"
diff --git a/libavcodec/utvideo.h b/libavcodec/utvideo.h
index 49ddf49..0d10865 100644
--- a/libavcodec/utvideo.h
+++ b/libavcodec/utvideo.h
@@ -30,6 +30,7 @@
#include "libavutil/common.h"
#include "avcodec.h"
#include "bswapdsp.h"
+#include "huffyuvdsp.h"
#include "huffyuvencdsp.h"
enum {
@@ -69,6 +70,7 @@ typedef struct UtvideoContext {
const AVClass *class;
AVCodecContext *avctx;
BswapDSPContext bdsp;
+ HuffYUVDSPContext hdspdec;
HuffYUVEncDSPContext hdsp;
uint32_t frame_info_size, flags, frame_info;
diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c
index 650c0ec..cae0ff5 100644
--- a/libavcodec/utvideodec.c
+++ b/libavcodec/utvideodec.c
@@ -372,8 +372,111 @@ static void restore_rgb_planes10(AVFrame *frame, int width, int height)
}
}
-static void restore_median(uint8_t *src, int step, int stride,
- int width, int height, int slices, int rmode)
+#undef A
+#undef B
+#undef C
+
+static void restore_median_planar(UtvideoContext *c, uint8_t *src, int stride,
+ int width, int height, int slices, int rmode)
+{
+ int i, j, slice;
+ int A, B, C;
+ uint8_t *bsrc;
+ int slice_start, slice_height;
+ const int cmask = ~rmode;
+
+ for (slice = 0; slice < slices; slice++) {
+ slice_start = ((slice * height) / slices) & cmask;
+ slice_height = ((((slice + 1) * height) / slices) & cmask) -
+ slice_start;
+
+ if (!slice_height)
+ continue;
+ bsrc = src + slice_start * stride;
+
+ // first line - left neighbour prediction
+ bsrc[0] += 0x80;
+ c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0);
+ bsrc += stride;
+ if (slice_height <= 1)
+ continue;
+ // second line - first element has top prediction, the rest uses median
+ C = bsrc[-stride];
+ bsrc[0] += C;
+ A = bsrc[0];
+ for (i = 1; i < width; i++) {
+ B = bsrc[i - stride];
+ bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
+ C = B;
+ A = bsrc[i];
+ }
+ bsrc += stride;
+ // the rest of lines use continuous median prediction
+ for (j = 2; j < slice_height; j++) {
+ c->hdspdec.add_hfyu_median_pred(bsrc, bsrc - stride,
+ bsrc, width, &B, &C);
+ bsrc += stride;
+ }
+ }
+}
+
+/* UtVideo interlaced mode treats every two lines as a single one,
+ * so restoring function should take care of possible padding between
+ * two parts of the same "line".
+ */
+static void restore_median_planar_il(UtvideoContext *c, uint8_t *src, int stride,
+ int width, int height, int slices, int rmode)
+{
+ int i, j, slice;
+ int A, B, C;
+ uint8_t *bsrc;
+ int slice_start, slice_height;
+ const int cmask = ~(rmode ? 3 : 1);
+ const int stride2 = stride << 1;
+
+ for (slice = 0; slice < slices; slice++) {
+ slice_start = ((slice * height) / slices) & cmask;
+ slice_height = ((((slice + 1) * height) / slices) & cmask) -
+ slice_start;
+ slice_height >>= 1;
+ if (!slice_height)
+ continue;
+
+ bsrc = src + slice_start * stride;
+
+ // first line - left neighbour prediction
+ bsrc[0] += 0x80;
+ A = c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0);
+ c->hdspdec.add_hfyu_left_pred(bsrc + stride, bsrc + stride, width, A);
+ bsrc += stride2;
+ if (slice_height <= 1)
+ continue;
+ // second line - first element has top prediction, the rest uses median
+ C = bsrc[-stride2];
+ bsrc[0] += C;
+ A = bsrc[0];
+ for (i = 1; i < width; i++) {
+ B = bsrc[i - stride2];
+ bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C));
+ C = B;
+ A = bsrc[i];
+ }
+ c->hdspdec.add_hfyu_median_pred(bsrc + stride, bsrc - stride,
+ bsrc + stride, width, &B, &C);
+ bsrc += stride2;
+ // the rest of lines use continuous median prediction
+ for (j = 2; j < slice_height; j++) {
+ c->hdspdec.add_hfyu_median_pred(bsrc, bsrc - stride2,
+ bsrc, width, &B, &C);
+ c->hdspdec.add_hfyu_median_pred(bsrc + stride, bsrc - stride,
+ bsrc + stride, width, &B, &C);
+ bsrc += stride2;
+ }
+ }
+}
+
+static void restore_median_packed(uint8_t *src, int step, int stride,
+ int width, int height, int slices, int rmode)
{
int i, j, slice;
int A, B, C;
@@ -428,8 +531,8 @@ static void restore_median(uint8_t *src, int step, int stride,
* so restoring function should take care of possible padding between
* two parts of the same "line".
*/
-static void restore_median_il(uint8_t *src, int step, int stride,
- int width, int height, int slices, int rmode)
+static void restore_median_packed_il(uint8_t *src, int step, int stride,
+ int width, int height, int slices, int rmode)
{
int i, j, slice;
int A, B, C;
@@ -608,14 +711,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return ret;
if (c->frame_pred == PRED_MEDIAN) {
if (!c->interlaced) {
- restore_median(frame.f->data[0] + ff_ut_rgb_order[i],
- c->planes, frame.f->linesize[0], avctx->width,
- avctx->height, c->slices, 0);
+ restore_median_packed(frame.f->data[0] + ff_ut_rgb_order[i],
+ c->planes, frame.f->linesize[0], avctx->width,
+ avctx->height, c->slices, 0);
} else {
- restore_median_il(frame.f->data[0] + ff_ut_rgb_order[i],
- c->planes, frame.f->linesize[0],
- avctx->width, avctx->height, c->slices,
- 0);
+ restore_median_packed_il(frame.f->data[0] + ff_ut_rgb_order[i],
+ c->planes, frame.f->linesize[0],
+ avctx->width, avctx->height, c->slices,
+ 0);
}
}
}
@@ -644,14 +747,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return ret;
if (c->frame_pred == PRED_MEDIAN) {
if (!c->interlaced) {
- restore_median(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width >> !!i, avctx->height >> !!i,
- c->slices, !i);
+ restore_median_planar(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i, avctx->height >> !!i,
+ c->slices, !i);
} else {
- restore_median_il(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width >> !!i,
- avctx->height >> !!i,
- c->slices, !i);
+ restore_median_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i,
+ avctx->height >> !!i,
+ c->slices, !i);
}
}
}
@@ -665,13 +768,13 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return ret;
if (c->frame_pred == PRED_MEDIAN) {
if (!c->interlaced) {
- restore_median(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width >> !!i, avctx->height,
- c->slices, 0);
+ restore_median_planar(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i, avctx->height,
+ c->slices, 0);
} else {
- restore_median_il(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width >> !!i, avctx->height,
- c->slices, 0);
+ restore_median_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width >> !!i, avctx->height,
+ c->slices, 0);
}
}
}
@@ -685,13 +788,13 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return ret;
if (c->frame_pred == PRED_MEDIAN) {
if (!c->interlaced) {
- restore_median(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width, avctx->height,
- c->slices, 0);
+ restore_median_planar(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width, avctx->height,
+ c->slices, 0);
} else {
- restore_median_il(frame.f->data[i], 1, frame.f->linesize[i],
- avctx->width, avctx->height,
- c->slices, 0);
+ restore_median_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+ avctx->width, avctx->height,
+ c->slices, 0);
}
}
}
@@ -724,6 +827,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
c->avctx = avctx;
ff_bswapdsp_init(&c->bdsp);
+ ff_huffyuvdsp_init(&c->hdspdec);
if (avctx->extradata_size >= 16) {
av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n",
diff --git a/libavcodec/utvideoenc.c b/libavcodec/utvideoenc.c
index 6082943..fd27a15 100644
--- a/libavcodec/utvideoenc.c
+++ b/libavcodec/utvideoenc.c
@@ -293,6 +293,9 @@ static void left_predict(uint8_t *src, uint8_t *dst, int stride,
}
}
+#undef A
+#undef B
+
/* Write data to a plane with median prediction */
static void median_predict(UtvideoContext *c, uint8_t *src, uint8_t *dst, int stride,
int width, int height)
More information about the ffmpeg-cvslog
mailing list