From 4edd74bd7c0aaef92d3ef81e627ec7660715e9e1 Mon Sep 17 00:00:00 2001 From: Stanislav Dolganov Date: Thu, 18 Aug 2016 14:40:09 +0300 Subject: [PATCH] avcodec/me_cmp: add median SAD compare function Signed-off-by: Michael Niedermayer --- libavcodec/avcodec.h | 33 +++++++++-------- libavcodec/me_cmp.c | 76 ++++++++++++++++++++++++++++++++++++++ libavcodec/me_cmp.h | 1 + libavcodec/motion_est.c | 1 + libavcodec/mpegvideo.h | 3 +- libavcodec/options_table.h | 1 + 6 files changed, 98 insertions(+), 17 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 6ac66461ac..e2dad5de6b 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -2093,22 +2093,23 @@ typedef struct AVCodecContext { * - decoding: unused */ int ildct_cmp; -#define FF_CMP_SAD 0 -#define FF_CMP_SSE 1 -#define FF_CMP_SATD 2 -#define FF_CMP_DCT 3 -#define FF_CMP_PSNR 4 -#define FF_CMP_BIT 5 -#define FF_CMP_RD 6 -#define FF_CMP_ZERO 7 -#define FF_CMP_VSAD 8 -#define FF_CMP_VSSE 9 -#define FF_CMP_NSSE 10 -#define FF_CMP_W53 11 -#define FF_CMP_W97 12 -#define FF_CMP_DCTMAX 13 -#define FF_CMP_DCT264 14 -#define FF_CMP_CHROMA 256 +#define FF_CMP_SAD 0 +#define FF_CMP_SSE 1 +#define FF_CMP_SATD 2 +#define FF_CMP_DCT 3 +#define FF_CMP_PSNR 4 +#define FF_CMP_BIT 5 +#define FF_CMP_RD 6 +#define FF_CMP_ZERO 7 +#define FF_CMP_VSAD 8 +#define FF_CMP_VSSE 9 +#define FF_CMP_NSSE 10 +#define FF_CMP_W53 11 +#define FF_CMP_W97 12 +#define FF_CMP_DCTMAX 13 +#define FF_CMP_DCT264 14 +#define FF_CMP_MEDIAN_SAD 15 +#define FF_CMP_CHROMA 256 /** * ME diamond size & shape diff --git a/libavcodec/me_cmp.c b/libavcodec/me_cmp.c index dc76b07ba2..6639b919ff 100644 --- a/libavcodec/me_cmp.c +++ b/libavcodec/me_cmp.c @@ -139,6 +139,45 @@ static inline int pix_abs16_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, return s; } +static inline int pix_median_abs16_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i, j; + +#define V(x) (pix1[x] - pix2[x]) + + s += abs(V(0)); + s += abs(V(1) - V(0)); + s += abs(V(2) - V(1)); + s += abs(V(3) - V(2)); + s += abs(V(4) - V(3)); + s += abs(V(5) - V(4)); + s += abs(V(6) - V(5)); + s += abs(V(7) - V(6)); + s += abs(V(8) - V(7)); + s += abs(V(9) - V(8)); + s += abs(V(10) - V(9)); + s += abs(V(11) - V(10)); + s += abs(V(12) - V(11)); + s += abs(V(13) - V(12)); + s += abs(V(14) - V(13)); + s += abs(V(15) - V(14)); + + pix1 += stride; + pix2 += stride; + + for (i = 1; i < h; i++) { + s += abs(V(0) - V(-stride)); + for (j = 1; j < 16; j++) + s += abs(V(j) - mid_pred(V(j-stride), V(j-1), V(j-stride) + V(j-1) - V(j-stride-1))); + pix1 += stride; + pix2 += stride; + + } +#undef V + return s; +} + static int pix_abs16_x2_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t stride, int h) { @@ -247,6 +286,37 @@ static inline int pix_abs8_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, return s; } +static inline int pix_median_abs8_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i, j; + +#define V(x) (pix1[x] - pix2[x]) + + s += abs(V(0)); + s += abs(V(1) - V(0)); + s += abs(V(2) - V(1)); + s += abs(V(3) - V(2)); + s += abs(V(4) - V(3)); + s += abs(V(5) - V(4)); + s += abs(V(6) - V(5)); + s += abs(V(7) - V(6)); + + pix1 += stride; + pix2 += stride; + + for (i = 1; i < h; i++) { + s += abs(V(0) - V(-stride)); + for (j = 1; j < 8; j++) + s += abs(V(j) - mid_pred(V(j-stride), V(j-1), V(j-stride) + V(j-1) - V(j-stride-1))); + pix1 += stride; + pix2 += stride; + + } +#undef V + return s; +} + static int pix_abs8_x2_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t stride, int h) { @@ -378,6 +448,9 @@ void ff_set_cmp(MECmpContext *c, me_cmp_func *cmp, int type) case FF_CMP_SAD: cmp[i] = c->sad[i]; break; + case FF_CMP_MEDIAN_SAD: + cmp[i] = c->median_sad[i]; + break; case FF_CMP_SATD: cmp[i] = c->hadamard8_diff[i]; break; @@ -993,4 +1066,7 @@ av_cold void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx) ff_me_cmp_init_x86(c, avctx); if (ARCH_MIPS) ff_me_cmp_init_mips(c, avctx); + + c->median_sad[0] = pix_median_abs16_c; + c->median_sad[1] = pix_median_abs8_c; } diff --git a/libavcodec/me_cmp.h b/libavcodec/me_cmp.h index a3603ec2c1..5666f59ade 100644 --- a/libavcodec/me_cmp.h +++ b/libavcodec/me_cmp.h @@ -76,6 +76,7 @@ typedef struct MECmpContext { me_cmp_func frame_skip_cmp[6]; // only width 8 used me_cmp_func pix_abs[2][4]; + me_cmp_func median_sad[2]; } MECmpContext; void ff_me_cmp_init_static(void); diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index 257d00b59e..25b606f819 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -897,6 +897,7 @@ static inline int get_penalty_factor(int lambda, int lambda2, int type){ case FF_CMP_NSSE: return lambda2>>FF_LAMBDA_SHIFT; case FF_CMP_BIT: + case FF_CMP_MEDIAN_SAD: return 1; } } diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index a1f3d4bd9a..c82fa3e1a1 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -594,7 +594,8 @@ enum rc_strategy { { "nsse", "Noise preserving sum of squared differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_NSSE }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ { "dct264", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCT264 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ { "dctmax", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ -{ "chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" } +{ "chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "msad", "Sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" } #ifndef FF_MPV_OFFSET #define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x) diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h index adfbe72bff..fe354549a8 100644 --- a/libavcodec/options_table.h +++ b/libavcodec/options_table.h @@ -312,6 +312,7 @@ static const AVOption avcodec_options[] = { #endif {"dctmax", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, V|E, "cmp_func"}, {"chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"msad", "sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, {"pre_dia_size", "diamond type & size for motion estimation pre-pass", OFFSET(pre_dia_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"subq", "sub-pel motion estimation quality", OFFSET(me_subpel_quality), AV_OPT_TYPE_INT, {.i64 = 8 }, INT_MIN, INT_MAX, V|E}, #if FF_API_AFD