vpx/vp8/common/entropymv.c
Deb Mukherjee 5259744145 Adds support for switchable interpolation filters.
Allows for swtiching/setting interpolation filters at the MB
level. A frame level flag indicates whether to use a specifc
filter for the entire frame or to signal the interpolation
filter for each MB. When switchable filters are used, the
encoder chooses between 8-tap and 8-tap sharp filters. The
code currently has options to explore other variations as well,
which will be cleaned up subsequently.

One issue with the framework is that encoding is slow. I
tried to do some tricks to speed things up but it is still slow.
Decoding speed should not be affected since the number of
filter taps remain unchanged.

With the current version, we are up 0.5% on derf on average but
some videos city/mobile improve by close to 4 and 2% respectively.
If we did a full-search by turning the SEARCH_BEST_FILTER flag
on, the results are somewhat better.

The framework can be combined with filtered prediction, and I
seek feedback regarding that.

Rebased.

Change-Id: I8f632cb2c111e76284140a2bd480945d6d42b77a
2012-07-30 11:33:43 -07:00

413 lines
13 KiB
C

/*
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "onyxc_int.h"
#include "entropymv.h"
#if CONFIG_HIGH_PRECISION_MV
const MV_CONTEXT_HP vp8_mv_update_probs_hp[2] = {
{{
237,
246,
253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 250, 250, 252, 254, 254, 254
}
},
{{
231,
243,
245, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 251, 251, 254, 254, 254, 254
}
}
};
const MV_CONTEXT_HP vp8_default_mv_context_hp[2] = {
{{
/* row */
162, /* is short */
128, /* sign */
220, 204, 180, 192, 192, 119, 192, 192, 180, 140, 192, 192, 224, 224, 224, /* short tree */
128, 129, 132, 75, 145, 178, 206, 239, 254, 254, 254 /* long bits */
}
},
{{
/* same for column */
164, /* is short */
128,
220, 204, 180, 192, 192, 119, 192, 192, 180, 140, 192, 192, 224, 224, 224, /* short tree */
128, 130, 130, 74, 148, 180, 203, 236, 254, 254, 254 /* long bits */
}
}
};
#endif /* CONFIG_HIGH_PRECISION_MV */
const MV_CONTEXT vp8_mv_update_probs[2] = {
{{
237,
246,
253, 253, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 250, 250, 252, 254, 254
}
},
{{
231,
243,
245, 253, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 251, 251, 254, 254, 254
}
}
};
const MV_CONTEXT vp8_default_mv_context[2] = {
{{
/* row */
162, /* is short */
128, /* sign */
225, 146, 172, 147, 214, 39, 156, /* short tree */
128, 129, 132, 75, 145, 178, 206, 239, 254, 254 /* long bits */
}
},
{{
/* same for column */
164, /* is short */
128,
204, 170, 119, 235, 140, 230, 228,
128, 130, 130, 74, 148, 180, 203, 236, 254, 254 /* long bits */
}
}
};
#if CONFIG_HIGH_PRECISION_MV
const vp8_tree_index vp8_small_mvtree_hp [30] = {
2, 16,
4, 10,
6, 8,
-0, -1,
-2, -3,
12, 14,
-4, -5,
-6, -7,
18, 24,
20, 22,
-8, -9,
-10, -11,
26, 28,
-12, -13,
-14, -15
};
struct vp8_token_struct vp8_small_mvencodings_hp [16];
#endif /* CONFIG_HIGH_PRECISION_MV */
const vp8_tree_index vp8_small_mvtree [14] = {
2, 8,
4, 6,
-0, -1,
-2, -3,
10, 12,
-4, -5,
-6, -7
};
struct vp8_token_struct vp8_small_mvencodings [8];
__inline static void calc_prob(vp8_prob *p, const unsigned int ct[2], int pbits) {
const unsigned int tot = ct[0] + ct[1];
if (tot) {
const vp8_prob x = ((ct[0] * 255) / tot) & -(1 << (8 - pbits));
*p = x ? x : 1;
}
}
static void compute_component_probs(
const unsigned int events [MVvals],
vp8_prob Pnew [MVPcount],
unsigned int is_short_ct[2],
unsigned int sign_ct[2],
unsigned int bit_ct [mvlong_width] [2],
unsigned int short_ct [mvnum_short],
unsigned int short_bct [mvnum_short - 1] [2]
) {
is_short_ct[0] = is_short_ct[1] = 0;
sign_ct[0] = sign_ct[1] = 0;
vpx_memset(bit_ct, 0, sizeof(unsigned int)*mvlong_width * 2);
vpx_memset(short_ct, 0, sizeof(unsigned int)*mvnum_short);
vpx_memset(short_bct, 0, sizeof(unsigned int) * (mvnum_short - 1) * 2);
{
const int c = events [mv_max];
is_short_ct [0] += c; // Short vector
short_ct [0] += c; // Magnitude distribution
}
{
int j = 1;
do {
const int c1 = events [mv_max + j]; // positive
const int c2 = events [mv_max - j]; // negative
const int c = c1 + c2;
int a = j;
sign_ct [0] += c1;
sign_ct [1] += c2;
if (a < mvnum_short) {
is_short_ct [0] += c; // Short vector
short_ct [a] += c; // Magnitude distribution
} else {
int k = mvlong_width - 1;
is_short_ct [1] += c; // Long vector
do
bit_ct [k] [(a >> k) & 1] += c;
while (--k >= 0);
}
} while (++j <= mv_max);
}
calc_prob(Pnew + mvpis_short, is_short_ct, 8);
calc_prob(Pnew + MVPsign, sign_ct, 8);
{
vp8_prob p [mvnum_short - 1]; /* actually only need branch ct */
int j = 0;
vp8_tree_probs_from_distribution(
mvnum_short, vp8_small_mvencodings, vp8_small_mvtree,
p, short_bct, short_ct,
256, 1
);
do
calc_prob(Pnew + MVPshort + j, short_bct[j], 8);
while (++j < mvnum_short - 1);
}
{
int j = 0;
do
calc_prob(Pnew + MVPbits + j, bit_ct[j], 8);
while (++j < mvlong_width);
}
}
#if CONFIG_HIGH_PRECISION_MV
static void compute_component_probs_hp(
const unsigned int events [MVvals_hp],
vp8_prob Pnew [MVPcount_hp],
unsigned int is_short_ct[2],
unsigned int sign_ct[2],
unsigned int bit_ct [mvlong_width_hp] [2],
unsigned int short_ct [mvnum_short_hp],
unsigned int short_bct [mvnum_short_hp - 1] [2]
) {
is_short_ct[0] = is_short_ct[1] = 0;
sign_ct[0] = sign_ct[1] = 0;
vpx_memset(bit_ct, 0, sizeof(unsigned int)*mvlong_width_hp * 2);
vpx_memset(short_ct, 0, sizeof(unsigned int)*mvnum_short_hp);
vpx_memset(short_bct, 0, sizeof(unsigned int) * (mvnum_short_hp - 1) * 2);
{
const int c = events [mv_max_hp];
is_short_ct [0] += c; // Short vector
short_ct [0] += c; // Magnitude distribution
}
{
int j = 1;
do {
const int c1 = events [mv_max_hp + j]; // positive
const int c2 = events [mv_max_hp - j]; // negative
const int c = c1 + c2;
int a = j;
sign_ct [0] += c1;
sign_ct [1] += c2;
if (a < mvnum_short_hp) {
is_short_ct [0] += c; // Short vector
short_ct [a] += c; // Magnitude distribution
} else {
int k = mvlong_width_hp - 1;
is_short_ct [1] += c; // Long vector
do
bit_ct [k] [(a >> k) & 1] += c;
while (--k >= 0);
}
} while (++j <= mv_max_hp);
}
calc_prob(Pnew + mvpis_short_hp, is_short_ct, 8);
calc_prob(Pnew + MVPsign_hp, sign_ct, 8);
{
vp8_prob p [mvnum_short_hp - 1]; /* actually only need branch ct */
int j = 0;
vp8_tree_probs_from_distribution(
mvnum_short_hp, vp8_small_mvencodings_hp, vp8_small_mvtree_hp,
p, short_bct, short_ct,
256, 1
);
do
calc_prob(Pnew + MVPshort_hp + j, short_bct[j], 8);
while (++j < mvnum_short_hp - 1);
}
{
int j = 0;
do
calc_prob(Pnew + MVPbits_hp + j, bit_ct[j], 8);
while (++j < mvlong_width_hp);
}
}
#endif /* CONFIG_HIGH_PRECISION_MV */
void vp8_entropy_mv_init() {
vp8_tokens_from_tree(vp8_small_mvencodings, vp8_small_mvtree);
#if CONFIG_HIGH_PRECISION_MV
vp8_tokens_from_tree(vp8_small_mvencodings_hp, vp8_small_mvtree_hp);
#endif
}
// #define MV_COUNT_TESTING
#define MV_COUNT_SAT 16
#define MV_MAX_UPDATE_FACTOR 128
void vp8_adapt_mv_probs(VP8_COMMON *cm) {
int i, t, count, factor;
#ifdef MV_COUNT_TESTING
printf("static const unsigned int\nMVcount[2][MVvals]={\n");
for (i = 0; i < 2; ++i) {
printf(" { ");
for (t = 0; t < MVvals; t++) {
printf("%d, ", cm->fc.MVcount[i][t]);
if (t % 16 == 15 && t != MVvals - 1) printf("\n ");
}
printf("},\n");
}
printf("};\n");
#if CONFIG_HIGH_PRECISION_MV
printf("static const unsigned int\nMVcount_hp[2][MVvals_hp]={\n");
for (i = 0; i < 2; ++i) {
printf(" { ");
for (t = 0; t < MVvals_hp; t++) {
printf("%d, ", cm->fc.MVcount_hp[i][t]);
if (t % 16 == 15 && t != MVvals_hp - 1) printf("\n ");
}
printf("},\n");
}
printf("};\n");
#endif
#endif /* MV_COUNT_TESTING */
for (i = 0; i < 2; ++i) {
int prob;
unsigned int is_short_ct[2];
unsigned int sign_ct[2];
unsigned int bit_ct [mvlong_width] [2];
unsigned int short_ct [mvnum_short];
unsigned int short_bct [mvnum_short - 1] [2];
vp8_prob Pnew [MVPcount];
compute_component_probs(cm->fc.MVcount[i], Pnew,
is_short_ct, sign_ct,
bit_ct, short_ct, short_bct);
count = is_short_ct[0] + is_short_ct[1];
count = count > MV_COUNT_SAT ? MV_COUNT_SAT : count;
factor = (MV_MAX_UPDATE_FACTOR * count / MV_COUNT_SAT);
prob = ((int)cm->fc.pre_mvc[i].prob[mvpis_short] * (256 - factor) +
(int)Pnew[mvpis_short] * factor + 128) >> 8;
if (prob <= 0) cm->fc.mvc[i].prob[mvpis_short] = 1;
else if (prob > 255) cm->fc.mvc[i].prob[mvpis_short] = 255;
else cm->fc.mvc[i].prob[mvpis_short] = prob;
count = sign_ct[0] + sign_ct[1];
count = count > MV_COUNT_SAT ? MV_COUNT_SAT : count;
factor = (MV_MAX_UPDATE_FACTOR * count / MV_COUNT_SAT);
prob = ((int)cm->fc.pre_mvc[i].prob[MVPsign] * (256 - factor) +
(int)Pnew[MVPsign] * factor + 128) >> 8;
if (prob <= 0) cm->fc.mvc[i].prob[MVPsign] = 1;
else if (prob > 255) cm->fc.mvc[i].prob[MVPsign] = 255;
else cm->fc.mvc[i].prob[MVPsign] = prob;
for (t = 0; t < mvnum_short - 1; ++t) {
count = short_bct[t][0] + short_bct[t][1];
count = count > MV_COUNT_SAT ? MV_COUNT_SAT : count;
factor = (MV_MAX_UPDATE_FACTOR * count / MV_COUNT_SAT);
prob = ((int)cm->fc.pre_mvc[i].prob[MVPshort + t] * (256 - factor) +
(int)Pnew[MVPshort + t] * factor + 128) >> 8;
if (prob <= 0) cm->fc.mvc[i].prob[MVPshort + t] = 1;
else if (prob > 255) cm->fc.mvc[i].prob[MVPshort + t] = 255;
else cm->fc.mvc[i].prob[MVPshort + t] = prob;
}
for (t = 0; t < mvlong_width; ++t) {
count = bit_ct[t][0] + bit_ct[t][1];
count = count > MV_COUNT_SAT ? MV_COUNT_SAT : count;
factor = (MV_MAX_UPDATE_FACTOR * count / MV_COUNT_SAT);
prob = ((int)cm->fc.pre_mvc[i].prob[MVPbits + t] * (256 - factor) +
(int)Pnew[MVPbits + t] * factor + 128) >> 8;
if (prob <= 0) cm->fc.mvc[i].prob[MVPbits + t] = 1;
else if (prob > 255) cm->fc.mvc[i].prob[MVPbits + t] = 255;
else cm->fc.mvc[i].prob[MVPbits + t] = prob;
}
}
#if CONFIG_HIGH_PRECISION_MV
for (i = 0; i < 2; ++i) {
int prob;
unsigned int is_short_ct[2];
unsigned int sign_ct[2];
unsigned int bit_ct [mvlong_width_hp] [2];
unsigned int short_ct [mvnum_short_hp];
unsigned int short_bct [mvnum_short_hp - 1] [2];
vp8_prob Pnew [MVPcount_hp];
compute_component_probs_hp(cm->fc.MVcount_hp[i], Pnew,
is_short_ct, sign_ct,
bit_ct, short_ct, short_bct);
count = is_short_ct[0] + is_short_ct[1];
count = count > MV_COUNT_SAT ? MV_COUNT_SAT : count;
factor = (MV_MAX_UPDATE_FACTOR * count / MV_COUNT_SAT);
prob = ((int)cm->fc.pre_mvc_hp[i].prob[mvpis_short_hp] * (256 - factor) +
(int)Pnew[mvpis_short_hp] * factor + 128) >> 8;
if (prob <= 0) cm->fc.mvc_hp[i].prob[mvpis_short_hp] = 1;
else if (prob > 255) cm->fc.mvc_hp[i].prob[mvpis_short_hp] = 255;
else cm->fc.mvc_hp[i].prob[mvpis_short_hp] = prob;
count = sign_ct[0] + sign_ct[1];
count = count > MV_COUNT_SAT ? MV_COUNT_SAT : count;
factor = (MV_MAX_UPDATE_FACTOR * count / MV_COUNT_SAT);
prob = ((int)cm->fc.pre_mvc_hp[i].prob[MVPsign_hp] * (256 - factor) +
(int)Pnew[MVPsign_hp] * factor + 128) >> 8;
if (prob <= 0) cm->fc.mvc_hp[i].prob[MVPsign_hp] = 1;
else if (prob > 255) cm->fc.mvc_hp[i].prob[MVPsign_hp] = 255;
else cm->fc.mvc_hp[i].prob[MVPsign_hp] = prob;
for (t = 0; t < mvnum_short_hp - 1; ++t) {
count = short_bct[t][0] + short_bct[t][1];
count = count > MV_COUNT_SAT ? MV_COUNT_SAT : count;
factor = (MV_MAX_UPDATE_FACTOR * count / MV_COUNT_SAT);
prob = ((int)cm->fc.pre_mvc_hp[i].prob[MVPshort_hp + t] * (256 - factor) +
(int)Pnew[MVPshort_hp + t] * factor + 128) >> 8;
if (prob <= 0) cm->fc.mvc_hp[i].prob[MVPshort_hp + t] = 1;
else if (prob > 255) cm->fc.mvc_hp[i].prob[MVPshort_hp + t] = 255;
else cm->fc.mvc_hp[i].prob[MVPshort_hp + t] = prob;
}
for (t = 0; t < mvlong_width_hp; ++t) {
count = bit_ct[t][0] + bit_ct[t][1];
count = count > MV_COUNT_SAT ? MV_COUNT_SAT : count;
factor = (MV_MAX_UPDATE_FACTOR * count / MV_COUNT_SAT);
prob = ((int)cm->fc.pre_mvc_hp[i].prob[MVPbits_hp + t] * (256 - factor) +
(int)Pnew[MVPbits_hp + t] * factor + 128) >> 8;
if (prob <= 0) cm->fc.mvc_hp[i].prob[MVPbits_hp + t] = 1;
else if (prob > 255) cm->fc.mvc_hp[i].prob[MVPbits_hp + t] = 255;
else cm->fc.mvc_hp[i].prob[MVPbits_hp + t] = prob;
}
}
#endif
}