2010-05-18 17:58:33 +02:00
|
|
|
/*
|
2010-09-09 14:16:39 +02:00
|
|
|
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
2010-05-18 17:58:33 +02:00
|
|
|
*
|
2010-06-18 18:39:21 +02:00
|
|
|
* Use of this source code is governed by a BSD-style license
|
2010-06-04 22:19:40 +02:00
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
2010-06-18 18:39:21 +02:00
|
|
|
* in the file PATENTS. All contributing project authors may
|
2010-06-04 22:19:40 +02:00
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
2010-05-18 17:58:33 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2012-12-23 16:20:10 +01:00
|
|
|
#include "./vpx_config.h"
|
2012-11-27 22:59:17 +01:00
|
|
|
#include "vp9/encoder/vp9_encodeframe.h"
|
2012-11-28 19:41:40 +01:00
|
|
|
#include "vp9/encoder/vp9_encodemb.h"
|
|
|
|
#include "vp9/encoder/vp9_encodemv.h"
|
2012-11-27 22:59:17 +01:00
|
|
|
#include "vp9/common/vp9_common.h"
|
2012-11-28 19:41:40 +01:00
|
|
|
#include "vp9/encoder/vp9_onyx_int.h"
|
2012-11-27 22:59:17 +01:00
|
|
|
#include "vp9/common/vp9_extend.h"
|
2012-11-29 00:15:51 +01:00
|
|
|
#include "vp9/common/vp9_entropy.h"
|
2012-11-27 22:59:17 +01:00
|
|
|
#include "vp9/common/vp9_entropymode.h"
|
|
|
|
#include "vp9/common/vp9_quant_common.h"
|
2012-11-28 19:41:40 +01:00
|
|
|
#include "vp9/encoder/vp9_segmentation.h"
|
2012-11-27 22:59:17 +01:00
|
|
|
#include "vp9/common/vp9_setupintrarecon.h"
|
2012-11-28 19:41:40 +01:00
|
|
|
#include "vp9/encoder/vp9_encodeintra.h"
|
2012-11-27 22:59:17 +01:00
|
|
|
#include "vp9/common/vp9_reconinter.h"
|
|
|
|
#include "vp9/common/vp9_invtrans.h"
|
2012-11-28 19:41:40 +01:00
|
|
|
#include "vp9/encoder/vp9_rdopt.h"
|
2012-11-27 22:59:17 +01:00
|
|
|
#include "vp9/common/vp9_findnearmv.h"
|
|
|
|
#include "vp9/common/vp9_reconintra.h"
|
|
|
|
#include "vp9/common/vp9_seg_common.h"
|
2013-02-07 00:30:21 +01:00
|
|
|
#include "vp9/common/vp9_tile_common.h"
|
2012-11-27 22:59:17 +01:00
|
|
|
#include "vp9/encoder/vp9_tokenize.h"
|
2013-02-13 23:22:15 +01:00
|
|
|
#include "./vp9_rtcd.h"
|
2010-05-18 17:58:33 +02:00
|
|
|
#include <stdio.h>
|
2011-02-14 23:18:18 +01:00
|
|
|
#include <math.h>
|
2010-05-18 17:58:33 +02:00
|
|
|
#include <limits.h>
|
|
|
|
#include "vpx_ports/vpx_timer.h"
|
2012-11-27 22:59:17 +01:00
|
|
|
#include "vp9/common/vp9_pred_common.h"
|
|
|
|
#include "vp9/common/vp9_mvref_common.h"
|
2012-08-24 16:44:01 +02:00
|
|
|
|
2012-11-07 19:41:04 +01:00
|
|
|
#define DBG_PRNT_SEGMAP 0
|
2010-09-24 00:25:33 +02:00
|
|
|
|
2012-11-16 00:14:38 +01:00
|
|
|
// #define ENC_DEBUG
|
2011-02-14 23:18:18 +01:00
|
|
|
#ifdef ENC_DEBUG
|
2012-07-14 00:21:29 +02:00
|
|
|
int enc_debug = 0;
|
2011-02-14 23:18:18 +01:00
|
|
|
#endif
|
|
|
|
|
2013-02-28 22:18:02 +01:00
|
|
|
void vp9_select_interp_filter_type(VP9_COMP *cpi);
|
2012-12-20 23:56:19 +01:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
static void encode_macroblock(VP9_COMP *cpi, TOKENEXTRA **t,
|
|
|
|
int output_enabled, int mb_row, int mb_col);
|
2012-10-30 22:25:33 +01:00
|
|
|
|
2013-04-10 06:28:27 +02:00
|
|
|
static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t,
|
|
|
|
int output_enabled, int mb_row, int mb_col,
|
|
|
|
BLOCK_SIZE_TYPE bsize);
|
2012-10-30 22:25:33 +01:00
|
|
|
|
2012-10-31 01:53:32 +01:00
|
|
|
static void adjust_act_zbin(VP9_COMP *cpi, MACROBLOCK *x);
|
2011-02-14 23:18:18 +01:00
|
|
|
|
2010-05-18 17:58:33 +02:00
|
|
|
#ifdef MODE_STATS
|
2012-05-15 01:21:01 +02:00
|
|
|
unsigned int inter_y_modes[MB_MODE_COUNT];
|
2012-10-31 22:40:53 +01:00
|
|
|
unsigned int inter_uv_modes[VP9_UV_MODES];
|
2012-05-15 01:21:01 +02:00
|
|
|
unsigned int inter_b_modes[B_MODE_COUNT];
|
2012-10-31 22:40:53 +01:00
|
|
|
unsigned int y_modes[VP9_YMODES];
|
|
|
|
unsigned int i8x8_modes[VP9_I8X8_MODES];
|
|
|
|
unsigned int uv_modes[VP9_UV_MODES];
|
|
|
|
unsigned int uv_modes_y[VP9_YMODES][VP9_UV_MODES];
|
2012-05-15 01:21:01 +02:00
|
|
|
unsigned int b_modes[B_MODE_COUNT];
|
2010-05-18 17:58:33 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2010-10-11 23:37:27 +02:00
|
|
|
/* activity_avg must be positive, or flat regions could get a zero weight
|
|
|
|
* (infinite lambda), which confounds analysis.
|
|
|
|
* This also avoids the need for divide by zero checks in
|
2012-10-30 20:58:42 +01:00
|
|
|
* vp9_activity_masking().
|
2010-10-11 23:37:27 +02:00
|
|
|
*/
|
2012-10-31 22:40:53 +01:00
|
|
|
#define VP9_ACTIVITY_AVG_MIN (64)
|
2010-10-11 23:37:27 +02:00
|
|
|
|
|
|
|
/* This is used as a reference when computing the source variance for the
|
|
|
|
* purposes of activity masking.
|
|
|
|
* Eventually this should be replaced by custom no-reference routines,
|
|
|
|
* which will be faster.
|
|
|
|
*/
|
2012-12-19 00:31:19 +01:00
|
|
|
static const uint8_t VP9_VAR_OFFS[16] = {
|
2012-07-14 00:21:29 +02:00
|
|
|
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
|
2010-10-11 23:37:27 +02:00
|
|
|
};
|
|
|
|
|
2011-05-12 18:01:55 +02:00
|
|
|
|
|
|
|
// Original activity measure from Tim T's code.
|
2012-10-31 01:53:32 +01:00
|
|
|
static unsigned int tt_activity_measure(VP9_COMP *cpi, MACROBLOCK *x) {
|
2012-07-14 00:21:29 +02:00
|
|
|
unsigned int act;
|
|
|
|
unsigned int sse;
|
|
|
|
/* TODO: This could also be done over smaller areas (8x8), but that would
|
|
|
|
* require extensive changes elsewhere, as lambda is assumed to be fixed
|
|
|
|
* over an entire MB in most of the code.
|
|
|
|
* Another option is to compute four 8x8 variances, and pick a single
|
|
|
|
* lambda using a non-linear combination (e.g., the smallest, or second
|
|
|
|
* smallest, etc.).
|
|
|
|
*/
|
2012-10-31 22:40:53 +01:00
|
|
|
act = vp9_variance16x16(x->src.y_buffer, x->src.y_stride, VP9_VAR_OFFS, 0,
|
2012-10-22 05:47:57 +02:00
|
|
|
&sse);
|
2013-02-28 22:18:02 +01:00
|
|
|
act <<= 4;
|
2012-07-14 00:21:29 +02:00
|
|
|
|
|
|
|
/* If the region is flat, lower the activity some more. */
|
|
|
|
if (act < 8 << 12)
|
|
|
|
act = act < 5 << 12 ? act : 5 << 12;
|
|
|
|
|
|
|
|
return act;
|
2010-10-11 23:37:27 +02:00
|
|
|
}
|
|
|
|
|
2011-05-12 18:01:55 +02:00
|
|
|
// Stub for alternative experimental activity measures.
|
2012-10-31 01:53:32 +01:00
|
|
|
static unsigned int alt_activity_measure(VP9_COMP *cpi,
|
2012-07-14 00:21:29 +02:00
|
|
|
MACROBLOCK *x, int use_dc_pred) {
|
2012-10-30 20:58:42 +01:00
|
|
|
return vp9_encode_intra(cpi, x, use_dc_pred);
|
2011-05-12 18:01:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Measure the activity of the current macroblock
|
|
|
|
// What we measure here is TBD so abstracted to this function
|
2011-06-08 17:00:59 +02:00
|
|
|
#define ALT_ACT_MEASURE 1
|
2012-10-31 01:53:32 +01:00
|
|
|
static unsigned int mb_activity_measure(VP9_COMP *cpi, MACROBLOCK *x,
|
2012-07-14 00:21:29 +02:00
|
|
|
int mb_row, int mb_col) {
|
|
|
|
unsigned int mb_activity;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
if (ALT_ACT_MEASURE) {
|
|
|
|
int use_dc_pred = (mb_col || mb_row) && (!mb_col || !mb_row);
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Or use and alternative.
|
|
|
|
mb_activity = alt_activity_measure(cpi, x, use_dc_pred);
|
|
|
|
} else {
|
|
|
|
// Original activity measure from Tim T's code.
|
|
|
|
mb_activity = tt_activity_measure(cpi, x);
|
|
|
|
}
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-10-31 22:40:53 +01:00
|
|
|
if (mb_activity < VP9_ACTIVITY_AVG_MIN)
|
|
|
|
mb_activity = VP9_ACTIVITY_AVG_MIN;
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
return mb_activity;
|
2011-05-12 18:01:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate an "average" mb activity value for the frame
|
2011-06-08 17:00:59 +02:00
|
|
|
#define ACT_MEDIAN 0
|
2012-10-31 01:53:32 +01:00
|
|
|
static void calc_av_activity(VP9_COMP *cpi, int64_t activity_sum) {
|
2011-06-08 17:00:59 +02:00
|
|
|
#if ACT_MEDIAN
|
2012-07-14 00:21:29 +02:00
|
|
|
// Find median: Simple n^2 algorithm for experimentation
|
|
|
|
{
|
|
|
|
unsigned int median;
|
|
|
|
unsigned int i, j;
|
|
|
|
unsigned int *sortlist;
|
|
|
|
unsigned int tmp;
|
|
|
|
|
|
|
|
// Create a list to sort to
|
|
|
|
CHECK_MEM_ERROR(sortlist,
|
|
|
|
vpx_calloc(sizeof(unsigned int),
|
|
|
|
cpi->common.MBs));
|
|
|
|
|
|
|
|
// Copy map to sort list
|
|
|
|
vpx_memcpy(sortlist, cpi->mb_activity_map,
|
|
|
|
sizeof(unsigned int) * cpi->common.MBs);
|
|
|
|
|
|
|
|
|
|
|
|
// Ripple each value down to its correct position
|
|
|
|
for (i = 1; i < cpi->common.MBs; i ++) {
|
|
|
|
for (j = i; j > 0; j --) {
|
|
|
|
if (sortlist[j] < sortlist[j - 1]) {
|
|
|
|
// Swap values
|
|
|
|
tmp = sortlist[j - 1];
|
|
|
|
sortlist[j - 1] = sortlist[j];
|
|
|
|
sortlist[j] = tmp;
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Even number MBs so estimate median as mean of two either side.
|
|
|
|
median = (1 + sortlist[cpi->common.MBs >> 1] +
|
|
|
|
sortlist[(cpi->common.MBs >> 1) + 1]) >> 1;
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
cpi->activity_avg = median;
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
vpx_free(sortlist);
|
|
|
|
}
|
2011-06-08 17:00:59 +02:00
|
|
|
#else
|
2012-07-14 00:21:29 +02:00
|
|
|
// Simple mean for now
|
|
|
|
cpi->activity_avg = (unsigned int)(activity_sum / cpi->common.MBs);
|
2011-06-08 17:00:59 +02:00
|
|
|
#endif
|
|
|
|
|
2012-10-31 22:40:53 +01:00
|
|
|
if (cpi->activity_avg < VP9_ACTIVITY_AVG_MIN)
|
|
|
|
cpi->activity_avg = VP9_ACTIVITY_AVG_MIN;
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Experimental code: return fixed value normalized for several clips
|
|
|
|
if (ALT_ACT_MEASURE)
|
|
|
|
cpi->activity_avg = 100000;
|
2011-05-12 18:01:55 +02:00
|
|
|
}
|
|
|
|
|
2011-06-08 17:00:59 +02:00
|
|
|
#define USE_ACT_INDEX 0
|
2011-05-12 18:01:55 +02:00
|
|
|
#define OUTPUT_NORM_ACT_STATS 0
|
2011-06-08 17:00:59 +02:00
|
|
|
|
|
|
|
#if USE_ACT_INDEX
|
2013-03-26 14:11:52 +01:00
|
|
|
// Calculate an activity index for each mb
|
2012-10-31 01:53:32 +01:00
|
|
|
static void calc_activity_index(VP9_COMP *cpi, MACROBLOCK *x) {
|
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
2012-07-14 00:21:29 +02:00
|
|
|
int mb_row, mb_col;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
int64_t act;
|
|
|
|
int64_t a;
|
|
|
|
int64_t b;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
|
|
|
#if OUTPUT_NORM_ACT_STATS
|
2012-07-14 00:21:29 +02:00
|
|
|
FILE *f = fopen("norm_act.stt", "a");
|
|
|
|
fprintf(f, "\n%12d\n", cpi->activity_avg);
|
2011-05-12 18:01:55 +02:00
|
|
|
#endif
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Reset pointers to start of activity map
|
|
|
|
x->mb_activity_ptr = cpi->mb_activity_map;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Calculate normalized mb activity number.
|
|
|
|
for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
|
|
|
|
// for each macroblock col in image
|
|
|
|
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
|
|
|
|
// Read activity from the map
|
|
|
|
act = *(x->mb_activity_ptr);
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Calculate a normalized activity number
|
|
|
|
a = act + 4 * cpi->activity_avg;
|
|
|
|
b = 4 * act + cpi->activity_avg;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
if (b >= a)
|
|
|
|
*(x->activity_ptr) = (int)((b + (a >> 1)) / a) - 1;
|
|
|
|
else
|
|
|
|
*(x->activity_ptr) = 1 - (int)((a + (b >> 1)) / b);
|
2011-05-12 18:01:55 +02:00
|
|
|
|
|
|
|
#if OUTPUT_NORM_ACT_STATS
|
2012-07-14 00:21:29 +02:00
|
|
|
fprintf(f, " %6d", *(x->mb_activity_ptr));
|
2011-05-12 18:01:55 +02:00
|
|
|
#endif
|
2012-07-14 00:21:29 +02:00
|
|
|
// Increment activity map pointers
|
|
|
|
x->mb_activity_ptr++;
|
|
|
|
}
|
2011-05-12 18:01:55 +02:00
|
|
|
|
|
|
|
#if OUTPUT_NORM_ACT_STATS
|
2012-07-14 00:21:29 +02:00
|
|
|
fprintf(f, "\n");
|
2011-05-12 18:01:55 +02:00
|
|
|
#endif
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2011-05-12 18:01:55 +02:00
|
|
|
|
|
|
|
#if OUTPUT_NORM_ACT_STATS
|
2012-07-14 00:21:29 +02:00
|
|
|
fclose(f);
|
2011-05-12 18:01:55 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
2011-06-08 17:00:59 +02:00
|
|
|
#endif
|
2011-05-12 18:01:55 +02:00
|
|
|
|
|
|
|
// Loop through all MBs. Note activity of each, average activity and
|
|
|
|
// calculate a normalized activity for each
|
2012-10-31 01:53:32 +01:00
|
|
|
static void build_activity_map(VP9_COMP *cpi) {
|
2012-10-17 23:51:27 +02:00
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
2012-07-14 00:21:29 +02:00
|
|
|
MACROBLOCKD *xd = &x->e_mbd;
|
2012-10-31 01:53:32 +01:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2011-06-08 17:00:59 +02:00
|
|
|
#if ALT_ACT_MEASURE
|
2012-07-14 00:21:29 +02:00
|
|
|
YV12_BUFFER_CONFIG *new_yv12 = &cm->yv12_fb[cm->new_fb_idx];
|
|
|
|
int recon_yoffset;
|
|
|
|
int recon_y_stride = new_yv12->y_stride;
|
2011-06-08 17:00:59 +02:00
|
|
|
#endif
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
int mb_row, mb_col;
|
|
|
|
unsigned int mb_activity;
|
|
|
|
int64_t activity_sum = 0;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2013-03-26 14:11:52 +01:00
|
|
|
x->mb_activity_ptr = cpi->mb_activity_map;
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// for each macroblock row in image
|
|
|
|
for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) {
|
2011-06-08 17:00:59 +02:00
|
|
|
#if ALT_ACT_MEASURE
|
2012-07-14 00:21:29 +02:00
|
|
|
// reset above block coeffs
|
|
|
|
xd->up_available = (mb_row != 0);
|
|
|
|
recon_yoffset = (mb_row * recon_y_stride * 16);
|
2011-06-08 17:00:59 +02:00
|
|
|
#endif
|
2012-07-14 00:21:29 +02:00
|
|
|
// for each macroblock col in image
|
|
|
|
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
|
2011-06-08 17:00:59 +02:00
|
|
|
#if ALT_ACT_MEASURE
|
2012-07-14 00:21:29 +02:00
|
|
|
xd->dst.y_buffer = new_yv12->y_buffer + recon_yoffset;
|
|
|
|
xd->left_available = (mb_col != 0);
|
|
|
|
recon_yoffset += 16;
|
2011-06-08 17:00:59 +02:00
|
|
|
#endif
|
2011-06-23 19:54:02 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// measure activity
|
|
|
|
mb_activity = mb_activity_measure(cpi, x, mb_row, mb_col);
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Keep frame sum
|
|
|
|
activity_sum += mb_activity;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Store MB level activity details.
|
|
|
|
*x->mb_activity_ptr = mb_activity;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Increment activity map pointer
|
|
|
|
x->mb_activity_ptr++;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// adjust to the next column of source macroblocks
|
|
|
|
x->src.y_buffer += 16;
|
|
|
|
}
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// adjust to the next row of mbs
|
|
|
|
x->src.y_buffer += 16 * x->src.y_stride - 16 * cm->mb_cols;
|
2011-06-08 17:00:59 +02:00
|
|
|
|
|
|
|
#if ALT_ACT_MEASURE
|
2012-07-14 00:21:29 +02:00
|
|
|
// extend the recon for intra prediction
|
2012-10-31 00:25:53 +01:00
|
|
|
vp9_extend_mb_row(new_yv12, xd->dst.y_buffer + 16,
|
2012-07-14 00:21:29 +02:00
|
|
|
xd->dst.u_buffer + 8, xd->dst.v_buffer + 8);
|
2011-06-08 17:00:59 +02:00
|
|
|
#endif
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Calculate an "average" MB activity
|
|
|
|
calc_av_activity(cpi, activity_sum);
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2011-06-08 17:00:59 +02:00
|
|
|
#if USE_ACT_INDEX
|
2012-07-14 00:21:29 +02:00
|
|
|
// Calculate an activity index number of each mb
|
|
|
|
calc_activity_index(cpi, x);
|
2011-06-08 17:00:59 +02:00
|
|
|
#endif
|
|
|
|
|
2011-05-12 18:01:55 +02:00
|
|
|
}
|
|
|
|
|
2011-06-08 17:00:59 +02:00
|
|
|
// Macroblock activity masking
|
2012-10-31 01:53:32 +01:00
|
|
|
void vp9_activity_masking(VP9_COMP *cpi, MACROBLOCK *x) {
|
2011-06-08 17:00:59 +02:00
|
|
|
#if USE_ACT_INDEX
|
2012-07-14 00:21:29 +02:00
|
|
|
x->rdmult += *(x->mb_activity_ptr) * (x->rdmult >> 2);
|
|
|
|
x->errorperbit = x->rdmult * 100 / (110 * x->rddiv);
|
|
|
|
x->errorperbit += (x->errorperbit == 0);
|
2011-06-08 17:00:59 +02:00
|
|
|
#else
|
2012-07-14 00:21:29 +02:00
|
|
|
int64_t a;
|
|
|
|
int64_t b;
|
|
|
|
int64_t act = *(x->mb_activity_ptr);
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Apply the masking to the RD multiplier.
|
|
|
|
a = act + (2 * cpi->activity_avg);
|
|
|
|
b = (2 * act) + cpi->activity_avg;
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
x->rdmult = (unsigned int)(((int64_t)x->rdmult * b + (a >> 1)) / a);
|
|
|
|
x->errorperbit = x->rdmult * 100 / (110 * x->rddiv);
|
|
|
|
x->errorperbit += (x->errorperbit == 0);
|
2011-06-08 17:00:59 +02:00
|
|
|
#endif
|
2011-05-12 18:01:55 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Activity based Zbin adjustment
|
|
|
|
adjust_act_zbin(cpi, x);
|
2011-05-12 18:01:55 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-01-07 20:41:49 +01:00
|
|
|
static void update_state(VP9_COMP *cpi,
|
2013-04-10 06:28:27 +02:00
|
|
|
PICK_MODE_CONTEXT *ctx,
|
|
|
|
BLOCK_SIZE_TYPE bsize,
|
2013-01-06 03:20:25 +01:00
|
|
|
int output_enabled) {
|
|
|
|
int i, x_idx, y;
|
2013-04-12 02:13:02 +02:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
2013-01-07 20:41:49 +01:00
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
2012-07-14 00:21:29 +02:00
|
|
|
MODE_INFO *mi = &ctx->mic;
|
2013-01-06 03:20:25 +01:00
|
|
|
MB_MODE_INFO *const mbmi = &xd->mode_info_context->mbmi;
|
2012-07-14 00:21:29 +02:00
|
|
|
int mb_mode = mi->mbmi.mode;
|
|
|
|
int mb_mode_index = ctx->best_mode_index;
|
2013-01-06 03:20:25 +01:00
|
|
|
const int mis = cpi->common.mode_info_stride;
|
2013-04-10 06:28:27 +02:00
|
|
|
const int bh = 1 << mb_height_log2(bsize), bw = 1 << mb_width_log2(bsize);
|
2012-04-07 01:38:34 +02:00
|
|
|
|
|
|
|
#if CONFIG_DEBUG
|
2012-07-14 00:21:29 +02:00
|
|
|
assert(mb_mode < MB_MODE_COUNT);
|
|
|
|
assert(mb_mode_index < MAX_MODES);
|
|
|
|
assert(mi->mbmi.ref_frame < MAX_REF_FRAMES);
|
2012-04-07 01:38:34 +02:00
|
|
|
#endif
|
2013-04-10 06:28:27 +02:00
|
|
|
assert(mi->mbmi.sb_type == bsize);
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Restore the coding context of the MB to that that was in place
|
|
|
|
// when the mode was picked for it
|
2013-04-10 06:28:27 +02:00
|
|
|
for (y = 0; y < bh; y++) {
|
|
|
|
for (x_idx = 0; x_idx < bw; x_idx++) {
|
|
|
|
if ((xd->mb_to_right_edge >> 7) + bw > x_idx &&
|
|
|
|
(xd->mb_to_bottom_edge >> 7) + bh > y) {
|
2013-01-06 03:20:25 +01:00
|
|
|
MODE_INFO *mi_addr = xd->mode_info_context + x_idx + y * mis;
|
|
|
|
|
|
|
|
vpx_memcpy(mi_addr, mi, sizeof(MODE_INFO));
|
|
|
|
}
|
2012-10-30 01:58:18 +01:00
|
|
|
}
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
2013-04-10 06:28:27 +02:00
|
|
|
if (bsize < BLOCK_SIZE_SB32X32) {
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
ctx->txfm_rd_diff[ALLOW_32X32] = ctx->txfm_rd_diff[ALLOW_16X16];
|
2012-08-20 23:43:34 +02:00
|
|
|
}
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-04-11 21:16:35 +02:00
|
|
|
if (mb_mode == I4X4_PRED) {
|
2012-07-14 00:21:29 +02:00
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
xd->block[i].bmi.as_mode = xd->mode_info_context->bmi[i].as_mode;
|
2012-12-03 21:18:59 +01:00
|
|
|
assert(xd->block[i].bmi.as_mode.first < B_MODE_COUNT);
|
2012-04-07 01:38:34 +02:00
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
} else if (mb_mode == I8X8_PRED) {
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
xd->block[i].bmi = xd->mode_info_context->bmi[i];
|
2012-04-07 01:38:34 +02:00
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
} else if (mb_mode == SPLITMV) {
|
|
|
|
vpx_memcpy(x->partition_info, &ctx->partition_info,
|
|
|
|
sizeof(PARTITION_INFO));
|
|
|
|
|
2012-08-10 01:07:41 +02:00
|
|
|
mbmi->mv[0].as_int = x->partition_info->bmi[15].mv.as_int;
|
|
|
|
mbmi->mv[1].as_int = x->partition_info->bmi[15].second_mv.as_int;
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
|
|
|
|
2013-01-07 20:02:14 +01:00
|
|
|
x->skip = ctx->skip;
|
2013-01-06 03:20:25 +01:00
|
|
|
if (!output_enabled)
|
|
|
|
return;
|
|
|
|
|
2012-10-09 18:18:21 +02:00
|
|
|
{
|
2013-04-12 02:13:02 +02:00
|
|
|
int segment_id = mbmi->segment_id, ref_pred_flag;
|
2013-01-28 16:22:53 +01:00
|
|
|
if (!vp9_segfeature_active(xd, segment_id, SEG_LVL_SKIP)) {
|
2012-10-09 18:18:21 +02:00
|
|
|
for (i = 0; i < NB_TXFM_MODES; i++) {
|
|
|
|
cpi->rd_tx_select_diff[i] += ctx->txfm_rd_diff[i];
|
|
|
|
}
|
|
|
|
}
|
2013-04-12 02:13:02 +02:00
|
|
|
|
|
|
|
// Did the chosen reference frame match its predicted value.
|
|
|
|
ref_pred_flag = ((xd->mode_info_context->mbmi.ref_frame ==
|
|
|
|
vp9_get_pred_ref(cm, xd)));
|
|
|
|
vp9_set_pred_flag(xd, PRED_REF, ref_pred_flag);
|
|
|
|
if (!xd->segmentation_enabled ||
|
|
|
|
!vp9_segfeature_active(xd, segment_id, SEG_LVL_REF_FRAME) ||
|
|
|
|
vp9_check_segref(xd, segment_id, INTRA_FRAME) +
|
|
|
|
vp9_check_segref(xd, segment_id, LAST_FRAME) +
|
|
|
|
vp9_check_segref(xd, segment_id, GOLDEN_FRAME) +
|
|
|
|
vp9_check_segref(xd, segment_id, ALTREF_FRAME) > 1) {
|
|
|
|
// Get the prediction context and status
|
|
|
|
int pred_context = vp9_get_pred_context(cm, xd, PRED_REF);
|
|
|
|
|
|
|
|
// Count prediction success
|
|
|
|
cpi->ref_pred_count[pred_context][ref_pred_flag]++;
|
|
|
|
}
|
2012-10-09 18:18:21 +02:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
if (cpi->common.frame_type == KEY_FRAME) {
|
|
|
|
// Restore the coding modes to that held in the coding context
|
2013-04-11 21:16:35 +02:00
|
|
|
// if (mb_mode == I4X4_PRED)
|
2012-07-14 00:21:29 +02:00
|
|
|
// for (i = 0; i < 16; i++)
|
|
|
|
// {
|
|
|
|
// xd->block[i].bmi.as_mode =
|
|
|
|
// xd->mode_info_context->bmi[i].as_mode;
|
|
|
|
// assert(xd->mode_info_context->bmi[i].as_mode < MB_MODE_COUNT);
|
|
|
|
// }
|
2012-07-03 22:57:27 +02:00
|
|
|
#if CONFIG_INTERNAL_STATS
|
2012-07-14 00:21:29 +02:00
|
|
|
static const int kf_mode_index[] = {
|
|
|
|
THR_DC /*DC_PRED*/,
|
|
|
|
THR_V_PRED /*V_PRED*/,
|
|
|
|
THR_H_PRED /*H_PRED*/,
|
|
|
|
THR_D45_PRED /*D45_PRED*/,
|
|
|
|
THR_D135_PRED /*D135_PRED*/,
|
|
|
|
THR_D117_PRED /*D117_PRED*/,
|
|
|
|
THR_D153_PRED /*D153_PRED*/,
|
|
|
|
THR_D27_PRED /*D27_PRED*/,
|
|
|
|
THR_D63_PRED /*D63_PRED*/,
|
|
|
|
THR_TM /*TM_PRED*/,
|
|
|
|
THR_I8X8_PRED /*I8X8_PRED*/,
|
2013-04-11 21:16:35 +02:00
|
|
|
THR_B_PRED /*I4X4_PRED*/,
|
2012-07-14 00:21:29 +02:00
|
|
|
};
|
|
|
|
cpi->mode_chosen_counts[kf_mode_index[mb_mode]]++;
|
2012-07-03 22:57:27 +02:00
|
|
|
#endif
|
2012-07-14 00:21:29 +02:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
// Reduce the activation RD thresholds for the best choice mode
|
|
|
|
if ((cpi->rd_baseline_thresh[mb_mode_index] > 0) &&
|
|
|
|
(cpi->rd_baseline_thresh[mb_mode_index] < (INT_MAX >> 2)))
|
|
|
|
{
|
|
|
|
int best_adjustment = (cpi->rd_thresh_mult[mb_mode_index] >> 2);
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
cpi->rd_thresh_mult[mb_mode_index] =
|
|
|
|
(cpi->rd_thresh_mult[mb_mode_index]
|
|
|
|
>= (MIN_THRESHMULT + best_adjustment)) ?
|
|
|
|
cpi->rd_thresh_mult[mb_mode_index] - best_adjustment :
|
|
|
|
MIN_THRESHMULT;
|
|
|
|
cpi->rd_threshes[mb_mode_index] =
|
|
|
|
(cpi->rd_baseline_thresh[mb_mode_index] >> 7)
|
|
|
|
* cpi->rd_thresh_mult[mb_mode_index];
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
|
|
|
*/
|
|
|
|
// Note how often each mode chosen as best
|
|
|
|
cpi->mode_chosen_counts[mb_mode_index]++;
|
2012-11-09 19:52:08 +01:00
|
|
|
if (mbmi->mode == SPLITMV || mbmi->mode == NEWMV) {
|
|
|
|
int_mv best_mv, best_second_mv;
|
|
|
|
MV_REFERENCE_FRAME rf = mbmi->ref_frame;
|
|
|
|
best_mv.as_int = ctx->best_ref_mv.as_int;
|
|
|
|
best_second_mv.as_int = ctx->second_best_ref_mv.as_int;
|
|
|
|
if (mbmi->mode == NEWMV) {
|
|
|
|
best_mv.as_int = mbmi->ref_mvs[rf][0].as_int;
|
|
|
|
best_second_mv.as_int = mbmi->ref_mvs[mbmi->second_ref_frame][0].as_int;
|
|
|
|
}
|
|
|
|
mbmi->best_mv.as_int = best_mv.as_int;
|
|
|
|
mbmi->best_second_mv.as_int = best_second_mv.as_int;
|
|
|
|
vp9_update_nmv_count(cpi, x, &best_mv, &best_second_mv);
|
|
|
|
}
|
2012-11-07 15:50:25 +01:00
|
|
|
#if CONFIG_COMP_INTERINTRA_PRED
|
|
|
|
if (mbmi->mode >= NEARESTMV && mbmi->mode < SPLITMV &&
|
|
|
|
mbmi->second_ref_frame <= INTRA_FRAME) {
|
|
|
|
if (mbmi->second_ref_frame == INTRA_FRAME) {
|
|
|
|
++cpi->interintra_count[1];
|
|
|
|
++cpi->ymode_count[mbmi->interintra_mode];
|
|
|
|
#if SEPARATE_INTERINTRA_UV
|
|
|
|
++cpi->y_uv_mode_count[mbmi->interintra_mode][mbmi->interintra_uv_mode];
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
++cpi->interintra_count[0];
|
|
|
|
}
|
|
|
|
}
|
2012-12-10 21:10:36 +01:00
|
|
|
#endif
|
2012-11-30 01:39:15 +01:00
|
|
|
if (cpi->common.mcomp_filter_type == SWITCHABLE &&
|
|
|
|
mbmi->mode >= NEARESTMV &&
|
|
|
|
mbmi->mode <= SPLITMV) {
|
|
|
|
++cpi->switchable_interp_count
|
|
|
|
[vp9_get_pred_context(&cpi->common, xd, PRED_SWITCHABLE_INTERP)]
|
|
|
|
[vp9_switchable_interp_map[mbmi->interp_filter]];
|
|
|
|
}
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2012-11-08 20:03:00 +01:00
|
|
|
cpi->rd_comp_pred_diff[SINGLE_PREDICTION_ONLY] += ctx->single_pred_diff;
|
|
|
|
cpi->rd_comp_pred_diff[COMP_PREDICTION_ONLY] += ctx->comp_pred_diff;
|
|
|
|
cpi->rd_comp_pred_diff[HYBRID_PREDICTION] += ctx->hybrid_pred_diff;
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2012-04-07 01:38:34 +02:00
|
|
|
}
|
|
|
|
|
2013-04-10 06:28:27 +02:00
|
|
|
static unsigned find_seg_id(uint8_t *buf, BLOCK_SIZE_TYPE bsize,
|
2013-01-06 03:20:25 +01:00
|
|
|
int start_y, int height, int start_x, int width) {
|
2013-04-10 06:28:27 +02:00
|
|
|
const int bw = 1 << mb_width_log2(bsize), bh = 1 << mb_height_log2(bsize);
|
|
|
|
const int end_x = MIN(start_x + bw, width);
|
|
|
|
const int end_y = MIN(start_y + bh, height);
|
2013-01-06 03:20:25 +01:00
|
|
|
int x, y;
|
|
|
|
unsigned seg_id = -1;
|
|
|
|
|
|
|
|
buf += width * start_y;
|
|
|
|
for (y = start_y; y < end_y; y++, buf += width) {
|
|
|
|
for (x = start_x; x < end_x; x++) {
|
|
|
|
seg_id = MIN(seg_id, buf[x]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return seg_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_offsets(VP9_COMP *cpi,
|
2013-04-10 06:28:27 +02:00
|
|
|
int mb_row, int mb_col, BLOCK_SIZE_TYPE bsize) {
|
2013-01-06 03:20:25 +01:00
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
|
|
MB_MODE_INFO *mbmi;
|
|
|
|
const int dst_fb_idx = cm->new_fb_idx;
|
|
|
|
const int idx_map = mb_row * cm->mb_cols + mb_col;
|
|
|
|
const int idx_str = xd->mode_info_stride * mb_row + mb_col;
|
2013-04-10 06:28:27 +02:00
|
|
|
const int bw = 1 << mb_width_log2(bsize), bh = 1 << mb_height_log2(bsize);
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
// entropy context structures
|
|
|
|
xd->above_context = cm->above_context + mb_col;
|
|
|
|
xd->left_context = cm->left_context + (mb_row & 3);
|
|
|
|
|
|
|
|
// GF active flags data structure
|
|
|
|
x->gf_active_ptr = (signed char *)&cpi->gf_active_flags[idx_map];
|
|
|
|
|
|
|
|
// Activity map pointer
|
|
|
|
x->mb_activity_ptr = &cpi->mb_activity_map[idx_map];
|
|
|
|
x->active_ptr = cpi->active_map + idx_map;
|
|
|
|
|
|
|
|
/* pointers to mode info contexts */
|
|
|
|
x->partition_info = x->pi + idx_str;
|
|
|
|
xd->mode_info_context = cm->mi + idx_str;
|
|
|
|
mbmi = &xd->mode_info_context->mbmi;
|
|
|
|
xd->prev_mode_info_context = cm->prev_mi + idx_str;
|
|
|
|
|
|
|
|
// Set up destination pointers
|
2013-02-07 19:09:05 +01:00
|
|
|
setup_pred_block(&xd->dst,
|
|
|
|
&cm->yv12_fb[dst_fb_idx],
|
Spatial resamping of ZEROMV predictors
This patch allows coding frames using references of different
resolution, in ZEROMV mode. For compound prediction, either
reference may be scaled.
To test, I use the resize_test and enable WRITE_RECON_BUFFER
in vp9_onyxd_if.c. It's also useful to apply this patch to
test/i420_video_source.h:
--- a/test/i420_video_source.h
+++ b/test/i420_video_source.h
@@ -93,6 +93,7 @@ class I420VideoSource : public VideoSource {
virtual void FillFrame() {
// Read a frame from input_file.
+ if (frame_ != 3)
if (fread(img_->img_data, raw_sz_, 1, input_file_) == 0) {
limit_ = frame_;
}
This forces the frame that the resolution changes on to be coded
with no motion, only scaling, and improves the quality of the
result.
Change-Id: I1ee75d19a437ff801192f767fd02a36bcbd1d496
2013-02-25 05:55:14 +01:00
|
|
|
mb_row, mb_col, NULL, NULL);
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
/* Set up limit values for MV components to prevent them from
|
|
|
|
* extending beyond the UMV borders assuming 16x16 block size */
|
|
|
|
x->mv_row_min = -((mb_row * 16) + VP9BORDERINPIXELS - VP9_INTERP_EXTEND);
|
|
|
|
x->mv_col_min = -((mb_col * 16) + VP9BORDERINPIXELS - VP9_INTERP_EXTEND);
|
|
|
|
x->mv_row_max = ((cm->mb_rows - mb_row) * 16 +
|
2013-04-10 06:28:27 +02:00
|
|
|
(VP9BORDERINPIXELS - 16 * bh - VP9_INTERP_EXTEND));
|
2013-01-06 03:20:25 +01:00
|
|
|
x->mv_col_max = ((cm->mb_cols - mb_col) * 16 +
|
2013-04-10 06:28:27 +02:00
|
|
|
(VP9BORDERINPIXELS - 16 * bw - VP9_INTERP_EXTEND));
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
// Set up distance of MB to edge of frame in 1/8th pel units
|
2013-04-10 06:28:27 +02:00
|
|
|
assert(!(mb_col & (bw - 1)) && !(mb_row & (bh - 1)));
|
|
|
|
set_mb_row(cm, xd, mb_row, bh);
|
|
|
|
set_mb_col(cm, xd, mb_col, bw);
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
/* set up source buffers */
|
Spatial resamping of ZEROMV predictors
This patch allows coding frames using references of different
resolution, in ZEROMV mode. For compound prediction, either
reference may be scaled.
To test, I use the resize_test and enable WRITE_RECON_BUFFER
in vp9_onyxd_if.c. It's also useful to apply this patch to
test/i420_video_source.h:
--- a/test/i420_video_source.h
+++ b/test/i420_video_source.h
@@ -93,6 +93,7 @@ class I420VideoSource : public VideoSource {
virtual void FillFrame() {
// Read a frame from input_file.
+ if (frame_ != 3)
if (fread(img_->img_data, raw_sz_, 1, input_file_) == 0) {
limit_ = frame_;
}
This forces the frame that the resolution changes on to be coded
with no motion, only scaling, and improves the quality of the
result.
Change-Id: I1ee75d19a437ff801192f767fd02a36bcbd1d496
2013-02-25 05:55:14 +01:00
|
|
|
setup_pred_block(&x->src, cpi->Source, mb_row, mb_col, NULL, NULL);
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
/* R/D setup */
|
|
|
|
x->rddiv = cpi->RDDIV;
|
|
|
|
x->rdmult = cpi->RDMULT;
|
|
|
|
|
|
|
|
/* segment ID */
|
|
|
|
if (xd->segmentation_enabled) {
|
|
|
|
if (xd->update_mb_segmentation_map) {
|
2013-04-10 06:28:27 +02:00
|
|
|
mbmi->segment_id = find_seg_id(cpi->segmentation_map, bsize,
|
2013-01-06 03:20:25 +01:00
|
|
|
mb_row, cm->mb_rows, mb_col, cm->mb_cols);
|
|
|
|
} else {
|
2013-04-10 06:28:27 +02:00
|
|
|
mbmi->segment_id = find_seg_id(cm->last_frame_seg_map, bsize,
|
2013-01-06 03:20:25 +01:00
|
|
|
mb_row, cm->mb_rows, mb_col, cm->mb_cols);
|
|
|
|
}
|
|
|
|
assert(mbmi->segment_id <= 3);
|
|
|
|
vp9_mb_init_quantizer(cpi, x);
|
|
|
|
|
|
|
|
if (xd->segmentation_enabled && cpi->seg0_cnt > 0 &&
|
|
|
|
!vp9_segfeature_active(xd, 0, SEG_LVL_REF_FRAME) &&
|
|
|
|
vp9_segfeature_active(xd, 1, SEG_LVL_REF_FRAME) &&
|
|
|
|
vp9_check_segref(xd, 1, INTRA_FRAME) +
|
|
|
|
vp9_check_segref(xd, 1, LAST_FRAME) +
|
|
|
|
vp9_check_segref(xd, 1, GOLDEN_FRAME) +
|
|
|
|
vp9_check_segref(xd, 1, ALTREF_FRAME) == 1) {
|
|
|
|
cpi->seg0_progress = (cpi->seg0_idx << 16) / cpi->seg0_cnt;
|
|
|
|
} else {
|
|
|
|
const int y = mb_row & ~3;
|
|
|
|
const int x = mb_col & ~3;
|
|
|
|
const int p16 = ((mb_row & 1) << 1) + (mb_col & 1);
|
|
|
|
const int p32 = ((mb_row & 2) << 2) + ((mb_col & 2) << 1);
|
[WIP] Add column-based tiling.
This patch adds column-based tiling. The idea is to make each tile
independently decodable (after reading the common frame header) and
also independendly encodable (minus within-frame cost adjustments in
the RD loop) to speed-up hardware & software en/decoders if they used
multi-threading. Column-based tiling has the added advantage (over
other tiling methods) that it minimizes realtime use-case latency,
since all threads can start encoding data as soon as the first SB-row
worth of data is available to the encoder.
There is some test code that does random tile ordering in the decoder,
to confirm that each tile is indeed independently decodable from other
tiles in the same frame. At tile edges, all contexts assume default
values (i.e. 0, 0 motion vector, no coefficients, DC intra4x4 mode),
and motion vector search and ordering do not cross tiles in the same
frame.
t log
Tile independence is not maintained between frames ATM, i.e. tile 0 of
frame 1 is free to use motion vectors that point into any tile of frame
0. We support 1 (i.e. no tiling), 2 or 4 column-tiles.
The loopfilter crosses tile boundaries. I discussed this briefly with Aki
and he says that's OK. An in-loop loopfilter would need to do some sync
between tile threads, but that shouldn't be a big issue.
Resuls: with tiling disabled, we go up slightly because of improved edge
use in the intra4x4 prediction. With 2 tiles, we lose about ~1% on derf,
~0.35% on HD and ~0.55% on STD/HD. With 4 tiles, we lose another ~1.5%
on derf ~0.77% on HD and ~0.85% on STD/HD. Most of this loss is
concentrated in the low-bitrate end of clips, and most of it is because
of the loss of edges at tile boundaries and the resulting loss of intra
predictors.
TODO:
- more tiles (perhaps allow row-based tiling also, and max. 8 tiles)?
- maybe optionally (for EC purposes), motion vectors themselves
should not cross tile edges, or we should emulate such borders as
if they were off-frame, to limit error propagation to within one
tile only. This doesn't have to be the default behaviour but could
be an optional bitstream flag.
Change-Id: I5951c3a0742a767b20bc9fb5af685d9892c2c96f
2013-02-01 18:35:28 +01:00
|
|
|
const int tile_progress = cm->cur_tile_mb_col_start * cm->mb_rows;
|
|
|
|
const int mb_cols = cm->cur_tile_mb_col_end - cm->cur_tile_mb_col_start;
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
cpi->seg0_progress =
|
[WIP] Add column-based tiling.
This patch adds column-based tiling. The idea is to make each tile
independently decodable (after reading the common frame header) and
also independendly encodable (minus within-frame cost adjustments in
the RD loop) to speed-up hardware & software en/decoders if they used
multi-threading. Column-based tiling has the added advantage (over
other tiling methods) that it minimizes realtime use-case latency,
since all threads can start encoding data as soon as the first SB-row
worth of data is available to the encoder.
There is some test code that does random tile ordering in the decoder,
to confirm that each tile is indeed independently decodable from other
tiles in the same frame. At tile edges, all contexts assume default
values (i.e. 0, 0 motion vector, no coefficients, DC intra4x4 mode),
and motion vector search and ordering do not cross tiles in the same
frame.
t log
Tile independence is not maintained between frames ATM, i.e. tile 0 of
frame 1 is free to use motion vectors that point into any tile of frame
0. We support 1 (i.e. no tiling), 2 or 4 column-tiles.
The loopfilter crosses tile boundaries. I discussed this briefly with Aki
and he says that's OK. An in-loop loopfilter would need to do some sync
between tile threads, but that shouldn't be a big issue.
Resuls: with tiling disabled, we go up slightly because of improved edge
use in the intra4x4 prediction. With 2 tiles, we lose about ~1% on derf,
~0.35% on HD and ~0.55% on STD/HD. With 4 tiles, we lose another ~1.5%
on derf ~0.77% on HD and ~0.85% on STD/HD. Most of this loss is
concentrated in the low-bitrate end of clips, and most of it is because
of the loss of edges at tile boundaries and the resulting loss of intra
predictors.
TODO:
- more tiles (perhaps allow row-based tiling also, and max. 8 tiles)?
- maybe optionally (for EC purposes), motion vectors themselves
should not cross tile edges, or we should emulate such borders as
if they were off-frame, to limit error propagation to within one
tile only. This doesn't have to be the default behaviour but could
be an optional bitstream flag.
Change-Id: I5951c3a0742a767b20bc9fb5af685d9892c2c96f
2013-02-01 18:35:28 +01:00
|
|
|
((y * mb_cols + x * 4 + p32 + p16 + tile_progress) << 16) / cm->MBs;
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
mbmi->segment_id = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-12 02:13:02 +02:00
|
|
|
static int pick_mb_mode(VP9_COMP *cpi,
|
|
|
|
int mb_row,
|
|
|
|
int mb_col,
|
|
|
|
TOKENEXTRA **tp,
|
|
|
|
int *totalrate,
|
|
|
|
int *totaldist) {
|
2013-01-07 20:41:49 +01:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
2013-02-05 13:54:09 +01:00
|
|
|
int splitmodes_used = 0;
|
2013-04-12 00:56:39 +02:00
|
|
|
MB_MODE_INFO *mbmi;
|
2013-02-07 19:09:05 +01:00
|
|
|
|
2013-04-12 00:56:39 +02:00
|
|
|
set_offsets(cpi, mb_row, mb_col, BLOCK_SIZE_MB16X16);
|
2012-08-20 23:43:34 +02:00
|
|
|
|
2013-04-12 00:56:39 +02:00
|
|
|
if (cpi->oxcf.tuning == VP8_TUNE_SSIM)
|
|
|
|
vp9_activity_masking(cpi, x);
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2013-04-12 00:56:39 +02:00
|
|
|
mbmi = &xd->mode_info_context->mbmi;
|
|
|
|
mbmi->sb_type = BLOCK_SIZE_MB16X16;
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2013-04-12 00:56:39 +02:00
|
|
|
// Find best coding mode & reconstruct the MB so it is available
|
|
|
|
// as a predictor for MBs that follow in the SB
|
|
|
|
if (cm->frame_type == KEY_FRAME) {
|
|
|
|
vp9_rd_pick_intra_mode(cpi, x, totalrate, totaldist);
|
2013-02-05 13:54:09 +01:00
|
|
|
|
2013-04-12 00:56:39 +02:00
|
|
|
// Save the coding context
|
|
|
|
vpx_memcpy(&x->mb_context[xd->sb_index][xd->mb_index].mic,
|
|
|
|
xd->mode_info_context, sizeof(MODE_INFO));
|
|
|
|
} else {
|
|
|
|
vp9_pick_mode_inter_macroblock(cpi, x, mb_row, mb_col,
|
|
|
|
totalrate, totaldist);
|
|
|
|
splitmodes_used += (mbmi->mode == SPLITMV);
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2013-04-12 02:13:02 +02:00
|
|
|
if (cpi->mb.e_mbd.segmentation_enabled && mbmi->segment_id == 0) {
|
2013-04-12 00:56:39 +02:00
|
|
|
cpi->seg0_idx++;
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-05 13:54:09 +01:00
|
|
|
return splitmodes_used;
|
2012-04-07 01:38:34 +02:00
|
|
|
}
|
|
|
|
|
2013-04-11 18:33:49 +02:00
|
|
|
static void pick_sb_modes(VP9_COMP *cpi, int mb_row, int mb_col,
|
|
|
|
TOKENEXTRA **tp, int *totalrate, int *totaldist,
|
|
|
|
BLOCK_SIZE_TYPE bsize, PICK_MODE_CONTEXT *ctx) {
|
2013-01-07 20:41:49 +01:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
2012-08-20 23:43:34 +02:00
|
|
|
|
2013-04-11 18:33:49 +02:00
|
|
|
set_offsets(cpi, mb_row, mb_col, bsize);
|
|
|
|
xd->mode_info_context->mbmi.sb_type = bsize;
|
2013-01-06 03:20:25 +01:00
|
|
|
if (cpi->oxcf.tuning == VP8_TUNE_SSIM)
|
2012-10-30 20:58:42 +01:00
|
|
|
vp9_activity_masking(cpi, x);
|
2012-08-20 23:43:34 +02:00
|
|
|
|
|
|
|
/* Find best coding mode & reconstruct the MB so it is available
|
|
|
|
* as a predictor for MBs that follow in the SB */
|
2013-01-06 03:20:25 +01:00
|
|
|
if (cm->frame_type == KEY_FRAME) {
|
2013-04-11 18:33:49 +02:00
|
|
|
vp9_rd_pick_intra_mode_sb(cpi, x, totalrate, totaldist, bsize, ctx);
|
2013-01-06 03:20:25 +01:00
|
|
|
} else {
|
2013-04-11 00:55:59 +02:00
|
|
|
vp9_rd_pick_inter_mode_sb(cpi, x, mb_row, mb_col, totalrate, totaldist,
|
2013-04-11 18:33:49 +02:00
|
|
|
bsize, ctx);
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
|
|
|
}
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-02-20 19:16:24 +01:00
|
|
|
static void update_stats(VP9_COMP *cpi, int mb_row, int mb_col) {
|
2013-01-06 03:20:25 +01:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
|
|
MODE_INFO *mi = xd->mode_info_context;
|
|
|
|
MB_MODE_INFO *const mbmi = &mi->mbmi;
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
if (cm->frame_type == KEY_FRAME) {
|
|
|
|
#ifdef MODE_STATS
|
|
|
|
y_modes[mbmi->mode]++;
|
2012-04-07 01:38:34 +02:00
|
|
|
#endif
|
2013-01-06 03:20:25 +01:00
|
|
|
} else {
|
|
|
|
int segment_id, seg_ref_active;
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
if (mbmi->ref_frame) {
|
|
|
|
int pred_context = vp9_get_pred_context(cm, xd, PRED_COMP);
|
2012-11-13 00:43:11 +01:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
if (mbmi->second_ref_frame <= INTRA_FRAME)
|
|
|
|
cpi->single_pred_count[pred_context]++;
|
|
|
|
else
|
|
|
|
cpi->comp_pred_count[pred_context]++;
|
2012-08-20 23:43:34 +02:00
|
|
|
}
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
#ifdef MODE_STATS
|
|
|
|
inter_y_modes[mbmi->mode]++;
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
if (mbmi->mode == SPLITMV) {
|
|
|
|
int b;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
for (b = 0; b < x->partition_info->count; b++) {
|
|
|
|
inter_b_modes[x->partition_info->bmi[b].mode]++;
|
|
|
|
}
|
|
|
|
}
|
2012-11-10 17:39:51 +01:00
|
|
|
#endif
|
2011-06-23 19:54:02 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
// If we have just a single reference frame coded for a segment then
|
|
|
|
// exclude from the reference frame counts used to work out
|
|
|
|
// probabilities. NOTE: At the moment we dont support custom trees
|
|
|
|
// for the reference frame coding for each segment but this is a
|
|
|
|
// possible future action.
|
|
|
|
segment_id = mbmi->segment_id;
|
|
|
|
seg_ref_active = vp9_segfeature_active(xd, segment_id,
|
|
|
|
SEG_LVL_REF_FRAME);
|
|
|
|
if (!seg_ref_active ||
|
|
|
|
((vp9_check_segref(xd, segment_id, INTRA_FRAME) +
|
|
|
|
vp9_check_segref(xd, segment_id, LAST_FRAME) +
|
|
|
|
vp9_check_segref(xd, segment_id, GOLDEN_FRAME) +
|
|
|
|
vp9_check_segref(xd, segment_id, ALTREF_FRAME)) > 1)) {
|
|
|
|
cpi->count_mb_ref_frame_usage[mbmi->ref_frame]++;
|
2012-08-20 23:43:34 +02:00
|
|
|
}
|
2013-01-06 03:20:25 +01:00
|
|
|
// Count of last ref frame 0,0 usage
|
|
|
|
if ((mbmi->mode == ZEROMV) && (mbmi->ref_frame == LAST_FRAME))
|
|
|
|
cpi->inter_zz_count++;
|
|
|
|
}
|
2013-02-20 19:16:24 +01:00
|
|
|
#if CONFIG_CODE_NONZEROCOUNT
|
|
|
|
vp9_update_nzc_counts(&cpi->common, xd, mb_row, mb_col);
|
|
|
|
#endif
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
static void encode_sb(VP9_COMP *cpi,
|
|
|
|
int mb_row,
|
|
|
|
int mb_col,
|
|
|
|
int output_enabled,
|
2013-04-17 18:25:06 +02:00
|
|
|
TOKENEXTRA **tp, BLOCK_SIZE_TYPE is_sb) {
|
2013-01-07 20:41:49 +01:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
2013-04-16 09:18:02 +02:00
|
|
|
BLOCK_SIZE_TYPE bsize = BLOCK_SIZE_SB32X32;
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2013-04-17 18:25:06 +02:00
|
|
|
if (is_sb == BLOCK_SIZE_SB32X32) {
|
2013-04-16 09:18:02 +02:00
|
|
|
set_offsets(cpi, mb_row, mb_col, bsize);
|
2013-04-10 06:28:27 +02:00
|
|
|
update_state(cpi, &x->sb32_context[xd->sb_index],
|
2013-04-16 09:18:02 +02:00
|
|
|
bsize, output_enabled);
|
2012-10-26 03:09:02 +02:00
|
|
|
|
2013-04-10 06:28:27 +02:00
|
|
|
encode_superblock(cpi, tp,
|
2013-04-16 09:18:02 +02:00
|
|
|
output_enabled, mb_row, mb_col, bsize);
|
2013-02-20 19:16:24 +01:00
|
|
|
if (output_enabled) {
|
|
|
|
update_stats(cpi, mb_row, mb_col);
|
2013-04-16 09:18:02 +02:00
|
|
|
cpi->partition_count[partition_plane(bsize)][PARTITION_NONE]++;
|
2011-02-14 23:18:18 +01:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
(*tp)->Token = EOSB_TOKEN;
|
|
|
|
(*tp)++;
|
|
|
|
}
|
2013-04-17 18:25:06 +02:00
|
|
|
#if CONFIG_SBSEGMENT
|
|
|
|
} else if (is_sb == BLOCK_SIZE_SB16X32) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (output_enabled)
|
|
|
|
cpi->partition_count[partition_plane(bsize)][PARTITION_VERT]++;
|
|
|
|
for (i = 0; i < 2 && mb_col + i != cm->mb_cols; i++) {
|
|
|
|
set_offsets(cpi, mb_row, mb_col + i, BLOCK_SIZE_SB16X32);
|
|
|
|
update_state(cpi, &x->sb16x32_context[xd->sb_index][i],
|
|
|
|
BLOCK_SIZE_SB16X32, output_enabled);
|
|
|
|
encode_superblock(cpi, tp,
|
|
|
|
output_enabled, mb_row, mb_col + i, BLOCK_SIZE_SB16X32);
|
|
|
|
if (output_enabled) {
|
|
|
|
update_stats(cpi, mb_row, mb_col + i);
|
|
|
|
|
|
|
|
(*tp)->Token = EOSB_TOKEN;
|
|
|
|
(*tp)++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (is_sb == BLOCK_SIZE_SB32X16) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (output_enabled)
|
|
|
|
cpi->partition_count[partition_plane(bsize)][PARTITION_HORZ]++;
|
|
|
|
for (i = 0; i < 2 && mb_row + i != cm->mb_rows; i++) {
|
|
|
|
set_offsets(cpi, mb_row + i, mb_col, BLOCK_SIZE_SB32X16);
|
|
|
|
update_state(cpi, &x->sb32x16_context[xd->sb_index][i],
|
|
|
|
BLOCK_SIZE_SB32X16, output_enabled);
|
|
|
|
encode_superblock(cpi, tp,
|
|
|
|
output_enabled, mb_row + i, mb_col, BLOCK_SIZE_SB32X16);
|
|
|
|
if (output_enabled) {
|
|
|
|
update_stats(cpi, mb_row + i, mb_col);
|
|
|
|
|
|
|
|
(*tp)->Token = EOSB_TOKEN;
|
|
|
|
(*tp)++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2013-01-08 19:29:22 +01:00
|
|
|
} else {
|
2013-01-06 03:20:25 +01:00
|
|
|
int i;
|
2013-04-16 09:18:02 +02:00
|
|
|
if (output_enabled)
|
|
|
|
cpi->partition_count[partition_plane(bsize)][PARTITION_SPLIT]++;
|
2012-08-20 23:43:34 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
const int x_idx = i & 1, y_idx = i >> 1;
|
2012-08-20 23:43:34 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
if ((mb_row + y_idx >= cm->mb_rows) || (mb_col + x_idx >= cm->mb_cols)) {
|
|
|
|
// MB lies outside frame, move on
|
|
|
|
continue;
|
2012-08-20 23:43:34 +02:00
|
|
|
}
|
|
|
|
|
2013-04-10 06:28:27 +02:00
|
|
|
set_offsets(cpi, mb_row + y_idx, mb_col + x_idx, BLOCK_SIZE_MB16X16);
|
2013-01-06 03:20:25 +01:00
|
|
|
xd->mb_index = i;
|
2013-04-10 06:28:27 +02:00
|
|
|
update_state(cpi, &x->mb_context[xd->sb_index][i],
|
|
|
|
BLOCK_SIZE_MB16X16, output_enabled);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
if (cpi->oxcf.tuning == VP8_TUNE_SSIM)
|
|
|
|
vp9_activity_masking(cpi, x);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-02-07 19:09:05 +01:00
|
|
|
encode_macroblock(cpi, tp,
|
2013-01-06 03:20:25 +01:00
|
|
|
output_enabled, mb_row + y_idx, mb_col + x_idx);
|
2013-02-20 19:16:24 +01:00
|
|
|
if (output_enabled) {
|
|
|
|
update_stats(cpi, mb_row + y_idx, mb_col + x_idx);
|
2012-10-16 01:41:41 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
(*tp)->Token = EOSB_TOKEN;
|
2013-04-17 18:25:06 +02:00
|
|
|
(*tp)++;
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
2012-08-20 23:43:34 +02:00
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// debug output
|
2012-04-07 01:38:34 +02:00
|
|
|
#if DBG_PRNT_SEGMAP
|
2012-07-14 00:21:29 +02:00
|
|
|
{
|
|
|
|
FILE *statsfile;
|
|
|
|
statsfile = fopen("segmap2.stt", "a");
|
|
|
|
fprintf(statsfile, "\n");
|
|
|
|
fclose(statsfile);
|
|
|
|
}
|
2013-01-06 03:20:25 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void encode_sb64(VP9_COMP *cpi,
|
|
|
|
int mb_row,
|
|
|
|
int mb_col,
|
2013-04-17 18:25:06 +02:00
|
|
|
TOKENEXTRA **tp, BLOCK_SIZE_TYPE is_sb[4]) {
|
2013-01-07 20:41:49 +01:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
2013-04-16 09:18:02 +02:00
|
|
|
BLOCK_SIZE_TYPE bsize = BLOCK_SIZE_SB64X64;
|
2013-01-07 20:41:49 +01:00
|
|
|
|
2013-04-17 18:25:06 +02:00
|
|
|
if (is_sb[0] == BLOCK_SIZE_SB64X64) {
|
2013-04-16 09:18:02 +02:00
|
|
|
set_offsets(cpi, mb_row, mb_col, bsize);
|
|
|
|
update_state(cpi, &x->sb64_context, bsize, 1);
|
2013-04-10 06:28:27 +02:00
|
|
|
encode_superblock(cpi, tp,
|
2013-04-16 09:18:02 +02:00
|
|
|
1, mb_row, mb_col, bsize);
|
2013-02-20 19:16:24 +01:00
|
|
|
update_stats(cpi, mb_row, mb_col);
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
(*tp)->Token = EOSB_TOKEN;
|
|
|
|
(*tp)++;
|
2013-04-16 09:18:02 +02:00
|
|
|
cpi->partition_count[partition_plane(bsize)][PARTITION_NONE]++;
|
2013-04-17 18:25:06 +02:00
|
|
|
#if CONFIG_SBSEGMENT
|
|
|
|
} else if (is_sb[0] == BLOCK_SIZE_SB32X64) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
cpi->partition_count[partition_plane(bsize)][PARTITION_VERT]++;
|
|
|
|
for (i = 0; i < 2 && mb_col + i * 2 != cm->mb_cols; i++) {
|
|
|
|
set_offsets(cpi, mb_row, mb_col + i * 2, BLOCK_SIZE_SB32X64);
|
|
|
|
update_state(cpi, &x->sb32x64_context[i], BLOCK_SIZE_SB32X64, 1);
|
|
|
|
encode_superblock(cpi, tp,
|
|
|
|
1, mb_row, mb_col + i * 2, BLOCK_SIZE_SB32X64);
|
|
|
|
update_stats(cpi, mb_row, mb_col + i * 2);
|
|
|
|
|
|
|
|
(*tp)->Token = EOSB_TOKEN;
|
|
|
|
(*tp)++;
|
|
|
|
}
|
|
|
|
} else if (is_sb[0] == BLOCK_SIZE_SB64X32) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
cpi->partition_count[partition_plane(bsize)][PARTITION_HORZ]++;
|
|
|
|
for (i = 0; i < 2 && mb_row + i * 2 != cm->mb_rows; i++) {
|
|
|
|
set_offsets(cpi, mb_row + i * 2, mb_col, BLOCK_SIZE_SB64X32);
|
|
|
|
update_state(cpi, &x->sb64x32_context[i], BLOCK_SIZE_SB64X32, 1);
|
|
|
|
encode_superblock(cpi, tp,
|
|
|
|
1, mb_row + i * 2, mb_col, BLOCK_SIZE_SB64X32);
|
|
|
|
update_stats(cpi, mb_row + i * 2, mb_col);
|
|
|
|
|
|
|
|
(*tp)->Token = EOSB_TOKEN;
|
|
|
|
(*tp)++;
|
|
|
|
}
|
|
|
|
#endif
|
2013-01-06 03:20:25 +01:00
|
|
|
} else {
|
|
|
|
int i;
|
2013-04-16 09:18:02 +02:00
|
|
|
cpi->partition_count[partition_plane(bsize)][PARTITION_SPLIT]++;
|
2013-01-06 03:20:25 +01:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
const int x_idx = i & 1, y_idx = i >> 1;
|
|
|
|
|
|
|
|
if (mb_row + y_idx * 2 >= cm->mb_rows ||
|
|
|
|
mb_col + x_idx * 2 >= cm->mb_cols) {
|
|
|
|
// MB lies outside frame, move on
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
xd->sb_index = i;
|
2013-01-07 20:41:49 +01:00
|
|
|
encode_sb(cpi, mb_row + 2 * y_idx, mb_col + 2 * x_idx, 1, tp,
|
2013-01-06 03:20:25 +01:00
|
|
|
is_sb[i]);
|
|
|
|
}
|
|
|
|
}
|
2012-04-07 01:38:34 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
static void encode_sb_row(VP9_COMP *cpi,
|
|
|
|
int mb_row,
|
|
|
|
TOKENEXTRA **tp,
|
|
|
|
int *totalrate) {
|
2013-01-07 20:41:49 +01:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
2012-07-14 00:21:29 +02:00
|
|
|
int mb_col;
|
|
|
|
|
|
|
|
// Initialize the left context for the new SB row
|
2012-08-20 23:43:34 +02:00
|
|
|
vpx_memset(cm->left_context, 0, sizeof(cm->left_context));
|
2012-07-14 00:21:29 +02:00
|
|
|
|
|
|
|
// Code each SB in the row
|
[WIP] Add column-based tiling.
This patch adds column-based tiling. The idea is to make each tile
independently decodable (after reading the common frame header) and
also independendly encodable (minus within-frame cost adjustments in
the RD loop) to speed-up hardware & software en/decoders if they used
multi-threading. Column-based tiling has the added advantage (over
other tiling methods) that it minimizes realtime use-case latency,
since all threads can start encoding data as soon as the first SB-row
worth of data is available to the encoder.
There is some test code that does random tile ordering in the decoder,
to confirm that each tile is indeed independently decodable from other
tiles in the same frame. At tile edges, all contexts assume default
values (i.e. 0, 0 motion vector, no coefficients, DC intra4x4 mode),
and motion vector search and ordering do not cross tiles in the same
frame.
t log
Tile independence is not maintained between frames ATM, i.e. tile 0 of
frame 1 is free to use motion vectors that point into any tile of frame
0. We support 1 (i.e. no tiling), 2 or 4 column-tiles.
The loopfilter crosses tile boundaries. I discussed this briefly with Aki
and he says that's OK. An in-loop loopfilter would need to do some sync
between tile threads, but that shouldn't be a big issue.
Resuls: with tiling disabled, we go up slightly because of improved edge
use in the intra4x4 prediction. With 2 tiles, we lose about ~1% on derf,
~0.35% on HD and ~0.55% on STD/HD. With 4 tiles, we lose another ~1.5%
on derf ~0.77% on HD and ~0.85% on STD/HD. Most of this loss is
concentrated in the low-bitrate end of clips, and most of it is because
of the loss of edges at tile boundaries and the resulting loss of intra
predictors.
TODO:
- more tiles (perhaps allow row-based tiling also, and max. 8 tiles)?
- maybe optionally (for EC purposes), motion vectors themselves
should not cross tile edges, or we should emulate such borders as
if they were off-frame, to limit error propagation to within one
tile only. This doesn't have to be the default behaviour but could
be an optional bitstream flag.
Change-Id: I5951c3a0742a767b20bc9fb5af685d9892c2c96f
2013-02-01 18:35:28 +01:00
|
|
|
for (mb_col = cm->cur_tile_mb_col_start;
|
|
|
|
mb_col < cm->cur_tile_mb_col_end; mb_col += 4) {
|
2013-01-06 03:20:25 +01:00
|
|
|
int i;
|
2013-04-17 18:25:06 +02:00
|
|
|
BLOCK_SIZE_TYPE sb_partitioning[4];
|
|
|
|
int sb64_rate = 0, sb64_dist = 0;
|
2013-02-05 13:54:09 +01:00
|
|
|
int sb64_skip = 0;
|
2013-01-06 03:20:25 +01:00
|
|
|
ENTROPY_CONTEXT_PLANES l[4], a[4];
|
|
|
|
TOKENEXTRA *tp_orig = *tp;
|
|
|
|
|
|
|
|
memcpy(&a, cm->above_context + mb_col, sizeof(a));
|
|
|
|
memcpy(&l, cm->left_context, sizeof(l));
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
const int x_idx = (i & 1) << 1, y_idx = i & 2;
|
2013-04-17 18:25:06 +02:00
|
|
|
int sb32_rate = 0, sb32_dist = 0;
|
2013-02-05 13:54:09 +01:00
|
|
|
int splitmodes_used = 0;
|
|
|
|
int sb32_skip = 0;
|
2013-04-12 00:56:39 +02:00
|
|
|
int j;
|
|
|
|
ENTROPY_CONTEXT_PLANES l2[2], a2[2];
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
if (mb_row + y_idx >= cm->mb_rows || mb_col + x_idx >= cm->mb_cols)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
xd->sb_index = i;
|
|
|
|
|
2013-04-12 00:56:39 +02:00
|
|
|
/* Function should not modify L & A contexts; save and restore on exit */
|
|
|
|
vpx_memcpy(l2, cm->left_context + y_idx, sizeof(l2));
|
|
|
|
vpx_memcpy(a2, cm->above_context + mb_col + x_idx, sizeof(a2));
|
|
|
|
|
|
|
|
/* Encode MBs in raster order within the SB */
|
2013-04-17 18:25:06 +02:00
|
|
|
sb_partitioning[i] = BLOCK_SIZE_MB16X16;
|
2013-04-12 00:56:39 +02:00
|
|
|
for (j = 0; j < 4; j++) {
|
|
|
|
const int x_idx_m = x_idx + (j & 1), y_idx_m = y_idx + (j >> 1);
|
|
|
|
int r, d;
|
|
|
|
|
|
|
|
if (mb_row + y_idx_m >= cm->mb_rows ||
|
|
|
|
mb_col + x_idx_m >= cm->mb_cols) {
|
|
|
|
// MB lies outside frame, move on
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Index of the MB in the SB 0..3
|
|
|
|
xd->mb_index = j;
|
|
|
|
|
2013-04-12 02:13:02 +02:00
|
|
|
splitmodes_used += pick_mb_mode(cpi, mb_row + y_idx_m,
|
|
|
|
mb_col + x_idx_m, tp, &r, &d);
|
2013-04-17 18:25:06 +02:00
|
|
|
sb32_rate += r;
|
|
|
|
sb32_dist += d;
|
2013-04-12 02:13:02 +02:00
|
|
|
|
|
|
|
// Dummy encode, do not do the tokenization
|
|
|
|
encode_macroblock(cpi, tp, 0, mb_row + y_idx_m,
|
|
|
|
mb_col + x_idx_m);
|
2013-04-12 00:56:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore L & A coding context to those in place on entry */
|
|
|
|
vpx_memcpy(cm->left_context + y_idx, l2, sizeof(l2));
|
|
|
|
vpx_memcpy(cm->above_context + mb_col + x_idx, a2, sizeof(a2));
|
2013-02-05 13:54:09 +01:00
|
|
|
|
2013-04-17 18:25:06 +02:00
|
|
|
sb32_rate += x->partition_cost[partition_plane(BLOCK_SIZE_SB32X32)]
|
|
|
|
[PARTITION_SPLIT];
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-02-05 13:54:09 +01:00
|
|
|
if (cpi->sf.splitmode_breakout) {
|
|
|
|
sb32_skip = splitmodes_used;
|
|
|
|
sb64_skip += splitmodes_used;
|
|
|
|
}
|
|
|
|
|
2013-04-17 18:25:06 +02:00
|
|
|
#if CONFIG_SBSEGMENT
|
|
|
|
// check 32x16
|
|
|
|
if (mb_col + x_idx + 1 < cm->mb_cols) {
|
|
|
|
int r, d;
|
|
|
|
|
|
|
|
xd->mb_index = 0;
|
|
|
|
pick_sb_modes(cpi, mb_row + y_idx, mb_col + x_idx,
|
|
|
|
tp, &r, &d, BLOCK_SIZE_SB32X16,
|
|
|
|
&x->sb32x16_context[xd->sb_index][xd->mb_index]);
|
|
|
|
if (mb_row + y_idx + 1 < cm->mb_rows) {
|
|
|
|
int r2, d2;
|
|
|
|
|
|
|
|
update_state(cpi, &x->sb32x16_context[xd->sb_index][xd->mb_index],
|
|
|
|
BLOCK_SIZE_SB32X16, 0);
|
|
|
|
encode_superblock(cpi, tp,
|
|
|
|
0, mb_row + y_idx, mb_col + x_idx,
|
|
|
|
BLOCK_SIZE_SB32X16);
|
|
|
|
xd->mb_index = 1;
|
|
|
|
pick_sb_modes(cpi, mb_row + y_idx + 1, mb_col + x_idx,
|
|
|
|
tp, &r2, &d2, BLOCK_SIZE_SB32X16,
|
|
|
|
&x->sb32x16_context[xd->sb_index][xd->mb_index]);
|
|
|
|
r += r2;
|
|
|
|
d += d2;
|
|
|
|
}
|
|
|
|
|
|
|
|
r += x->partition_cost[partition_plane(BLOCK_SIZE_SB32X32)]
|
|
|
|
[PARTITION_HORZ];
|
|
|
|
|
|
|
|
/* is this better than MB coding? */
|
|
|
|
if (RDCOST(x->rdmult, x->rddiv, r, d) <
|
|
|
|
RDCOST(x->rdmult, x->rddiv, sb32_rate, sb32_dist)) {
|
|
|
|
sb32_rate = r;
|
|
|
|
sb32_dist = d;
|
|
|
|
sb_partitioning[i] = BLOCK_SIZE_SB32X16;
|
|
|
|
}
|
|
|
|
|
|
|
|
vpx_memcpy(cm->left_context + y_idx, l2, sizeof(l2));
|
|
|
|
vpx_memcpy(cm->above_context + mb_col + x_idx, a2, sizeof(a2));
|
|
|
|
}
|
|
|
|
|
|
|
|
// check 16x32
|
|
|
|
if (mb_row + y_idx + 1 < cm->mb_rows) {
|
|
|
|
int r, d;
|
|
|
|
|
|
|
|
xd->mb_index = 0;
|
|
|
|
pick_sb_modes(cpi, mb_row + y_idx, mb_col + x_idx,
|
|
|
|
tp, &r, &d, BLOCK_SIZE_SB16X32,
|
|
|
|
&x->sb16x32_context[xd->sb_index][xd->mb_index]);
|
|
|
|
if (mb_col + x_idx + 1 < cm->mb_cols) {
|
|
|
|
int r2, d2;
|
|
|
|
|
|
|
|
update_state(cpi, &x->sb16x32_context[xd->sb_index][xd->mb_index],
|
|
|
|
BLOCK_SIZE_SB16X32, 0);
|
|
|
|
encode_superblock(cpi, tp,
|
|
|
|
0, mb_row + y_idx, mb_col + x_idx,
|
|
|
|
BLOCK_SIZE_SB16X32);
|
|
|
|
xd->mb_index = 1;
|
|
|
|
pick_sb_modes(cpi, mb_row + y_idx, mb_col + x_idx + 1,
|
|
|
|
tp, &r2, &d2, BLOCK_SIZE_SB16X32,
|
|
|
|
&x->sb16x32_context[xd->sb_index][xd->mb_index]);
|
|
|
|
r += r2;
|
|
|
|
d += d2;
|
|
|
|
}
|
|
|
|
|
|
|
|
r += x->partition_cost[partition_plane(BLOCK_SIZE_SB32X32)]
|
|
|
|
[PARTITION_VERT];
|
|
|
|
|
|
|
|
/* is this better than MB coding? */
|
|
|
|
if (RDCOST(x->rdmult, x->rddiv, r, d) <
|
|
|
|
RDCOST(x->rdmult, x->rddiv, sb32_rate, sb32_dist)) {
|
|
|
|
sb32_rate = r;
|
|
|
|
sb32_dist = d;
|
|
|
|
sb_partitioning[i] = BLOCK_SIZE_SB16X32;
|
|
|
|
}
|
|
|
|
|
|
|
|
vpx_memcpy(cm->left_context + y_idx, l2, sizeof(l2));
|
|
|
|
vpx_memcpy(cm->above_context + mb_col + x_idx, a2, sizeof(a2));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-04-11 18:14:55 +02:00
|
|
|
if (!sb32_skip && !(mb_col + x_idx + 1 >= cm->mb_cols ||
|
|
|
|
mb_row + y_idx + 1 >= cm->mb_rows)) {
|
2013-04-17 18:25:06 +02:00
|
|
|
int r, d;
|
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
/* Pick a mode assuming that it applies to all 4 of the MBs in the SB */
|
2013-01-07 20:41:49 +01:00
|
|
|
pick_sb_modes(cpi, mb_row + y_idx, mb_col + x_idx,
|
2013-04-17 18:25:06 +02:00
|
|
|
tp, &r, &d, BLOCK_SIZE_SB32X32,
|
2013-04-11 18:33:49 +02:00
|
|
|
&x->sb32_context[xd->sb_index]);
|
2013-04-17 18:25:06 +02:00
|
|
|
r += x->partition_cost[partition_plane(BLOCK_SIZE_SB32X32)]
|
|
|
|
[PARTITION_NONE];
|
|
|
|
|
|
|
|
if (RDCOST(x->rdmult, x->rddiv, r, d) <
|
|
|
|
RDCOST(x->rdmult, x->rddiv, sb32_rate, sb32_dist)) {
|
|
|
|
sb32_rate = r;
|
|
|
|
sb32_dist = d;
|
|
|
|
sb_partitioning[i] = BLOCK_SIZE_SB32X32;
|
|
|
|
}
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
|
|
|
|
2013-04-17 18:25:06 +02:00
|
|
|
// If we used 16x16 instead of 32x32 then skip 64x64 (if enabled).
|
|
|
|
if (cpi->sf.mb16_breakout && sb_partitioning[i] != BLOCK_SIZE_SB32X32) {
|
|
|
|
++sb64_skip;
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-04-17 18:25:06 +02:00
|
|
|
sb64_rate += sb32_rate;
|
|
|
|
sb64_dist += sb32_dist;
|
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
/* Encode SB using best computed mode(s) */
|
|
|
|
// FIXME(rbultje): there really shouldn't be any need to encode_mb/sb
|
|
|
|
// for each level that we go up, we can just keep tokens and recon
|
|
|
|
// pixels of the lower level; also, inverting SB/MB order (big->small
|
|
|
|
// instead of small->big) means we can use as threshold for small, which
|
|
|
|
// may enable breakouts if RD is not good enough (i.e. faster)
|
2013-04-17 18:25:06 +02:00
|
|
|
encode_sb(cpi, mb_row + y_idx, mb_col + x_idx, 0, tp,
|
|
|
|
sb_partitioning[i]);
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
memcpy(cm->above_context + mb_col, &a, sizeof(a));
|
|
|
|
memcpy(cm->left_context, &l, sizeof(l));
|
2013-04-17 18:25:06 +02:00
|
|
|
|
|
|
|
sb64_rate += x->partition_cost[partition_plane(BLOCK_SIZE_SB64X64)]
|
|
|
|
[PARTITION_SPLIT];
|
|
|
|
|
|
|
|
#if CONFIG_SBSEGMENT
|
|
|
|
// check 64x32
|
|
|
|
if (mb_col + 3 < cm->mb_cols && !(cm->mb_rows & 1)) {
|
|
|
|
int r, d;
|
|
|
|
|
|
|
|
xd->sb_index = 0;
|
|
|
|
pick_sb_modes(cpi, mb_row, mb_col,
|
|
|
|
tp, &r, &d, BLOCK_SIZE_SB64X32,
|
|
|
|
&x->sb64x32_context[xd->sb_index]);
|
|
|
|
if (mb_row + 2 != cm->mb_rows) {
|
|
|
|
int r2, d2;
|
|
|
|
|
|
|
|
update_state(cpi, &x->sb64x32_context[xd->sb_index],
|
|
|
|
BLOCK_SIZE_SB64X32, 0);
|
|
|
|
encode_superblock(cpi, tp,
|
|
|
|
0, mb_row, mb_col, BLOCK_SIZE_SB64X32);
|
|
|
|
xd->sb_index = 1;
|
|
|
|
pick_sb_modes(cpi, mb_row + 2, mb_col,
|
|
|
|
tp, &r2, &d2, BLOCK_SIZE_SB64X32,
|
|
|
|
&x->sb64x32_context[xd->sb_index]);
|
|
|
|
r += r2;
|
|
|
|
d += d2;
|
|
|
|
}
|
|
|
|
|
|
|
|
r += x->partition_cost[partition_plane(BLOCK_SIZE_SB64X64)]
|
|
|
|
[PARTITION_HORZ];
|
|
|
|
|
|
|
|
/* is this better than MB coding? */
|
|
|
|
if (RDCOST(x->rdmult, x->rddiv, r, d) <
|
|
|
|
RDCOST(x->rdmult, x->rddiv, sb64_rate, sb64_dist)) {
|
|
|
|
sb64_rate = r;
|
|
|
|
sb64_dist = d;
|
|
|
|
sb_partitioning[0] = BLOCK_SIZE_SB64X32;
|
|
|
|
}
|
|
|
|
|
|
|
|
vpx_memcpy(cm->left_context, l, sizeof(l));
|
|
|
|
vpx_memcpy(cm->above_context + mb_col, a, sizeof(a));
|
|
|
|
}
|
|
|
|
|
|
|
|
// check 32x64
|
|
|
|
if (mb_row + 3 < cm->mb_rows && !(cm->mb_cols & 1)) {
|
|
|
|
int r, d;
|
|
|
|
|
|
|
|
xd->sb_index = 0;
|
|
|
|
pick_sb_modes(cpi, mb_row, mb_col,
|
|
|
|
tp, &r, &d, BLOCK_SIZE_SB32X64,
|
|
|
|
&x->sb32x64_context[xd->sb_index]);
|
|
|
|
if (mb_col + 2 != cm->mb_cols) {
|
|
|
|
int r2, d2;
|
|
|
|
|
|
|
|
update_state(cpi, &x->sb32x64_context[xd->sb_index],
|
|
|
|
BLOCK_SIZE_SB32X64, 0);
|
|
|
|
encode_superblock(cpi, tp,
|
|
|
|
0, mb_row, mb_col, BLOCK_SIZE_SB32X64);
|
|
|
|
xd->sb_index = 1;
|
|
|
|
pick_sb_modes(cpi, mb_row, mb_col + 2,
|
|
|
|
tp, &r2, &d2, BLOCK_SIZE_SB32X64,
|
|
|
|
&x->sb32x64_context[xd->sb_index]);
|
|
|
|
r += r2;
|
|
|
|
d += d2;
|
|
|
|
}
|
|
|
|
|
|
|
|
r += x->partition_cost[partition_plane(BLOCK_SIZE_SB64X64)]
|
|
|
|
[PARTITION_VERT];
|
|
|
|
|
|
|
|
/* is this better than MB coding? */
|
|
|
|
if (RDCOST(x->rdmult, x->rddiv, r, d) <
|
|
|
|
RDCOST(x->rdmult, x->rddiv, sb64_rate, sb64_dist)) {
|
|
|
|
sb64_rate = r;
|
|
|
|
sb64_dist = d;
|
|
|
|
sb_partitioning[0] = BLOCK_SIZE_SB32X64;
|
|
|
|
}
|
|
|
|
|
|
|
|
vpx_memcpy(cm->left_context, l, sizeof(l));
|
|
|
|
vpx_memcpy(cm->above_context + mb_col, a, sizeof(a));
|
|
|
|
}
|
|
|
|
#endif
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-04-11 18:14:55 +02:00
|
|
|
if (!sb64_skip && !(mb_col + 3 >= cm->mb_cols ||
|
|
|
|
mb_row + 3 >= cm->mb_rows)) {
|
2013-04-17 18:25:06 +02:00
|
|
|
int r, d;
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2013-04-17 18:25:06 +02:00
|
|
|
pick_sb_modes(cpi, mb_row, mb_col, tp, &r, &d,
|
|
|
|
BLOCK_SIZE_SB64X64, &x->sb64_context);
|
|
|
|
r += x->partition_cost[partition_plane(BLOCK_SIZE_SB64X64)]
|
|
|
|
[PARTITION_NONE];
|
|
|
|
|
|
|
|
if (RDCOST(x->rdmult, x->rddiv, r, d) <
|
|
|
|
RDCOST(x->rdmult, x->rddiv, sb64_rate, sb64_dist)) {
|
|
|
|
sb64_rate = r;
|
|
|
|
sb64_dist = d;
|
|
|
|
sb_partitioning[0] = BLOCK_SIZE_SB64X64;
|
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
assert(tp_orig == *tp);
|
2013-04-17 18:25:06 +02:00
|
|
|
encode_sb64(cpi, mb_row, mb_col, tp, sb_partitioning);
|
2013-01-06 03:20:25 +01:00
|
|
|
assert(tp_orig < *tp);
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2011-09-30 17:45:16 +02:00
|
|
|
}
|
|
|
|
|
2012-10-31 01:53:32 +01:00
|
|
|
static void init_encode_frame_mb_context(VP9_COMP *cpi) {
|
2012-10-17 23:51:27 +02:00
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
2012-10-31 01:53:32 +01:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
2012-10-17 23:51:27 +02:00
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
x->act_zbin_adj = 0;
|
|
|
|
cpi->seg0_idx = 0;
|
|
|
|
vpx_memset(cpi->ref_pred_count, 0, sizeof(cpi->ref_pred_count));
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
xd->mode_info_stride = cm->mode_info_stride;
|
|
|
|
xd->frame_type = cm->frame_type;
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
xd->frames_since_golden = cm->frames_since_golden;
|
|
|
|
xd->frames_till_alt_ref_frame = cm->frames_till_alt_ref_frame;
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// reset intra mode contexts
|
|
|
|
if (cm->frame_type == KEY_FRAME)
|
2012-10-31 00:25:53 +01:00
|
|
|
vp9_init_mbmode_probs(cm);
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Copy data over into macro block data structures.
|
2013-01-06 03:20:25 +01:00
|
|
|
x->src = *cpi->Source;
|
2013-02-22 20:22:03 +01:00
|
|
|
xd->pre = cm->yv12_fb[cm->ref_frame_map[cpi->lst_fb_idx]];
|
2012-07-14 00:21:29 +02:00
|
|
|
xd->dst = cm->yv12_fb[cm->new_fb_idx];
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// set up frame for intra coded blocks
|
2012-10-31 00:25:53 +01:00
|
|
|
vp9_setup_intra_recon(&cm->yv12_fb[cm->new_fb_idx]);
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-10-30 20:58:42 +01:00
|
|
|
vp9_build_block_offsets(x);
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-10-31 00:25:53 +01:00
|
|
|
vp9_setup_block_dptrs(&x->e_mbd);
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-10-30 20:58:42 +01:00
|
|
|
vp9_setup_block_ptrs(x);
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
xd->mode_info_context->mbmi.mode = DC_PRED;
|
|
|
|
xd->mode_info_context->mbmi.uv_mode = DC_PRED;
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-10-31 22:40:53 +01:00
|
|
|
vp9_zero(cpi->count_mb_ref_frame_usage)
|
|
|
|
vp9_zero(cpi->bmode_count)
|
|
|
|
vp9_zero(cpi->ymode_count)
|
|
|
|
vp9_zero(cpi->i8x8_mode_count)
|
|
|
|
vp9_zero(cpi->y_uv_mode_count)
|
|
|
|
vp9_zero(cpi->sub_mv_ref_count)
|
|
|
|
vp9_zero(cpi->mbsplit_count)
|
|
|
|
vp9_zero(cpi->common.fc.mv_ref_ct)
|
|
|
|
vp9_zero(cpi->sb_ymode_count)
|
2013-04-16 09:18:02 +02:00
|
|
|
vp9_zero(cpi->partition_count);
|
|
|
|
|
2012-11-07 15:50:25 +01:00
|
|
|
#if CONFIG_COMP_INTERINTRA_PRED
|
|
|
|
vp9_zero(cpi->interintra_count);
|
|
|
|
vp9_zero(cpi->interintra_select_count);
|
|
|
|
#endif
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
vpx_memset(cm->above_context, 0,
|
|
|
|
sizeof(ENTROPY_CONTEXT_PLANES) * cm->mb_cols);
|
2011-06-08 17:00:59 +02:00
|
|
|
}
|
2013-02-20 16:27:35 +01:00
|
|
|
|
2013-02-13 23:22:15 +01:00
|
|
|
static void switch_lossless_mode(VP9_COMP *cpi, int lossless) {
|
|
|
|
if (lossless) {
|
2013-03-12 19:24:04 +01:00
|
|
|
cpi->mb.fwd_txm8x4 = vp9_short_walsh8x4;
|
|
|
|
cpi->mb.fwd_txm4x4 = vp9_short_walsh4x4;
|
|
|
|
cpi->mb.e_mbd.inv_txm4x4_1 = vp9_short_iwalsh4x4_1;
|
|
|
|
cpi->mb.e_mbd.inv_txm4x4 = vp9_short_iwalsh4x4;
|
2013-02-13 23:22:15 +01:00
|
|
|
cpi->mb.optimize = 0;
|
|
|
|
cpi->common.filter_level = 0;
|
2013-04-16 00:24:39 +02:00
|
|
|
cpi->zbin_mode_boost_enabled = 0;
|
2013-02-13 23:22:15 +01:00
|
|
|
cpi->common.txfm_mode = ONLY_4X4;
|
|
|
|
} else {
|
|
|
|
cpi->mb.fwd_txm8x4 = vp9_short_fdct8x4;
|
|
|
|
cpi->mb.fwd_txm4x4 = vp9_short_fdct4x4;
|
2013-03-12 19:24:04 +01:00
|
|
|
cpi->mb.e_mbd.inv_txm4x4_1 = vp9_short_idct4x4_1;
|
|
|
|
cpi->mb.e_mbd.inv_txm4x4 = vp9_short_idct4x4;
|
2013-02-13 23:22:15 +01:00
|
|
|
}
|
|
|
|
}
|
2013-02-20 16:27:35 +01:00
|
|
|
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-10-31 01:53:32 +01:00
|
|
|
static void encode_frame_internal(VP9_COMP *cpi) {
|
2012-07-14 00:21:29 +02:00
|
|
|
int mb_row;
|
2012-10-17 23:51:27 +02:00
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
2012-10-31 01:53:32 +01:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
2012-10-17 23:51:27 +02:00
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
2012-07-14 00:21:29 +02:00
|
|
|
int totalrate;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-04-15 18:31:27 +02:00
|
|
|
// fprintf(stderr, "encode_frame_internal frame %d (%d) type %d\n",
|
|
|
|
// cpi->common.current_video_frame, cpi->common.show_frame,
|
|
|
|
// cm->frame_type);
|
2012-09-10 07:42:35 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Compute a modified set of reference frame probabilities to use when
|
|
|
|
// prediction fails. These are based on the current general estimates for
|
|
|
|
// this frame which may be updated with each iteration of the recode loop.
|
2012-10-29 14:44:18 +01:00
|
|
|
vp9_compute_mod_refprobs(cm);
|
2011-09-30 17:45:16 +02:00
|
|
|
|
|
|
|
// debug output
|
2011-10-07 17:58:28 +02:00
|
|
|
#if DBG_PRNT_SEGMAP
|
2012-07-14 00:21:29 +02:00
|
|
|
{
|
|
|
|
FILE *statsfile;
|
|
|
|
statsfile = fopen("segmap2.stt", "a");
|
|
|
|
fprintf(statsfile, "\n");
|
|
|
|
fclose(statsfile);
|
|
|
|
}
|
2011-09-30 17:45:16 +02:00
|
|
|
#endif
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
totalrate = 0;
|
|
|
|
|
|
|
|
// Reset frame count of inter 0,0 motion vector usage.
|
|
|
|
cpi->inter_zz_count = 0;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
cpi->skip_true_count[0] = cpi->skip_true_count[1] = cpi->skip_true_count[2] = 0;
|
|
|
|
cpi->skip_false_count[0] = cpi->skip_false_count[1] = cpi->skip_false_count[2] = 0;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-10-31 22:40:53 +01:00
|
|
|
vp9_zero(cpi->switchable_interp_count);
|
2012-12-20 23:56:19 +01:00
|
|
|
vp9_zero(cpi->best_switchable_interp_count);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
xd->mode_info_context = cm->mi;
|
|
|
|
xd->prev_mode_info_context = cm->prev_mi;
|
2011-11-16 01:16:30 +01:00
|
|
|
|
2012-10-31 22:40:53 +01:00
|
|
|
vp9_zero(cpi->NMVcount);
|
2012-12-08 01:09:59 +01:00
|
|
|
vp9_zero(cpi->coef_counts_4x4);
|
2012-10-31 22:40:53 +01:00
|
|
|
vp9_zero(cpi->coef_counts_8x8);
|
|
|
|
vp9_zero(cpi->coef_counts_16x16);
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
vp9_zero(cpi->coef_counts_32x32);
|
2013-03-27 00:46:09 +01:00
|
|
|
vp9_zero(cm->fc.eob_branch_counts);
|
2013-02-20 19:16:24 +01:00
|
|
|
#if CONFIG_CODE_NONZEROCOUNT
|
|
|
|
vp9_zero(cm->fc.nzc_counts_4x4);
|
|
|
|
vp9_zero(cm->fc.nzc_counts_8x8);
|
|
|
|
vp9_zero(cm->fc.nzc_counts_16x16);
|
|
|
|
vp9_zero(cm->fc.nzc_counts_32x32);
|
2013-03-08 05:56:34 +01:00
|
|
|
vp9_zero(cm->fc.nzc_pcat_counts);
|
2013-02-20 19:16:24 +01:00
|
|
|
#endif
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-02-13 23:22:15 +01:00
|
|
|
cpi->mb.e_mbd.lossless = (cm->base_qindex == 0 &&
|
2013-04-17 00:05:52 +02:00
|
|
|
cm->y_dc_delta_q == 0 &&
|
|
|
|
cm->uv_dc_delta_q == 0 &&
|
|
|
|
cm->uv_ac_delta_q == 0);
|
2013-02-13 23:22:15 +01:00
|
|
|
switch_lossless_mode(cpi, cpi->mb.e_mbd.lossless);
|
2013-02-20 16:27:35 +01:00
|
|
|
|
2012-10-30 22:25:33 +01:00
|
|
|
vp9_frame_init_quantizer(cpi);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-04-17 00:05:52 +02:00
|
|
|
vp9_initialize_rd_consts(cpi, cm->base_qindex + cm->y_dc_delta_q);
|
2012-10-30 22:25:33 +01:00
|
|
|
vp9_initialize_me_consts(cpi, cm->base_qindex);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
if (cpi->oxcf.tuning == VP8_TUNE_SSIM) {
|
|
|
|
// Initialize encode frame context.
|
2011-06-08 17:00:59 +02:00
|
|
|
init_encode_frame_mb_context(cpi);
|
2012-02-10 01:11:00 +01:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// Build a frame level activity map
|
|
|
|
build_activity_map(cpi);
|
|
|
|
}
|
2011-06-08 17:00:59 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
// re-initencode frame context.
|
|
|
|
init_encode_frame_mb_context(cpi);
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-08-10 03:25:29 +02:00
|
|
|
vpx_memset(cpi->rd_comp_pred_diff, 0, sizeof(cpi->rd_comp_pred_diff));
|
2012-07-14 00:21:29 +02:00
|
|
|
vpx_memset(cpi->single_pred_count, 0, sizeof(cpi->single_pred_count));
|
|
|
|
vpx_memset(cpi->comp_pred_count, 0, sizeof(cpi->comp_pred_count));
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
vpx_memset(cpi->txfm_count_32x32p, 0, sizeof(cpi->txfm_count_32x32p));
|
|
|
|
vpx_memset(cpi->txfm_count_16x16p, 0, sizeof(cpi->txfm_count_16x16p));
|
2012-10-11 02:18:22 +02:00
|
|
|
vpx_memset(cpi->txfm_count_8x8p, 0, sizeof(cpi->txfm_count_8x8p));
|
2012-10-09 18:18:21 +02:00
|
|
|
vpx_memset(cpi->rd_tx_select_diff, 0, sizeof(cpi->rd_tx_select_diff));
|
2012-07-14 00:21:29 +02:00
|
|
|
{
|
|
|
|
struct vpx_usec_timer emr_timer;
|
|
|
|
vpx_usec_timer_start(&emr_timer);
|
2012-04-07 01:38:34 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
{
|
[WIP] Add column-based tiling.
This patch adds column-based tiling. The idea is to make each tile
independently decodable (after reading the common frame header) and
also independendly encodable (minus within-frame cost adjustments in
the RD loop) to speed-up hardware & software en/decoders if they used
multi-threading. Column-based tiling has the added advantage (over
other tiling methods) that it minimizes realtime use-case latency,
since all threads can start encoding data as soon as the first SB-row
worth of data is available to the encoder.
There is some test code that does random tile ordering in the decoder,
to confirm that each tile is indeed independently decodable from other
tiles in the same frame. At tile edges, all contexts assume default
values (i.e. 0, 0 motion vector, no coefficients, DC intra4x4 mode),
and motion vector search and ordering do not cross tiles in the same
frame.
t log
Tile independence is not maintained between frames ATM, i.e. tile 0 of
frame 1 is free to use motion vectors that point into any tile of frame
0. We support 1 (i.e. no tiling), 2 or 4 column-tiles.
The loopfilter crosses tile boundaries. I discussed this briefly with Aki
and he says that's OK. An in-loop loopfilter would need to do some sync
between tile threads, but that shouldn't be a big issue.
Resuls: with tiling disabled, we go up slightly because of improved edge
use in the intra4x4 prediction. With 2 tiles, we lose about ~1% on derf,
~0.35% on HD and ~0.55% on STD/HD. With 4 tiles, we lose another ~1.5%
on derf ~0.77% on HD and ~0.85% on STD/HD. Most of this loss is
concentrated in the low-bitrate end of clips, and most of it is because
of the loss of edges at tile boundaries and the resulting loss of intra
predictors.
TODO:
- more tiles (perhaps allow row-based tiling also, and max. 8 tiles)?
- maybe optionally (for EC purposes), motion vectors themselves
should not cross tile edges, or we should emulate such borders as
if they were off-frame, to limit error propagation to within one
tile only. This doesn't have to be the default behaviour but could
be an optional bitstream flag.
Change-Id: I5951c3a0742a767b20bc9fb5af685d9892c2c96f
2013-02-01 18:35:28 +01:00
|
|
|
// Take tiles into account and give start/end MB
|
2013-02-20 19:16:24 +01:00
|
|
|
int tile_col, tile_row;
|
2013-02-08 20:33:11 +01:00
|
|
|
TOKENEXTRA *tp = cpi->tok;
|
2013-02-28 02:09:12 +01:00
|
|
|
|
2013-02-20 19:16:24 +01:00
|
|
|
for (tile_row = 0; tile_row < cm->tile_rows; tile_row++) {
|
|
|
|
vp9_get_tile_row_offsets(cm, tile_row);
|
|
|
|
|
|
|
|
for (tile_col = 0; tile_col < cm->tile_columns; tile_col++) {
|
|
|
|
TOKENEXTRA *tp_old = tp;
|
|
|
|
|
|
|
|
// For each row of SBs in the frame
|
|
|
|
vp9_get_tile_col_offsets(cm, tile_col);
|
|
|
|
for (mb_row = cm->cur_tile_mb_row_start;
|
|
|
|
mb_row < cm->cur_tile_mb_row_end; mb_row += 4) {
|
|
|
|
encode_sb_row(cpi, mb_row, &tp, &totalrate);
|
|
|
|
}
|
|
|
|
cpi->tok_count[tile_col] = (unsigned int)(tp - tp_old);
|
[WIP] Add column-based tiling.
This patch adds column-based tiling. The idea is to make each tile
independently decodable (after reading the common frame header) and
also independendly encodable (minus within-frame cost adjustments in
the RD loop) to speed-up hardware & software en/decoders if they used
multi-threading. Column-based tiling has the added advantage (over
other tiling methods) that it minimizes realtime use-case latency,
since all threads can start encoding data as soon as the first SB-row
worth of data is available to the encoder.
There is some test code that does random tile ordering in the decoder,
to confirm that each tile is indeed independently decodable from other
tiles in the same frame. At tile edges, all contexts assume default
values (i.e. 0, 0 motion vector, no coefficients, DC intra4x4 mode),
and motion vector search and ordering do not cross tiles in the same
frame.
t log
Tile independence is not maintained between frames ATM, i.e. tile 0 of
frame 1 is free to use motion vectors that point into any tile of frame
0. We support 1 (i.e. no tiling), 2 or 4 column-tiles.
The loopfilter crosses tile boundaries. I discussed this briefly with Aki
and he says that's OK. An in-loop loopfilter would need to do some sync
between tile threads, but that shouldn't be a big issue.
Resuls: with tiling disabled, we go up slightly because of improved edge
use in the intra4x4 prediction. With 2 tiles, we lose about ~1% on derf,
~0.35% on HD and ~0.55% on STD/HD. With 4 tiles, we lose another ~1.5%
on derf ~0.77% on HD and ~0.85% on STD/HD. Most of this loss is
concentrated in the low-bitrate end of clips, and most of it is because
of the loss of edges at tile boundaries and the resulting loss of intra
predictors.
TODO:
- more tiles (perhaps allow row-based tiling also, and max. 8 tiles)?
- maybe optionally (for EC purposes), motion vectors themselves
should not cross tile edges, or we should emulate such borders as
if they were off-frame, to limit error propagation to within one
tile only. This doesn't have to be the default behaviour but could
be an optional bitstream flag.
Change-Id: I5951c3a0742a767b20bc9fb5af685d9892c2c96f
2013-02-01 18:35:28 +01:00
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
vpx_usec_timer_mark(&emr_timer);
|
|
|
|
cpi->time_encode_mb_row += vpx_usec_timer_elapsed(&emr_timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 256 rate units to the bit,
|
|
|
|
// projected_frame_size in units of BYTES
|
|
|
|
cpi->projected_frame_size = totalrate >> 8;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
|
|
|
#if 0
|
2012-07-14 00:21:29 +02:00
|
|
|
// Keep record of the total distortion this time around for future use
|
|
|
|
cpi->last_frame_distortion = cpi->frame_distortion;
|
2010-05-18 17:58:33 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
Dual 16x16 inter prediction.
This patch introduces the concept of dual inter16x16 prediction. A
16x16 inter-predicted macroblock can use 2 references instead of 1,
where both references use the same mvmode (new, near/est, zero). In the
case of newmv, this means that two MVs are coded instead of one. The
frame can be encoded in 3 ways: all MBs single-prediction, all MBs dual
prediction, or per-MB single/dual prediction selection ("hybrid"), in
which case a single bit is coded per-MB to indicate whether the MB uses
single or dual inter prediction.
In the future, we can (maybe?) get further gains by mixing this with
Adrian's 32x32 work, per-segment dual prediction settings, or adding
support for dual splitmv/8x8mv inter prediction.
Gain (on derf-set, CQ mode) is ~2.8% (SSIM) or ~3.6% (glb PSNR). Most
gain is at medium/high bitrates, but there's minor gains at low bitrates
also. Output was confirmed to match between encoder and decoder.
Note for optimization people: this patch introduces a 2nd version of
16x16/8x8 sixtap/bilin functions, which does an avg instead of a
store. They may want to look and make sure this is implemented to
their satisfaction so we can optimize it best in the future.
Change-ID: I59dc84b07cbb3ccf073ac0f756d03d294cb19281
2011-12-06 20:53:02 +01:00
|
|
|
|
2012-10-31 01:53:32 +01:00
|
|
|
static int check_dual_ref_flags(VP9_COMP *cpi) {
|
2012-07-14 00:21:29 +02:00
|
|
|
MACROBLOCKD *xd = &cpi->mb.e_mbd;
|
|
|
|
int ref_flags = cpi->ref_frame_flags;
|
|
|
|
|
2012-10-30 06:15:27 +01:00
|
|
|
if (vp9_segfeature_active(xd, 1, SEG_LVL_REF_FRAME)) {
|
2012-10-31 22:40:53 +01:00
|
|
|
if ((ref_flags & (VP9_LAST_FLAG | VP9_GOLD_FLAG)) == (VP9_LAST_FLAG | VP9_GOLD_FLAG) &&
|
2012-10-30 06:15:27 +01:00
|
|
|
vp9_check_segref(xd, 1, LAST_FRAME))
|
2012-07-14 00:21:29 +02:00
|
|
|
return 1;
|
2012-10-31 22:40:53 +01:00
|
|
|
if ((ref_flags & (VP9_GOLD_FLAG | VP9_ALT_FLAG)) == (VP9_GOLD_FLAG | VP9_ALT_FLAG) &&
|
2012-10-30 06:15:27 +01:00
|
|
|
vp9_check_segref(xd, 1, GOLDEN_FRAME))
|
2012-07-14 00:21:29 +02:00
|
|
|
return 1;
|
2012-10-31 22:40:53 +01:00
|
|
|
if ((ref_flags & (VP9_ALT_FLAG | VP9_LAST_FLAG)) == (VP9_ALT_FLAG | VP9_LAST_FLAG) &&
|
2012-10-30 06:15:27 +01:00
|
|
|
vp9_check_segref(xd, 1, ALTREF_FRAME))
|
2012-07-14 00:21:29 +02:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
} else {
|
2012-10-31 22:40:53 +01:00
|
|
|
return (!!(ref_flags & VP9_GOLD_FLAG) +
|
|
|
|
!!(ref_flags & VP9_LAST_FLAG) +
|
|
|
|
!!(ref_flags & VP9_ALT_FLAG)) >= 2;
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2012-03-22 18:03:14 +01:00
|
|
|
}
|
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
static int get_skip_flag(MODE_INFO *mi, int mis, int ymbs, int xmbs) {
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
for (y = 0; y < ymbs; y++) {
|
|
|
|
for (x = 0; x < xmbs; x++) {
|
|
|
|
if (!mi[y * mis + x].mbmi.mb_skip_coeff)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_txfm_flag(MODE_INFO *mi, int mis, int ymbs, int xmbs,
|
|
|
|
TX_SIZE txfm_size) {
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
for (y = 0; y < ymbs; y++) {
|
2013-02-28 22:18:02 +01:00
|
|
|
for (x = 0; x < xmbs; x++)
|
2013-01-06 03:20:25 +01:00
|
|
|
mi[y * mis + x].mbmi.txfm_size = txfm_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-10 06:28:27 +02:00
|
|
|
static void reset_skip_txfm_size_sb(VP9_COMP *cpi, MODE_INFO *mi,
|
|
|
|
int mis, TX_SIZE txfm_max,
|
|
|
|
int mb_rows_left, int mb_cols_left,
|
|
|
|
BLOCK_SIZE_TYPE bsize) {
|
2013-01-06 03:20:25 +01:00
|
|
|
MB_MODE_INFO *const mbmi = &mi->mbmi;
|
|
|
|
|
|
|
|
if (mbmi->txfm_size > txfm_max) {
|
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
|
|
const int segment_id = mbmi->segment_id;
|
2013-04-10 06:28:27 +02:00
|
|
|
const int bh = 1 << mb_height_log2(bsize), bw = 1 << mb_width_log2(bsize);
|
|
|
|
const int ymbs = MIN(bh, mb_rows_left);
|
|
|
|
const int xmbs = MIN(bw, mb_cols_left);
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
xd->mode_info_context = mi;
|
2013-04-09 19:54:19 +02:00
|
|
|
assert(vp9_segfeature_active(xd, segment_id, SEG_LVL_SKIP) ||
|
|
|
|
get_skip_flag(mi, mis, ymbs, xmbs));
|
2013-01-06 03:20:25 +01:00
|
|
|
set_txfm_flag(mi, mis, ymbs, xmbs, txfm_max);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void reset_skip_txfm_size(VP9_COMP *cpi, TX_SIZE txfm_max) {
|
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
|
|
|
int mb_row, mb_col;
|
|
|
|
const int mis = cm->mode_info_stride;
|
|
|
|
MODE_INFO *mi, *mi_ptr = cm->mi;
|
2012-10-12 03:19:20 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
for (mb_row = 0; mb_row < cm->mb_rows; mb_row += 4, mi_ptr += 4 * mis) {
|
2012-10-12 03:19:20 +02:00
|
|
|
mi = mi_ptr;
|
2013-01-06 03:20:25 +01:00
|
|
|
for (mb_col = 0; mb_col < cm->mb_cols; mb_col += 4, mi += 4) {
|
|
|
|
if (mi->mbmi.sb_type == BLOCK_SIZE_SB64X64) {
|
2013-04-10 06:28:27 +02:00
|
|
|
reset_skip_txfm_size_sb(cpi, mi, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row, cm->mb_cols - mb_col,
|
|
|
|
BLOCK_SIZE_SB64X64);
|
2013-04-17 18:25:06 +02:00
|
|
|
#if CONFIG_SBSEGMENT
|
|
|
|
} else if (mi->mbmi.sb_type == BLOCK_SIZE_SB64X32) {
|
|
|
|
reset_skip_txfm_size_sb(cpi, mi, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row, cm->mb_cols - mb_col,
|
|
|
|
BLOCK_SIZE_SB64X32);
|
|
|
|
if (mb_row + 2 != cm->mb_rows)
|
|
|
|
reset_skip_txfm_size_sb(cpi, mi + 2 * mis, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row - 2,
|
|
|
|
cm->mb_cols - mb_col,
|
|
|
|
BLOCK_SIZE_SB64X32);
|
|
|
|
} else if (mi->mbmi.sb_type == BLOCK_SIZE_SB32X64) {
|
|
|
|
reset_skip_txfm_size_sb(cpi, mi, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row, cm->mb_cols - mb_col,
|
|
|
|
BLOCK_SIZE_SB32X64);
|
|
|
|
if (mb_col + 2 != cm->mb_cols)
|
|
|
|
reset_skip_txfm_size_sb(cpi, mi + 2, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row,
|
|
|
|
cm->mb_cols - mb_col - 2,
|
|
|
|
BLOCK_SIZE_SB32X64);
|
|
|
|
#endif
|
2013-01-10 02:21:28 +01:00
|
|
|
} else {
|
2013-01-06 03:20:25 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
const int x_idx_sb = (i & 1) << 1, y_idx_sb = i & 2;
|
|
|
|
MODE_INFO *sb_mi = mi + y_idx_sb * mis + x_idx_sb;
|
|
|
|
|
|
|
|
if (mb_row + y_idx_sb >= cm->mb_rows ||
|
|
|
|
mb_col + x_idx_sb >= cm->mb_cols)
|
|
|
|
continue;
|
|
|
|
|
2013-04-17 18:25:06 +02:00
|
|
|
if (sb_mi->mbmi.sb_type == BLOCK_SIZE_SB32X32) {
|
2013-04-10 06:28:27 +02:00
|
|
|
reset_skip_txfm_size_sb(cpi, sb_mi, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row - y_idx_sb,
|
|
|
|
cm->mb_cols - mb_col - x_idx_sb,
|
|
|
|
BLOCK_SIZE_SB32X32);
|
2013-04-17 18:25:06 +02:00
|
|
|
#if CONFIG_SBSEGMENT
|
|
|
|
} else if (sb_mi->mbmi.sb_type == BLOCK_SIZE_SB32X16) {
|
|
|
|
reset_skip_txfm_size_sb(cpi, sb_mi, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row - y_idx_sb,
|
|
|
|
cm->mb_cols - mb_col - x_idx_sb,
|
|
|
|
BLOCK_SIZE_SB32X16);
|
|
|
|
if (mb_row + y_idx_sb + 1 != cm->mb_rows)
|
|
|
|
reset_skip_txfm_size_sb(cpi, sb_mi + mis, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row - y_idx_sb - 1,
|
|
|
|
cm->mb_cols - mb_col - x_idx_sb,
|
|
|
|
BLOCK_SIZE_SB32X16);
|
|
|
|
} else if (sb_mi->mbmi.sb_type == BLOCK_SIZE_SB16X32) {
|
|
|
|
reset_skip_txfm_size_sb(cpi, sb_mi, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row - y_idx_sb,
|
|
|
|
cm->mb_cols - mb_col - x_idx_sb,
|
|
|
|
BLOCK_SIZE_SB16X32);
|
|
|
|
if (mb_col + x_idx_sb + 1 != cm->mb_cols)
|
|
|
|
reset_skip_txfm_size_sb(cpi, sb_mi + 1, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row - y_idx_sb,
|
|
|
|
cm->mb_cols - mb_col - x_idx_sb - 1,
|
|
|
|
BLOCK_SIZE_SB16X32);
|
|
|
|
#endif
|
2013-01-08 19:29:22 +01:00
|
|
|
} else {
|
2013-01-06 03:20:25 +01:00
|
|
|
int m;
|
|
|
|
|
|
|
|
for (m = 0; m < 4; m++) {
|
|
|
|
const int x_idx = x_idx_sb + (m & 1), y_idx = y_idx_sb + (m >> 1);
|
|
|
|
MODE_INFO *mb_mi;
|
|
|
|
|
|
|
|
if (mb_col + x_idx >= cm->mb_cols ||
|
|
|
|
mb_row + y_idx >= cm->mb_rows)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
mb_mi = mi + y_idx * mis + x_idx;
|
|
|
|
assert(mb_mi->mbmi.sb_type == BLOCK_SIZE_MB16X16);
|
2013-04-10 06:28:27 +02:00
|
|
|
reset_skip_txfm_size_sb(cpi, mb_mi, mis, txfm_max,
|
|
|
|
cm->mb_rows - mb_row - y_idx,
|
|
|
|
cm->mb_cols - mb_col - x_idx,
|
|
|
|
BLOCK_SIZE_MB16X16);
|
2012-11-08 20:03:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-12 03:19:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-31 01:53:32 +01:00
|
|
|
void vp9_encode_frame(VP9_COMP *cpi) {
|
2012-07-14 00:21:29 +02:00
|
|
|
if (cpi->sf.RD) {
|
2012-08-10 03:25:29 +02:00
|
|
|
int i, frame_type, pred_type;
|
2012-10-09 18:18:21 +02:00
|
|
|
TXFM_MODE txfm_type;
|
2012-07-14 00:21:29 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This code does a single RD pass over the whole frame assuming
|
|
|
|
* either compound, single or hybrid prediction as per whatever has
|
|
|
|
* worked best for that type of frame in the past.
|
|
|
|
* It also predicts whether another coding mode would have worked
|
|
|
|
* better that this coding mode. If that is the case, it remembers
|
2012-10-09 18:18:21 +02:00
|
|
|
* that for subsequent frames.
|
|
|
|
* It does the same analysis for transform size selection also.
|
2012-07-14 00:21:29 +02:00
|
|
|
*/
|
|
|
|
if (cpi->common.frame_type == KEY_FRAME)
|
|
|
|
frame_type = 0;
|
2013-01-15 22:49:44 +01:00
|
|
|
else if (cpi->is_src_frame_alt_ref && cpi->refresh_golden_frame)
|
2012-07-14 00:21:29 +02:00
|
|
|
frame_type = 3;
|
2013-01-15 22:49:44 +01:00
|
|
|
else if (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)
|
2012-07-14 00:21:29 +02:00
|
|
|
frame_type = 1;
|
Dual 16x16 inter prediction.
This patch introduces the concept of dual inter16x16 prediction. A
16x16 inter-predicted macroblock can use 2 references instead of 1,
where both references use the same mvmode (new, near/est, zero). In the
case of newmv, this means that two MVs are coded instead of one. The
frame can be encoded in 3 ways: all MBs single-prediction, all MBs dual
prediction, or per-MB single/dual prediction selection ("hybrid"), in
which case a single bit is coded per-MB to indicate whether the MB uses
single or dual inter prediction.
In the future, we can (maybe?) get further gains by mixing this with
Adrian's 32x32 work, per-segment dual prediction settings, or adding
support for dual splitmv/8x8mv inter prediction.
Gain (on derf-set, CQ mode) is ~2.8% (SSIM) or ~3.6% (glb PSNR). Most
gain is at medium/high bitrates, but there's minor gains at low bitrates
also. Output was confirmed to match between encoder and decoder.
Note for optimization people: this patch introduces a 2nd version of
16x16/8x8 sixtap/bilin functions, which does an avg instead of a
store. They may want to look and make sure this is implemented to
their satisfaction so we can optimize it best in the future.
Change-ID: I59dc84b07cbb3ccf073ac0f756d03d294cb19281
2011-12-06 20:53:02 +01:00
|
|
|
else
|
2012-07-14 00:21:29 +02:00
|
|
|
frame_type = 2;
|
|
|
|
|
2012-10-09 18:18:21 +02:00
|
|
|
/* prediction (compound, single or hybrid) mode selection */
|
2012-07-14 00:21:29 +02:00
|
|
|
if (frame_type == 3)
|
|
|
|
pred_type = SINGLE_PREDICTION_ONLY;
|
|
|
|
else if (cpi->rd_prediction_type_threshes[frame_type][1] >
|
2012-07-17 01:46:46 +02:00
|
|
|
cpi->rd_prediction_type_threshes[frame_type][0] &&
|
2012-07-14 00:21:29 +02:00
|
|
|
cpi->rd_prediction_type_threshes[frame_type][1] >
|
2012-07-17 01:46:46 +02:00
|
|
|
cpi->rd_prediction_type_threshes[frame_type][2] &&
|
|
|
|
check_dual_ref_flags(cpi) && cpi->static_mb_pct == 100)
|
2012-07-14 00:21:29 +02:00
|
|
|
pred_type = COMP_PREDICTION_ONLY;
|
|
|
|
else if (cpi->rd_prediction_type_threshes[frame_type][0] >
|
2012-07-17 01:46:46 +02:00
|
|
|
cpi->rd_prediction_type_threshes[frame_type][2])
|
2012-07-14 00:21:29 +02:00
|
|
|
pred_type = SINGLE_PREDICTION_ONLY;
|
|
|
|
else
|
|
|
|
pred_type = HYBRID_PREDICTION;
|
|
|
|
|
2012-10-09 18:18:21 +02:00
|
|
|
/* transform size (4x4, 8x8, 16x16 or select-per-mb) selection */
|
2013-02-20 16:27:35 +01:00
|
|
|
|
2013-02-12 00:58:22 +01:00
|
|
|
cpi->mb.e_mbd.lossless = 0;
|
2012-10-09 18:18:21 +02:00
|
|
|
if (cpi->oxcf.lossless) {
|
|
|
|
txfm_type = ONLY_4X4;
|
2013-02-12 00:58:22 +01:00
|
|
|
cpi->mb.e_mbd.lossless = 1;
|
2012-10-09 18:18:21 +02:00
|
|
|
} else
|
|
|
|
#if 0
|
2013-03-07 19:45:25 +01:00
|
|
|
/* FIXME (rbultje): this code is disabled until we support cost updates
|
|
|
|
* while a frame is being encoded; the problem is that each time we
|
|
|
|
* "revert" to 4x4 only (or even 8x8 only), the coefficient probabilities
|
|
|
|
* for 16x16 (and 8x8) start lagging behind, thus leading to them lagging
|
|
|
|
* further behind and not being chosen for subsequent frames either. This
|
|
|
|
* is essentially a local minimum problem that we can probably fix by
|
|
|
|
* estimating real costs more closely within a frame, perhaps by re-
|
|
|
|
* calculating costs on-the-fly as frame encoding progresses. */
|
2012-10-09 18:18:21 +02:00
|
|
|
if (cpi->rd_tx_select_threshes[frame_type][TX_MODE_SELECT] >
|
|
|
|
cpi->rd_tx_select_threshes[frame_type][ONLY_4X4] &&
|
|
|
|
cpi->rd_tx_select_threshes[frame_type][TX_MODE_SELECT] >
|
|
|
|
cpi->rd_tx_select_threshes[frame_type][ALLOW_16X16] &&
|
|
|
|
cpi->rd_tx_select_threshes[frame_type][TX_MODE_SELECT] >
|
|
|
|
cpi->rd_tx_select_threshes[frame_type][ALLOW_8X8]) {
|
|
|
|
txfm_type = TX_MODE_SELECT;
|
|
|
|
} else if (cpi->rd_tx_select_threshes[frame_type][ONLY_4X4] >
|
|
|
|
cpi->rd_tx_select_threshes[frame_type][ALLOW_8X8]
|
|
|
|
&& cpi->rd_tx_select_threshes[frame_type][ONLY_4X4] >
|
|
|
|
cpi->rd_tx_select_threshes[frame_type][ALLOW_16X16]
|
|
|
|
) {
|
|
|
|
txfm_type = ONLY_4X4;
|
|
|
|
} else if (cpi->rd_tx_select_threshes[frame_type][ALLOW_16X16] >=
|
|
|
|
cpi->rd_tx_select_threshes[frame_type][ALLOW_8X8]) {
|
|
|
|
txfm_type = ALLOW_16X16;
|
|
|
|
} else
|
|
|
|
txfm_type = ALLOW_8X8;
|
|
|
|
#else
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
txfm_type = cpi->rd_tx_select_threshes[frame_type][ALLOW_32X32] >=
|
2013-01-10 17:23:59 +01:00
|
|
|
cpi->rd_tx_select_threshes[frame_type][TX_MODE_SELECT] ?
|
|
|
|
ALLOW_32X32 : TX_MODE_SELECT;
|
2012-10-09 18:18:21 +02:00
|
|
|
#endif
|
|
|
|
cpi->common.txfm_mode = txfm_type;
|
|
|
|
if (txfm_type != TX_MODE_SELECT) {
|
|
|
|
cpi->common.prob_tx[0] = 128;
|
|
|
|
cpi->common.prob_tx[1] = 128;
|
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
cpi->common.comp_pred_mode = pred_type;
|
|
|
|
encode_frame_internal(cpi);
|
|
|
|
|
2012-08-10 03:25:29 +02:00
|
|
|
for (i = 0; i < NB_PREDICTION_TYPES; ++i) {
|
2012-11-05 23:22:59 +01:00
|
|
|
const int diff = (int)(cpi->rd_comp_pred_diff[i] / cpi->common.MBs);
|
2012-08-10 03:25:29 +02:00
|
|
|
cpi->rd_prediction_type_threshes[frame_type][i] += diff;
|
|
|
|
cpi->rd_prediction_type_threshes[frame_type][i] >>= 1;
|
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2012-10-09 18:18:21 +02:00
|
|
|
for (i = 0; i < NB_TXFM_MODES; ++i) {
|
|
|
|
int64_t pd = cpi->rd_tx_select_diff[i];
|
|
|
|
int diff;
|
|
|
|
if (i == TX_MODE_SELECT)
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
pd -= RDCOST(cpi->mb.rdmult, cpi->mb.rddiv,
|
|
|
|
2048 * (TX_SIZE_MAX_SB - 1), 0);
|
2012-11-05 23:22:59 +01:00
|
|
|
diff = (int)(pd / cpi->common.MBs);
|
2012-10-09 18:18:21 +02:00
|
|
|
cpi->rd_tx_select_threshes[frame_type][i] += diff;
|
|
|
|
cpi->rd_tx_select_threshes[frame_type][i] /= 2;
|
|
|
|
}
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
if (cpi->common.comp_pred_mode == HYBRID_PREDICTION) {
|
|
|
|
int single_count_zero = 0;
|
|
|
|
int comp_count_zero = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < COMP_PRED_CONTEXTS; i++) {
|
|
|
|
single_count_zero += cpi->single_pred_count[i];
|
|
|
|
comp_count_zero += cpi->comp_pred_count[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (comp_count_zero == 0) {
|
|
|
|
cpi->common.comp_pred_mode = SINGLE_PREDICTION_ONLY;
|
|
|
|
} else if (single_count_zero == 0) {
|
|
|
|
cpi->common.comp_pred_mode = COMP_PREDICTION_ONLY;
|
|
|
|
}
|
Dual 16x16 inter prediction.
This patch introduces the concept of dual inter16x16 prediction. A
16x16 inter-predicted macroblock can use 2 references instead of 1,
where both references use the same mvmode (new, near/est, zero). In the
case of newmv, this means that two MVs are coded instead of one. The
frame can be encoded in 3 ways: all MBs single-prediction, all MBs dual
prediction, or per-MB single/dual prediction selection ("hybrid"), in
which case a single bit is coded per-MB to indicate whether the MB uses
single or dual inter prediction.
In the future, we can (maybe?) get further gains by mixing this with
Adrian's 32x32 work, per-segment dual prediction settings, or adding
support for dual splitmv/8x8mv inter prediction.
Gain (on derf-set, CQ mode) is ~2.8% (SSIM) or ~3.6% (glb PSNR). Most
gain is at medium/high bitrates, but there's minor gains at low bitrates
also. Output was confirmed to match between encoder and decoder.
Note for optimization people: this patch introduces a 2nd version of
16x16/8x8 sixtap/bilin functions, which does an avg instead of a
store. They may want to look and make sure this is implemented to
their satisfaction so we can optimize it best in the future.
Change-ID: I59dc84b07cbb3ccf073ac0f756d03d294cb19281
2011-12-06 20:53:02 +01:00
|
|
|
}
|
2012-10-09 18:18:21 +02:00
|
|
|
|
|
|
|
if (cpi->common.txfm_mode == TX_MODE_SELECT) {
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
const int count4x4 = cpi->txfm_count_16x16p[TX_4X4] +
|
|
|
|
cpi->txfm_count_32x32p[TX_4X4] +
|
|
|
|
cpi->txfm_count_8x8p[TX_4X4];
|
|
|
|
const int count8x8_lp = cpi->txfm_count_32x32p[TX_8X8] +
|
|
|
|
cpi->txfm_count_16x16p[TX_8X8];
|
2012-10-11 02:18:22 +02:00
|
|
|
const int count8x8_8x8p = cpi->txfm_count_8x8p[TX_8X8];
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
const int count16x16_16x16p = cpi->txfm_count_16x16p[TX_16X16];
|
|
|
|
const int count16x16_lp = cpi->txfm_count_32x32p[TX_16X16];
|
|
|
|
const int count32x32 = cpi->txfm_count_32x32p[TX_32X32];
|
2012-10-09 18:18:21 +02:00
|
|
|
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
if (count4x4 == 0 && count16x16_lp == 0 && count16x16_16x16p == 0 &&
|
|
|
|
count32x32 == 0) {
|
2012-10-09 18:18:21 +02:00
|
|
|
cpi->common.txfm_mode = ALLOW_8X8;
|
2012-10-12 03:19:20 +02:00
|
|
|
reset_skip_txfm_size(cpi, TX_8X8);
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
} else if (count8x8_8x8p == 0 && count16x16_16x16p == 0 &&
|
|
|
|
count8x8_lp == 0 && count16x16_lp == 0 && count32x32 == 0) {
|
2012-10-09 18:18:21 +02:00
|
|
|
cpi->common.txfm_mode = ONLY_4X4;
|
2012-10-12 03:19:20 +02:00
|
|
|
reset_skip_txfm_size(cpi, TX_4X4);
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
} else if (count8x8_lp == 0 && count16x16_lp == 0 && count4x4 == 0) {
|
|
|
|
cpi->common.txfm_mode = ALLOW_32X32;
|
|
|
|
} else if (count32x32 == 0 && count8x8_lp == 0 && count4x4 == 0) {
|
2012-10-09 18:18:21 +02:00
|
|
|
cpi->common.txfm_mode = ALLOW_16X16;
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
reset_skip_txfm_size(cpi, TX_16X16);
|
2012-10-09 18:18:21 +02:00
|
|
|
}
|
|
|
|
}
|
2012-12-20 23:56:19 +01:00
|
|
|
|
|
|
|
// Update interpolation filter strategy for next frame.
|
|
|
|
if ((cpi->common.frame_type != KEY_FRAME) && (cpi->sf.search_best_filter))
|
2013-02-28 22:18:02 +01:00
|
|
|
vp9_select_interp_filter_type(cpi);
|
2012-07-14 00:21:29 +02:00
|
|
|
} else {
|
|
|
|
encode_frame_internal(cpi);
|
|
|
|
}
|
Dual 16x16 inter prediction.
This patch introduces the concept of dual inter16x16 prediction. A
16x16 inter-predicted macroblock can use 2 references instead of 1,
where both references use the same mvmode (new, near/est, zero). In the
case of newmv, this means that two MVs are coded instead of one. The
frame can be encoded in 3 ways: all MBs single-prediction, all MBs dual
prediction, or per-MB single/dual prediction selection ("hybrid"), in
which case a single bit is coded per-MB to indicate whether the MB uses
single or dual inter prediction.
In the future, we can (maybe?) get further gains by mixing this with
Adrian's 32x32 work, per-segment dual prediction settings, or adding
support for dual splitmv/8x8mv inter prediction.
Gain (on derf-set, CQ mode) is ~2.8% (SSIM) or ~3.6% (glb PSNR). Most
gain is at medium/high bitrates, but there's minor gains at low bitrates
also. Output was confirmed to match between encoder and decoder.
Note for optimization people: this patch introduces a 2nd version of
16x16/8x8 sixtap/bilin functions, which does an avg instead of a
store. They may want to look and make sure this is implemented to
their satisfaction so we can optimize it best in the future.
Change-ID: I59dc84b07cbb3ccf073ac0f756d03d294cb19281
2011-12-06 20:53:02 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-10-30 20:58:42 +01:00
|
|
|
void vp9_setup_block_ptrs(MACROBLOCK *x) {
|
2012-07-14 00:21:29 +02:00
|
|
|
int r, c;
|
|
|
|
int i;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
for (r = 0; r < 4; r++) {
|
2013-02-28 22:18:02 +01:00
|
|
|
for (c = 0; c < 4; c++)
|
2012-07-14 00:21:29 +02:00
|
|
|
x->block[r * 4 + c].src_diff = x->src_diff + r * 4 * 16 + c * 4;
|
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
for (r = 0; r < 2; r++) {
|
2013-02-28 22:18:02 +01:00
|
|
|
for (c = 0; c < 2; c++)
|
2012-07-14 00:21:29 +02:00
|
|
|
x->block[16 + r * 2 + c].src_diff = x->src_diff + 256 + r * 4 * 8 + c * 4;
|
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
for (r = 0; r < 2; r++) {
|
2013-02-28 22:18:02 +01:00
|
|
|
for (c = 0; c < 2; c++)
|
2012-07-14 00:21:29 +02:00
|
|
|
x->block[20 + r * 2 + c].src_diff = x->src_diff + 320 + r * 4 * 8 + c * 4;
|
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-02-28 22:18:02 +01:00
|
|
|
for (i = 0; i < 24; i++)
|
2012-07-14 00:21:29 +02:00
|
|
|
x->block[i].coeff = x->coeff + i * 16;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
2012-10-30 20:58:42 +01:00
|
|
|
void vp9_build_block_offsets(MACROBLOCK *x) {
|
2012-07-14 00:21:29 +02:00
|
|
|
int block = 0;
|
|
|
|
int br, bc;
|
|
|
|
|
2012-10-31 00:25:53 +01:00
|
|
|
vp9_build_block_doffsets(&x->e_mbd);
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2012-11-10 17:39:51 +01:00
|
|
|
for (br = 0; br < 4; br++) {
|
|
|
|
for (bc = 0; bc < 4; bc++) {
|
|
|
|
BLOCK *this_block = &x->block[block];
|
|
|
|
// this_block->base_src = &x->src.y_buffer;
|
|
|
|
// this_block->src_stride = x->src.y_stride;
|
|
|
|
// this_block->src = 4 * br * this_block->src_stride + 4 * bc;
|
|
|
|
this_block->base_src = &x->src.y_buffer;
|
|
|
|
this_block->src_stride = x->src.y_stride;
|
|
|
|
this_block->src = 4 * br * this_block->src_stride + 4 * bc;
|
|
|
|
++block;
|
|
|
|
}
|
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
|
|
|
|
// u blocks
|
|
|
|
for (br = 0; br < 2; br++) {
|
|
|
|
for (bc = 0; bc < 2; bc++) {
|
|
|
|
BLOCK *this_block = &x->block[block];
|
|
|
|
this_block->base_src = &x->src.u_buffer;
|
|
|
|
this_block->src_stride = x->src.uv_stride;
|
|
|
|
this_block->src = 4 * br * this_block->src_stride + 4 * bc;
|
|
|
|
++block;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// v blocks
|
|
|
|
for (br = 0; br < 2; br++) {
|
|
|
|
for (bc = 0; bc < 2; bc++) {
|
|
|
|
BLOCK *this_block = &x->block[block];
|
|
|
|
this_block->base_src = &x->src.v_buffer;
|
|
|
|
this_block->src_stride = x->src.uv_stride;
|
|
|
|
this_block->src = 4 * br * this_block->src_stride + 4 * bc;
|
|
|
|
++block;
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
2012-10-31 01:53:32 +01:00
|
|
|
static void sum_intra_stats(VP9_COMP *cpi, MACROBLOCK *x) {
|
2012-10-17 23:51:27 +02:00
|
|
|
const MACROBLOCKD *xd = &x->e_mbd;
|
2012-07-14 00:21:29 +02:00
|
|
|
const MB_PREDICTION_MODE m = xd->mode_info_context->mbmi.mode;
|
|
|
|
const MB_PREDICTION_MODE uvm = xd->mode_info_context->mbmi.uv_mode;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
|
|
|
#ifdef MODE_STATS
|
2012-07-14 00:21:29 +02:00
|
|
|
const int is_key = cpi->common.frame_type == KEY_FRAME;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
++ (is_key ? uv_modes : inter_uv_modes)[uvm];
|
|
|
|
++ uv_modes_y[m][uvm];
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2013-04-11 21:16:35 +02:00
|
|
|
if (m == I4X4_PRED) {
|
2012-07-14 00:21:29 +02:00
|
|
|
unsigned int *const bct = is_key ? b_modes : inter_b_modes;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
int b = 0;
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
do {
|
|
|
|
++ bct[xd->block[b].bmi.as_mode.first];
|
|
|
|
} while (++b < 16);
|
|
|
|
}
|
2011-12-07 22:03:57 +01:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
if (m == I8X8_PRED) {
|
|
|
|
i8x8_modes[xd->block[0].bmi.as_mode.first]++;
|
|
|
|
i8x8_modes[xd->block[2].bmi.as_mode.first]++;
|
|
|
|
i8x8_modes[xd->block[8].bmi.as_mode.first]++;
|
|
|
|
i8x8_modes[xd->block[10].bmi.as_mode.first]++;
|
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
#endif
|
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
if (xd->mode_info_context->mbmi.sb_type) {
|
2012-08-20 23:43:34 +02:00
|
|
|
++cpi->sb_ymode_count[m];
|
2013-01-08 19:29:22 +01:00
|
|
|
} else {
|
2012-08-20 23:43:34 +02:00
|
|
|
++cpi->ymode_count[m];
|
2013-01-08 19:29:22 +01:00
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
if (m != I8X8_PRED)
|
|
|
|
++cpi->y_uv_mode_count[m][uvm];
|
|
|
|
else {
|
|
|
|
cpi->i8x8_mode_count[xd->block[0].bmi.as_mode.first]++;
|
|
|
|
cpi->i8x8_mode_count[xd->block[2].bmi.as_mode.first]++;
|
|
|
|
cpi->i8x8_mode_count[xd->block[8].bmi.as_mode.first]++;
|
|
|
|
cpi->i8x8_mode_count[xd->block[10].bmi.as_mode.first]++;
|
|
|
|
}
|
2013-04-11 21:16:35 +02:00
|
|
|
if (m == I4X4_PRED) {
|
2012-07-14 00:21:29 +02:00
|
|
|
int b = 0;
|
|
|
|
do {
|
2012-10-09 22:19:15 +02:00
|
|
|
int m = xd->block[b].bmi.as_mode.first;
|
|
|
|
#if CONFIG_NEWBINTRAMODES
|
|
|
|
if (m == B_CONTEXT_PRED) m -= CONTEXT_PRED_REPLACEMENTS;
|
|
|
|
#endif
|
|
|
|
++cpi->bmode_count[m];
|
2012-07-14 00:21:29 +02:00
|
|
|
} while (++b < 16);
|
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2011-05-12 18:01:55 +02:00
|
|
|
|
|
|
|
// Experimental stub function to create a per MB zbin adjustment based on
|
|
|
|
// some previously calculated measure of MB activity.
|
2012-10-31 01:53:32 +01:00
|
|
|
static void adjust_act_zbin(VP9_COMP *cpi, MACROBLOCK *x) {
|
2011-06-08 17:00:59 +02:00
|
|
|
#if USE_ACT_INDEX
|
2012-07-14 00:21:29 +02:00
|
|
|
x->act_zbin_adj = *(x->mb_activity_ptr);
|
2011-06-08 17:00:59 +02:00
|
|
|
#else
|
2012-07-14 00:21:29 +02:00
|
|
|
int64_t a;
|
|
|
|
int64_t b;
|
|
|
|
int64_t act = *(x->mb_activity_ptr);
|
|
|
|
|
|
|
|
// Apply the masking to the RD multiplier.
|
|
|
|
a = act + 4 * cpi->activity_avg;
|
|
|
|
b = 4 * act + cpi->activity_avg;
|
|
|
|
|
|
|
|
if (act > cpi->activity_avg)
|
|
|
|
x->act_zbin_adj = (int)(((int64_t)b + (a >> 1)) / a) - 1;
|
|
|
|
else
|
|
|
|
x->act_zbin_adj = 1 - (int)(((int64_t)a + (b >> 1)) / b);
|
2011-06-08 17:00:59 +02:00
|
|
|
#endif
|
2011-05-12 18:01:55 +02:00
|
|
|
}
|
|
|
|
|
2013-02-20 19:16:24 +01:00
|
|
|
#if CONFIG_CODE_NONZEROCOUNT
|
|
|
|
static void gather_nzcs_mb16(VP9_COMMON *const cm,
|
|
|
|
MACROBLOCKD *xd) {
|
|
|
|
int i;
|
|
|
|
vpx_memset(xd->mode_info_context->mbmi.nzcs, 0,
|
|
|
|
384 * sizeof(xd->mode_info_context->mbmi.nzcs[0]));
|
|
|
|
switch (xd->mode_info_context->mbmi.txfm_size) {
|
|
|
|
case TX_4X4:
|
|
|
|
for (i = 0; i < 24; ++i) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TX_8X8:
|
|
|
|
for (i = 0; i < 16; i += 4) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
if (xd->mode_info_context->mbmi.mode == I8X8_PRED ||
|
|
|
|
xd->mode_info_context->mbmi.mode == SPLITMV) {
|
|
|
|
for (i = 16; i < 24; ++i) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 16; i < 24; i += 4) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TX_16X16:
|
|
|
|
xd->mode_info_context->mbmi.nzcs[0] = xd->nzcs[0];
|
|
|
|
for (i = 16; i < 24; i += 4) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gather_nzcs_sb32(VP9_COMMON *const cm,
|
|
|
|
MACROBLOCKD *xd) {
|
|
|
|
MODE_INFO *m = xd->mode_info_context;
|
|
|
|
int mis = cm->mode_info_stride;
|
2013-03-26 23:23:30 +01:00
|
|
|
int i, j;
|
|
|
|
|
2013-02-20 19:16:24 +01:00
|
|
|
vpx_memset(m->mbmi.nzcs, 0,
|
|
|
|
384 * sizeof(xd->mode_info_context->mbmi.nzcs[0]));
|
|
|
|
switch (xd->mode_info_context->mbmi.txfm_size) {
|
|
|
|
case TX_4X4:
|
|
|
|
for (i = 0; i < 96; ++i) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TX_8X8:
|
|
|
|
for (i = 0; i < 96; i += 4) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TX_16X16:
|
|
|
|
for (i = 0; i < 96; i += 16) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TX_32X32:
|
|
|
|
xd->mode_info_context->mbmi.nzcs[0] = xd->nzcs[0];
|
|
|
|
for (i = 64; i < 96; i += 16) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (i = 0; i < 2; ++i)
|
|
|
|
for (j = 0; j < 2; ++j) {
|
|
|
|
if (i == 0 && j == 0) continue;
|
|
|
|
vpx_memcpy((m + j + mis * i)->mbmi.nzcs, m->mbmi.nzcs,
|
|
|
|
384 * sizeof(m->mbmi.nzcs[0]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gather_nzcs_sb64(VP9_COMMON *const cm,
|
|
|
|
MACROBLOCKD *xd) {
|
|
|
|
MODE_INFO *m = xd->mode_info_context;
|
|
|
|
int mis = cm->mode_info_stride;
|
2013-03-26 23:23:30 +01:00
|
|
|
int i, j;
|
|
|
|
|
2013-02-20 19:16:24 +01:00
|
|
|
vpx_memset(xd->mode_info_context->mbmi.nzcs, 0,
|
|
|
|
384 * sizeof(xd->mode_info_context->mbmi.nzcs[0]));
|
|
|
|
switch (xd->mode_info_context->mbmi.txfm_size) {
|
|
|
|
case TX_4X4:
|
|
|
|
for (i = 0; i < 384; ++i) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TX_8X8:
|
|
|
|
for (i = 0; i < 384; i += 4) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TX_16X16:
|
|
|
|
for (i = 0; i < 384; i += 16) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TX_32X32:
|
|
|
|
for (i = 0; i < 384; i += 64) {
|
|
|
|
xd->mode_info_context->mbmi.nzcs[i] = xd->nzcs[i];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
|
|
for (j = 0; j < 4; ++j) {
|
|
|
|
if (i == 0 && j == 0) continue;
|
|
|
|
vpx_memcpy((m + j + mis * i)->mbmi.nzcs, m->mbmi.nzcs,
|
|
|
|
384 * sizeof(m->mbmi.nzcs[0]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
static void encode_macroblock(VP9_COMP *cpi, TOKENEXTRA **t,
|
|
|
|
int output_enabled,
|
|
|
|
int mb_row, int mb_col) {
|
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
2012-07-14 00:21:29 +02:00
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
2013-03-04 23:12:17 +01:00
|
|
|
MODE_INFO *mi = xd->mode_info_context;
|
|
|
|
MB_MODE_INFO *const mbmi = &mi->mbmi;
|
|
|
|
const int mis = cm->mode_info_stride;
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2013-01-06 03:20:25 +01:00
|
|
|
assert(!xd->mode_info_context->mbmi.sb_type);
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2012-11-16 00:14:38 +01:00
|
|
|
#ifdef ENC_DEBUG
|
Implicit weighted prediction experiment
Adds an experiment to use a weighted prediction of two INTER
predictors, where the weight is one of (1/4, 3/4), (3/8, 5/8),
(1/2, 1/2), (5/8, 3/8) or (3/4, 1/4), and is chosen implicitly
based on consistency of the predictors to the already
reconstructed pixels to the top and left of the current macroblock
or superblock.
Currently the weighting is not applied to SPLITMV modes, which
default to the usual (1/2, 1/2) weighting. However the code is in
place controlled by a macro. The same weighting is used for Y and
UV components, where the weight is derived from analyzing the Y
component only.
Results (over compound inter-intra experiment)
derf: +0.18%
yt: +0.34%
hd: +0.49%
stdhd: +0.23%
The experiment suggests bigger benefit for explicitly signaled weights.
Change-Id: I5438539ff4485c5752874cd1eb078ff14bf5235a
2013-03-12 22:21:08 +01:00
|
|
|
enc_debug = (cpi->common.current_video_frame == 11 && cm->show_frame &&
|
|
|
|
mb_row == 8 && mb_col == 0 && output_enabled);
|
2012-11-16 00:14:38 +01:00
|
|
|
if (enc_debug)
|
|
|
|
printf("Encode MB %d %d output %d\n", mb_row, mb_col, output_enabled);
|
|
|
|
#endif
|
2012-11-14 00:04:02 +01:00
|
|
|
if (cm->frame_type == KEY_FRAME) {
|
|
|
|
if (cpi->oxcf.tuning == VP8_TUNE_SSIM && output_enabled) {
|
|
|
|
// Adjust the zbin based on this MB rate.
|
|
|
|
adjust_act_zbin(cpi, x);
|
|
|
|
vp9_update_zbin_extra(cpi, x);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
vp9_setup_interp_filters(xd, mbmi->interp_filter, cm);
|
|
|
|
|
|
|
|
if (cpi->oxcf.tuning == VP8_TUNE_SSIM) {
|
|
|
|
// Adjust the zbin based on this MB rate.
|
|
|
|
adjust_act_zbin(cpi, x);
|
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
|
|
|
|
// Experimental code. Special case for gf and arf zeromv modes.
|
|
|
|
// Increase zbin size to suppress noise
|
|
|
|
cpi->zbin_mode_boost = 0;
|
|
|
|
if (cpi->zbin_mode_boost_enabled) {
|
2012-08-10 15:12:43 +02:00
|
|
|
if (mbmi->ref_frame != INTRA_FRAME) {
|
|
|
|
if (mbmi->mode == ZEROMV) {
|
|
|
|
if (mbmi->ref_frame != LAST_FRAME)
|
2012-07-14 00:21:29 +02:00
|
|
|
cpi->zbin_mode_boost = GF_ZEROMV_ZBIN_BOOST;
|
|
|
|
else
|
|
|
|
cpi->zbin_mode_boost = LF_ZEROMV_ZBIN_BOOST;
|
2012-08-10 15:12:43 +02:00
|
|
|
} else if (mbmi->mode == SPLITMV)
|
2013-03-21 19:37:48 +01:00
|
|
|
cpi->zbin_mode_boost = SPLIT_MV_ZBIN_BOOST;
|
2012-07-14 00:21:29 +02:00
|
|
|
else
|
|
|
|
cpi->zbin_mode_boost = MV_ZBIN_BOOST;
|
2013-03-21 19:37:48 +01:00
|
|
|
} else {
|
|
|
|
cpi->zbin_mode_boost = INTRA_ZBIN_BOOST;
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2011-05-12 18:01:55 +02:00
|
|
|
}
|
|
|
|
|
2012-10-30 20:58:42 +01:00
|
|
|
vp9_update_zbin_extra(cpi, x);
|
2012-11-14 00:04:02 +01:00
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2012-08-10 15:12:43 +02:00
|
|
|
if (mbmi->ref_frame == INTRA_FRAME) {
|
Implicit weighted prediction experiment
Adds an experiment to use a weighted prediction of two INTER
predictors, where the weight is one of (1/4, 3/4), (3/8, 5/8),
(1/2, 1/2), (5/8, 3/8) or (3/4, 1/4), and is chosen implicitly
based on consistency of the predictors to the already
reconstructed pixels to the top and left of the current macroblock
or superblock.
Currently the weighting is not applied to SPLITMV modes, which
default to the usual (1/2, 1/2) weighting. However the code is in
place controlled by a macro. The same weighting is used for Y and
UV components, where the weight is derived from analyzing the Y
component only.
Results (over compound inter-intra experiment)
derf: +0.18%
yt: +0.34%
hd: +0.49%
stdhd: +0.23%
The experiment suggests bigger benefit for explicitly signaled weights.
Change-Id: I5438539ff4485c5752874cd1eb078ff14bf5235a
2013-03-12 22:21:08 +01:00
|
|
|
#if 0 // def ENC_DEBUG
|
2012-11-16 00:14:38 +01:00
|
|
|
if (enc_debug) {
|
|
|
|
printf("Mode %d skip %d tx_size %d\n", mbmi->mode, x->skip,
|
|
|
|
mbmi->txfm_size);
|
|
|
|
}
|
|
|
|
#endif
|
2013-04-11 21:16:35 +02:00
|
|
|
if (mbmi->mode == I4X4_PRED) {
|
2013-02-20 19:16:24 +01:00
|
|
|
vp9_encode_intra16x16mbuv(cm, x);
|
2012-11-25 04:33:58 +01:00
|
|
|
vp9_encode_intra4x4mby(x);
|
2012-08-10 15:12:43 +02:00
|
|
|
} else if (mbmi->mode == I8X8_PRED) {
|
2012-11-25 04:33:58 +01:00
|
|
|
vp9_encode_intra8x8mby(x);
|
|
|
|
vp9_encode_intra8x8mbuv(x);
|
2012-07-14 00:21:29 +02:00
|
|
|
} else {
|
2013-02-20 19:16:24 +01:00
|
|
|
vp9_encode_intra16x16mbuv(cm, x);
|
|
|
|
vp9_encode_intra16x16mby(cm, x);
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
if (output_enabled)
|
|
|
|
sum_intra_stats(cpi, x);
|
|
|
|
} else {
|
|
|
|
int ref_fb_idx;
|
2012-11-16 00:14:38 +01:00
|
|
|
#ifdef ENC_DEBUG
|
|
|
|
if (enc_debug)
|
2012-11-30 01:39:15 +01:00
|
|
|
printf("Mode %d skip %d tx_size %d ref %d ref2 %d mv %d %d interp %d\n",
|
2012-11-16 00:14:38 +01:00
|
|
|
mbmi->mode, x->skip, mbmi->txfm_size,
|
|
|
|
mbmi->ref_frame, mbmi->second_ref_frame,
|
2012-11-30 01:39:15 +01:00
|
|
|
mbmi->mv[0].as_mv.row, mbmi->mv[0].as_mv.col,
|
|
|
|
mbmi->interp_filter);
|
2012-11-16 00:14:38 +01:00
|
|
|
#endif
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2012-11-14 00:04:02 +01:00
|
|
|
assert(cm->frame_type != KEY_FRAME);
|
|
|
|
|
2012-08-10 15:12:43 +02:00
|
|
|
if (mbmi->ref_frame == LAST_FRAME)
|
2013-02-22 20:22:03 +01:00
|
|
|
ref_fb_idx = cpi->common.ref_frame_map[cpi->lst_fb_idx];
|
2012-08-10 15:12:43 +02:00
|
|
|
else if (mbmi->ref_frame == GOLDEN_FRAME)
|
2013-02-22 20:22:03 +01:00
|
|
|
ref_fb_idx = cpi->common.ref_frame_map[cpi->gld_fb_idx];
|
2012-04-07 01:38:34 +02:00
|
|
|
else
|
2013-02-22 20:22:03 +01:00
|
|
|
ref_fb_idx = cpi->common.ref_frame_map[cpi->alt_fb_idx];
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2013-02-07 19:09:05 +01:00
|
|
|
setup_pred_block(&xd->pre,
|
|
|
|
&cpi->common.yv12_fb[ref_fb_idx],
|
Spatial resamping of ZEROMV predictors
This patch allows coding frames using references of different
resolution, in ZEROMV mode. For compound prediction, either
reference may be scaled.
To test, I use the resize_test and enable WRITE_RECON_BUFFER
in vp9_onyxd_if.c. It's also useful to apply this patch to
test/i420_video_source.h:
--- a/test/i420_video_source.h
+++ b/test/i420_video_source.h
@@ -93,6 +93,7 @@ class I420VideoSource : public VideoSource {
virtual void FillFrame() {
// Read a frame from input_file.
+ if (frame_ != 3)
if (fread(img_->img_data, raw_sz_, 1, input_file_) == 0) {
limit_ = frame_;
}
This forces the frame that the resolution changes on to be coded
with no motion, only scaling, and improves the quality of the
result.
Change-Id: I1ee75d19a437ff801192f767fd02a36bcbd1d496
2013-02-25 05:55:14 +01:00
|
|
|
mb_row, mb_col,
|
|
|
|
&xd->scale_factor[0], &xd->scale_factor_uv[0]);
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2012-11-07 15:50:25 +01:00
|
|
|
if (mbmi->second_ref_frame > 0) {
|
2012-07-14 00:21:29 +02:00
|
|
|
int second_ref_fb_idx;
|
|
|
|
|
2012-08-10 15:12:43 +02:00
|
|
|
if (mbmi->second_ref_frame == LAST_FRAME)
|
2013-02-22 20:22:03 +01:00
|
|
|
second_ref_fb_idx = cpi->common.ref_frame_map[cpi->lst_fb_idx];
|
2012-08-10 15:12:43 +02:00
|
|
|
else if (mbmi->second_ref_frame == GOLDEN_FRAME)
|
2013-02-22 20:22:03 +01:00
|
|
|
second_ref_fb_idx = cpi->common.ref_frame_map[cpi->gld_fb_idx];
|
2012-07-14 00:21:29 +02:00
|
|
|
else
|
2013-02-22 20:22:03 +01:00
|
|
|
second_ref_fb_idx = cpi->common.ref_frame_map[cpi->alt_fb_idx];
|
2012-07-14 00:21:29 +02:00
|
|
|
|
2013-02-07 19:09:05 +01:00
|
|
|
setup_pred_block(&xd->second_pre,
|
|
|
|
&cpi->common.yv12_fb[second_ref_fb_idx],
|
Spatial resamping of ZEROMV predictors
This patch allows coding frames using references of different
resolution, in ZEROMV mode. For compound prediction, either
reference may be scaled.
To test, I use the resize_test and enable WRITE_RECON_BUFFER
in vp9_onyxd_if.c. It's also useful to apply this patch to
test/i420_video_source.h:
--- a/test/i420_video_source.h
+++ b/test/i420_video_source.h
@@ -93,6 +93,7 @@ class I420VideoSource : public VideoSource {
virtual void FillFrame() {
// Read a frame from input_file.
+ if (frame_ != 3)
if (fread(img_->img_data, raw_sz_, 1, input_file_) == 0) {
limit_ = frame_;
}
This forces the frame that the resolution changes on to be coded
with no motion, only scaling, and improves the quality of the
result.
Change-Id: I1ee75d19a437ff801192f767fd02a36bcbd1d496
2013-02-25 05:55:14 +01:00
|
|
|
mb_row, mb_col,
|
|
|
|
&xd->scale_factor[1], &xd->scale_factor_uv[1]);
|
2012-04-07 01:38:34 +02:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
if (!x->skip) {
|
2013-02-20 19:16:24 +01:00
|
|
|
vp9_encode_inter16x16(cm, x, mb_row, mb_col);
|
2012-07-14 00:21:29 +02:00
|
|
|
} else {
|
2013-04-15 18:31:27 +02:00
|
|
|
vp9_build_inter_predictors_sb(xd, mb_row, mb_col, BLOCK_SIZE_MB16X16);
|
2012-11-16 00:14:38 +01:00
|
|
|
#if CONFIG_COMP_INTERINTRA_PRED
|
2013-02-09 02:49:44 +01:00
|
|
|
if (xd->mode_info_context->mbmi.second_ref_frame == INTRA_FRAME) {
|
2012-11-16 00:14:38 +01:00
|
|
|
vp9_build_interintra_16x16_predictors_mb(xd,
|
|
|
|
xd->dst.y_buffer,
|
|
|
|
xd->dst.u_buffer,
|
|
|
|
xd->dst.v_buffer,
|
|
|
|
xd->dst.y_stride,
|
|
|
|
xd->dst.uv_stride);
|
|
|
|
}
|
|
|
|
#endif
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
if (!x->skip) {
|
2013-02-20 19:16:24 +01:00
|
|
|
#ifdef ENC_DEBUG
|
2012-07-14 00:21:29 +02:00
|
|
|
if (enc_debug) {
|
2012-11-16 00:14:38 +01:00
|
|
|
int i, j;
|
|
|
|
printf("\n");
|
|
|
|
printf("qcoeff\n");
|
2013-02-20 19:16:24 +01:00
|
|
|
for (i = 0; i < 384; i++) {
|
2012-07-14 00:21:29 +02:00
|
|
|
printf("%3d ", xd->qcoeff[i]);
|
|
|
|
if (i % 16 == 15) printf("\n");
|
|
|
|
}
|
|
|
|
printf("\n");
|
2012-11-16 00:14:38 +01:00
|
|
|
printf("predictor\n");
|
|
|
|
for (i = 0; i < 384; i++) {
|
|
|
|
printf("%3d ", xd->predictor[i]);
|
|
|
|
if (i % 16 == 15) printf("\n");
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
printf("src_diff\n");
|
|
|
|
for (i = 0; i < 384; i++) {
|
|
|
|
printf("%3d ", x->src_diff[i]);
|
|
|
|
if (i % 16 == 15) printf("\n");
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
printf("diff\n");
|
|
|
|
for (i = 0; i < 384; i++) {
|
|
|
|
printf("%3d ", xd->block[0].diff[i]);
|
|
|
|
if (i % 16 == 15) printf("\n");
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
printf("final y\n");
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
for (j = 0; j < 16; j++)
|
|
|
|
printf("%3d ", xd->dst.y_buffer[i * xd->dst.y_stride + j]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
printf("final u\n");
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
for (j = 0; j < 8; j++)
|
|
|
|
printf("%3d ", xd->dst.u_buffer[i * xd->dst.uv_stride + j]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
printf("\n");
|
2012-11-16 00:14:38 +01:00
|
|
|
printf("final v\n");
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
for (j = 0; j < 8; j++)
|
|
|
|
printf("%3d ", xd->dst.v_buffer[i * xd->dst.uv_stride + j]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
2012-07-14 00:21:29 +02:00
|
|
|
fflush(stdout);
|
|
|
|
}
|
2011-02-14 23:18:18 +01:00
|
|
|
#endif
|
2012-08-06 19:51:20 +02:00
|
|
|
|
2013-02-20 19:16:24 +01:00
|
|
|
#if CONFIG_CODE_NONZEROCOUNT
|
|
|
|
gather_nzcs_mb16(cm, xd);
|
|
|
|
#endif
|
2012-10-30 20:58:42 +01:00
|
|
|
vp9_tokenize_mb(cpi, xd, t, !output_enabled);
|
2012-08-06 19:51:20 +02:00
|
|
|
|
2012-07-14 00:21:29 +02:00
|
|
|
} else {
|
2013-03-04 23:12:17 +01:00
|
|
|
// FIXME(rbultje): not tile-aware (mi - 1)
|
2013-04-09 19:54:19 +02:00
|
|
|
int mb_skip_context =
|
|
|
|
(mi - 1)->mbmi.mb_skip_coeff + (mi - mis)->mbmi.mb_skip_coeff;
|
|
|
|
|
|
|
|
mbmi->mb_skip_coeff = 1;
|
|
|
|
if (output_enabled)
|
|
|
|
cpi->skip_true_count[mb_skip_context]++;
|
|
|
|
vp9_reset_sb_tokens_context(xd, BLOCK_SIZE_MB16X16);
|
2012-07-14 00:21:29 +02:00
|
|
|
}
|
2012-10-09 18:18:21 +02:00
|
|
|
|
|
|
|
if (output_enabled) {
|
|
|
|
int segment_id = mbmi->segment_id;
|
|
|
|
if (cpi->common.txfm_mode == TX_MODE_SELECT &&
|
2013-04-09 19:54:19 +02:00
|
|
|
!(mbmi->mb_skip_coeff ||
|
|
|
|
vp9_segfeature_active(&x->e_mbd, segment_id, SEG_LVL_SKIP))) {
|
2013-01-07 20:02:14 +01:00
|
|
|
assert(mbmi->txfm_size <= TX_16X16);
|
2013-04-11 21:16:35 +02:00
|
|
|
if (mbmi->mode != I4X4_PRED && mbmi->mode != I8X8_PRED &&
|
2012-10-09 18:18:21 +02:00
|
|
|
mbmi->mode != SPLITMV) {
|
32x32 transform for superblocks.
This adds Debargha's DCT/DWT hybrid and a regular 32x32 DCT, and adds
code all over the place to wrap that in the bitstream/encoder/decoder/RD.
Some implementation notes (these probably need careful review):
- token range is extended by 1 bit, since the value range out of this
transform is [-16384,16383].
- the coefficients coming out of the FDCT are manually scaled back by
1 bit, or else they won't fit in int16_t (they are 17 bits). Because
of this, the RD error scoring does not right-shift the MSE score by
two (unlike for 4x4/8x8/16x16).
- to compensate for this loss in precision, the quantizer is halved
also. This is currently a little hacky.
- FDCT and IDCT is double-only right now. Needs a fixed-point impl.
- There are no default probabilities for the 32x32 transform yet; I'm
simply using the 16x16 luma ones. A future commit will add newly
generated probabilities for all transforms.
- No ADST version. I don't think we'll add one for this level; if an
ADST is desired, transform-size selection can scale back to 16x16
or lower, and use an ADST at that level.
Additional notes specific to Debargha's DWT/DCT hybrid:
- coefficient scale is different for the top/left 16x16 (DCT-over-DWT)
block than for the rest (DWT pixel differences) of the block. Therefore,
RD error scoring isn't easily scalable between coefficient and pixel
domain. Thus, unfortunately, we need to compute the RD distortion in
the pixel domain until we figure out how to scale these appropriately.
Change-Id: I00386f20f35d7fabb19aba94c8162f8aee64ef2b
2012-12-07 23:45:05 +01:00
|
|
|
cpi->txfm_count_16x16p[mbmi->txfm_size]++;
|
2012-10-22 20:49:00 +02:00
|
|
|
} else if (mbmi->mode == I8X8_PRED ||
|
|
|
|
(mbmi->mode == SPLITMV &&
|
|
|
|
mbmi->partitioning != PARTITIONING_4X4)) {
|
2012-10-11 02:18:22 +02:00
|
|
|
cpi->txfm_count_8x8p[mbmi->txfm_size]++;
|
2012-10-09 18:18:21 +02:00
|
|
|
}
|
2013-04-11 21:16:35 +02:00
|
|
|
} else if (mbmi->mode != I4X4_PRED && mbmi->mode != I8X8_PRED &&
|
2012-10-09 18:18:21 +02:00
|
|
|
mbmi->mode != SPLITMV && cpi->common.txfm_mode >= ALLOW_16X16) {
|
|
|
|
mbmi->txfm_size = TX_16X16;
|
2013-04-11 21:16:35 +02:00
|
|
|
} else if (mbmi->mode != I4X4_PRED &&
|
2012-10-22 20:49:00 +02:00
|
|
|
!(mbmi->mode == SPLITMV &&
|
|
|
|
mbmi->partitioning == PARTITIONING_4X4) &&
|
|
|
|
cpi->common.txfm_mode >= ALLOW_8X8) {
|
2012-10-09 18:18:21 +02:00
|
|
|
mbmi->txfm_size = TX_8X8;
|
|
|
|
} else {
|
|
|
|
mbmi->txfm_size = TX_4X4;
|
|
|
|
}
|
|
|
|
}
|
2010-05-18 17:58:33 +02:00
|
|
|
}
|
2012-08-20 23:43:34 +02:00
|
|
|
|
2013-04-10 06:28:27 +02:00
|
|
|
static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t,
|
|
|
|
int output_enabled, int mb_row, int mb_col,
|
|
|
|
BLOCK_SIZE_TYPE bsize) {
|
2013-01-06 03:20:25 +01:00
|
|
|
VP9_COMMON *const cm = &cpi->common;
|
|
|
|
MACROBLOCK *const x = &cpi->mb;
|
|
|
|
MACROBLOCKD *const xd = &x->e_mbd;
|
|
|
|
const uint8_t *src = x->src.y_buffer;
|
|
|
|
uint8_t *dst = xd->dst.y_buffer;
|
|
|
|
const uint8_t *usrc = x->src.u_buffer;
|
|
|
|
uint8_t *udst = xd->dst.u_buffer;
|
|
|
|
const uint8_t *vsrc = x->src.v_buffer;
|
|
|
|
uint8_t *vdst = xd->dst.v_buffer;
|
|
|
|
int src_y_stride = x->src.y_stride, dst_y_stride = xd->dst.y_stride;
|
|
|
|
int src_uv_stride = x->src.uv_stride, dst_uv_stride = xd->dst.uv_stride;
|
|
|
|
int n;
|
|
|
|
MODE_INFO *mi = x->e_mbd.mode_info_context;
|
|
|
|
unsigned int segment_id = mi->mbmi.segment_id;
|
|
|
|
const int mis = cm->mode_info_stride;
|
2013-04-10 06:28:27 +02:00
|
|
|
const int bwl = mb_width_log2(bsize);
|
|
|
|
const int bw = 1 << bwl, bh = 1 << mb_height_log2(bsize);
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
if (cm->frame_type == KEY_FRAME) {
|
|
|
|
if (cpi->oxcf.tuning == VP8_TUNE_SSIM) {
|
|
|
|
adjust_act_zbin(cpi, x);
|
|
|
|
vp9_update_zbin_extra(cpi, x);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
vp9_setup_interp_filters(xd, xd->mode_info_context->mbmi.interp_filter, cm);
|
|
|
|
|
|
|
|
if (cpi->oxcf.tuning == VP8_TUNE_SSIM) {
|
|
|
|
// Adjust the zbin based on this MB rate.
|
|
|
|
adjust_act_zbin(cpi, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Experimental code. Special case for gf and arf zeromv modes.
|
|
|
|
// Increase zbin size to suppress noise
|
|
|
|
cpi->zbin_mode_boost = 0;
|
|
|
|
if (cpi->zbin_mode_boost_enabled) {
|
|
|
|
if (xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME) {
|
|
|
|
if (xd->mode_info_context->mbmi.mode == ZEROMV) {
|
|
|
|
if (xd->mode_info_context->mbmi.ref_frame != LAST_FRAME)
|
|
|
|
cpi->zbin_mode_boost = GF_ZEROMV_ZBIN_BOOST;
|
|
|
|
else
|
|
|
|
cpi->zbin_mode_boost = LF_ZEROMV_ZBIN_BOOST;
|
|
|
|
} else if (xd->mode_info_context->mbmi.mode == SPLITMV) {
|
2013-03-21 19:37:48 +01:00
|
|
|
cpi->zbin_mode_boost = SPLIT_MV_ZBIN_BOOST;
|
2013-01-06 03:20:25 +01:00
|
|
|
} else {
|
|
|
|
cpi->zbin_mode_boost = MV_ZBIN_BOOST;
|
|
|
|
}
|
2013-03-21 19:37:48 +01:00
|
|
|
} else {
|
|
|
|
cpi->zbin_mode_boost = INTRA_ZBIN_BOOST;
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vp9_update_zbin_extra(cpi, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) {
|
2013-04-11 21:12:11 +02:00
|
|
|
vp9_build_intra_predictors_sby_s(&x->e_mbd, bsize);
|
|
|
|
vp9_build_intra_predictors_sbuv_s(&x->e_mbd, bsize);
|
2013-01-06 03:20:25 +01:00
|
|
|
if (output_enabled)
|
|
|
|
sum_intra_stats(cpi, x);
|
2012-11-08 20:03:00 +01:00
|
|
|
} else {
|
2013-01-06 03:20:25 +01:00
|
|
|
int ref_fb_idx;
|
|
|
|
|
|
|
|
assert(cm->frame_type != KEY_FRAME);
|
|
|
|
|
|
|
|
if (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME)
|
2013-02-22 20:22:03 +01:00
|
|
|
ref_fb_idx = cpi->common.ref_frame_map[cpi->lst_fb_idx];
|
2013-01-06 03:20:25 +01:00
|
|
|
else if (xd->mode_info_context->mbmi.ref_frame == GOLDEN_FRAME)
|
2013-02-22 20:22:03 +01:00
|
|
|
ref_fb_idx = cpi->common.ref_frame_map[cpi->gld_fb_idx];
|
2013-01-06 03:20:25 +01:00
|
|
|
else
|
2013-02-22 20:22:03 +01:00
|
|
|
ref_fb_idx = cpi->common.ref_frame_map[cpi->alt_fb_idx];
|
2013-01-06 03:20:25 +01:00
|
|
|
|
2013-02-07 19:09:05 +01:00
|
|
|
setup_pred_block(&xd->pre,
|
|
|
|
&cpi->common.yv12_fb[ref_fb_idx],
|
Spatial resamping of ZEROMV predictors
This patch allows coding frames using references of different
resolution, in ZEROMV mode. For compound prediction, either
reference may be scaled.
To test, I use the resize_test and enable WRITE_RECON_BUFFER
in vp9_onyxd_if.c. It's also useful to apply this patch to
test/i420_video_source.h:
--- a/test/i420_video_source.h
+++ b/test/i420_video_source.h
@@ -93,6 +93,7 @@ class I420VideoSource : public VideoSource {
virtual void FillFrame() {
// Read a frame from input_file.
+ if (frame_ != 3)
if (fread(img_->img_data, raw_sz_, 1, input_file_) == 0) {
limit_ = frame_;
}
This forces the frame that the resolution changes on to be coded
with no motion, only scaling, and improves the quality of the
result.
Change-Id: I1ee75d19a437ff801192f767fd02a36bcbd1d496
2013-02-25 05:55:14 +01:00
|
|
|
mb_row, mb_col,
|
|
|
|
&xd->scale_factor[0], &xd->scale_factor_uv[0]);
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
if (xd->mode_info_context->mbmi.second_ref_frame > 0) {
|
|
|
|
int second_ref_fb_idx;
|
|
|
|
|
|
|
|
if (xd->mode_info_context->mbmi.second_ref_frame == LAST_FRAME)
|
2013-02-22 20:22:03 +01:00
|
|
|
second_ref_fb_idx = cpi->common.ref_frame_map[cpi->lst_fb_idx];
|
2013-01-06 03:20:25 +01:00
|
|
|
else if (xd->mode_info_context->mbmi.second_ref_frame == GOLDEN_FRAME)
|
2013-02-22 20:22:03 +01:00
|
|
|
second_ref_fb_idx = cpi->common.ref_frame_map[cpi->gld_fb_idx];
|
2013-01-06 03:20:25 +01:00
|
|
|
else
|
2013-02-22 20:22:03 +01:00
|
|
|
second_ref_fb_idx = cpi->common.ref_frame_map[cpi->alt_fb_idx];
|
2013-01-06 03:20:25 +01:00
|
|
|
|
2013-02-07 19:09:05 +01:00
|
|
|
setup_pred_block(&xd->second_pre,
|
|
|
|
&cpi->common.yv12_fb[second_ref_fb_idx],
|
Spatial resamping of ZEROMV predictors
This patch allows coding frames using references of different
resolution, in ZEROMV mode. For compound prediction, either
reference may be scaled.
To test, I use the resize_test and enable WRITE_RECON_BUFFER
in vp9_onyxd_if.c. It's also useful to apply this patch to
test/i420_video_source.h:
--- a/test/i420_video_source.h
+++ b/test/i420_video_source.h
@@ -93,6 +93,7 @@ class I420VideoSource : public VideoSource {
virtual void FillFrame() {
// Read a frame from input_file.
+ if (frame_ != 3)
if (fread(img_->img_data, raw_sz_, 1, input_file_) == 0) {
limit_ = frame_;
}
This forces the frame that the resolution changes on to be coded
with no motion, only scaling, and improves the quality of the
result.
Change-Id: I1ee75d19a437ff801192f767fd02a36bcbd1d496
2013-02-25 05:55:14 +01:00
|
|
|
mb_row, mb_col,
|
|
|
|
&xd->scale_factor[1], &xd->scale_factor_uv[1]);
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
|
|
|
|
2013-04-12 20:25:53 +02:00
|
|
|
vp9_build_inter_predictors_sb(xd, mb_row, mb_col, bsize);
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
|
|
|
|
2013-03-04 23:12:17 +01:00
|
|
|
if (!x->skip) {
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_subtract_sby_s_c(x->src_diff, src, src_y_stride, dst, dst_y_stride,
|
|
|
|
bsize);
|
|
|
|
vp9_subtract_sbuv_s_c(x->src_diff, usrc, vsrc, src_uv_stride,
|
|
|
|
udst, vdst, dst_uv_stride, bsize);
|
2013-01-06 03:20:25 +01:00
|
|
|
|
2013-03-04 23:12:17 +01:00
|
|
|
switch (xd->mode_info_context->mbmi.txfm_size) {
|
|
|
|
case TX_32X32:
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_transform_sby_32x32(x, bsize);
|
|
|
|
vp9_quantize_sby_32x32(x, bsize);
|
|
|
|
if (bsize == BLOCK_SIZE_SB64X64) {
|
|
|
|
vp9_transform_sbuv_32x32(x, bsize);
|
|
|
|
vp9_quantize_sbuv_32x32(x, bsize);
|
|
|
|
} else {
|
|
|
|
vp9_transform_sbuv_16x16(x, bsize);
|
|
|
|
vp9_quantize_sbuv_16x16(x, bsize);
|
|
|
|
}
|
2013-03-04 23:12:17 +01:00
|
|
|
if (x->optimize) {
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_optimize_sby_32x32(cm, x, bsize);
|
|
|
|
if (bsize == BLOCK_SIZE_SB64X64)
|
|
|
|
vp9_optimize_sbuv_32x32(cm, x, bsize);
|
|
|
|
else
|
|
|
|
vp9_optimize_sbuv_16x16(cm, x, bsize);
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_inverse_transform_sby_32x32(xd, bsize);
|
|
|
|
if (bsize == BLOCK_SIZE_SB64X64)
|
|
|
|
vp9_inverse_transform_sbuv_32x32(xd, bsize);
|
|
|
|
else
|
|
|
|
vp9_inverse_transform_sbuv_16x16(xd, bsize);
|
2013-03-04 23:12:17 +01:00
|
|
|
break;
|
|
|
|
case TX_16X16:
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_transform_sby_16x16(x, bsize);
|
|
|
|
vp9_quantize_sby_16x16(x, bsize);
|
|
|
|
if (bsize >= BLOCK_SIZE_SB32X32) {
|
|
|
|
vp9_transform_sbuv_16x16(x, bsize);
|
|
|
|
vp9_quantize_sbuv_16x16(x, bsize);
|
|
|
|
} else {
|
|
|
|
vp9_transform_sbuv_8x8(x, bsize);
|
|
|
|
vp9_quantize_sbuv_8x8(x, bsize);
|
|
|
|
}
|
2013-03-04 23:12:17 +01:00
|
|
|
if (x->optimize) {
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_optimize_sby_16x16(cm, x, bsize);
|
|
|
|
if (bsize >= BLOCK_SIZE_SB32X32)
|
|
|
|
vp9_optimize_sbuv_16x16(cm, x, bsize);
|
|
|
|
else
|
|
|
|
vp9_optimize_sbuv_8x8(cm, x, bsize);
|
2013-03-04 23:12:17 +01:00
|
|
|
}
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_inverse_transform_sby_16x16(xd, bsize);
|
|
|
|
if (bsize >= BLOCK_SIZE_SB32X32)
|
|
|
|
vp9_inverse_transform_sbuv_16x16(xd, bsize);
|
|
|
|
else
|
|
|
|
vp9_inverse_transform_sbuv_8x8(xd, bsize);
|
2013-03-04 23:12:17 +01:00
|
|
|
break;
|
|
|
|
case TX_8X8:
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_transform_sby_8x8(x, bsize);
|
|
|
|
vp9_transform_sbuv_8x8(x, bsize);
|
|
|
|
vp9_quantize_sby_8x8(x, bsize);
|
|
|
|
vp9_quantize_sbuv_8x8(x, bsize);
|
2013-03-04 23:12:17 +01:00
|
|
|
if (x->optimize) {
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_optimize_sby_8x8(cm, x, bsize);
|
|
|
|
vp9_optimize_sbuv_8x8(cm, x, bsize);
|
2013-03-04 23:12:17 +01:00
|
|
|
}
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_inverse_transform_sby_8x8(xd, bsize);
|
|
|
|
vp9_inverse_transform_sbuv_8x8(xd, bsize);
|
2013-03-04 23:12:17 +01:00
|
|
|
break;
|
|
|
|
case TX_4X4:
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_transform_sby_4x4(x, bsize);
|
|
|
|
vp9_transform_sbuv_4x4(x, bsize);
|
|
|
|
vp9_quantize_sby_4x4(x, bsize);
|
|
|
|
vp9_quantize_sbuv_4x4(x, bsize);
|
2013-03-04 23:12:17 +01:00
|
|
|
if (x->optimize) {
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_optimize_sby_4x4(cm, x, bsize);
|
|
|
|
vp9_optimize_sbuv_4x4(cm, x, bsize);
|
2013-03-04 23:12:17 +01:00
|
|
|
}
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_inverse_transform_sby_4x4(xd, bsize);
|
|
|
|
vp9_inverse_transform_sbuv_4x4(xd, bsize);
|
2013-03-04 23:12:17 +01:00
|
|
|
break;
|
|
|
|
default: assert(0);
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_recon_sby_s_c(xd, dst, bsize);
|
|
|
|
vp9_recon_sbuv_s_c(&x->e_mbd, udst, vdst, bsize);
|
2013-02-20 19:16:24 +01:00
|
|
|
#if CONFIG_CODE_NONZEROCOUNT
|
2013-04-10 06:28:27 +02:00
|
|
|
if (bsize == BLOCK_SIZE_SB32X32) {
|
|
|
|
gather_nzcs_sb32(cm, &x->e_mbd);
|
|
|
|
} else {
|
|
|
|
gather_nzcs_sb64(cm, &x->e_mbd);
|
|
|
|
}
|
2013-02-20 19:16:24 +01:00
|
|
|
#endif
|
2013-04-10 06:28:27 +02:00
|
|
|
vp9_tokenize_sb(cpi, &x->e_mbd, t, !output_enabled, bsize);
|
2013-01-10 17:23:59 +01:00
|
|
|
} else {
|
2013-03-04 23:12:17 +01:00
|
|
|
// FIXME(rbultje): not tile-aware (mi - 1)
|
2013-04-09 19:54:19 +02:00
|
|
|
int mb_skip_context =
|
|
|
|
(mi - 1)->mbmi.mb_skip_coeff + (mi - mis)->mbmi.mb_skip_coeff;
|
2013-03-04 23:12:17 +01:00
|
|
|
|
|
|
|
xd->mode_info_context->mbmi.mb_skip_coeff = 1;
|
2013-04-09 19:54:19 +02:00
|
|
|
if (output_enabled)
|
|
|
|
cpi->skip_true_count[mb_skip_context]++;
|
|
|
|
vp9_reset_sb_tokens_context(xd, bsize);
|
2013-01-06 03:20:25 +01:00
|
|
|
}
|
|
|
|
|
2013-03-04 23:12:17 +01:00
|
|
|
// copy skip flag on all mb_mode_info contexts in this SB
|
|
|
|
// if this was a skip at this txfm size
|
2013-04-10 06:28:27 +02:00
|
|
|
for (n = 1; n < bw * bh; n++) {
|
|
|
|
const int x_idx = n & (bw - 1), y_idx = n >> bwl;
|
2013-03-04 23:12:17 +01:00
|
|
|
if (mb_col + x_idx < cm->mb_cols && mb_row + y_idx < cm->mb_rows)
|
|
|
|
mi[x_idx + y_idx * mis].mbmi.mb_skip_coeff = mi->mbmi.mb_skip_coeff;
|
|
|
|
}
|
2013-01-06 03:20:25 +01:00
|
|
|
|
|
|
|
if (output_enabled) {
|
|
|
|
if (cm->txfm_mode == TX_MODE_SELECT &&
|
2013-04-09 19:54:19 +02:00
|
|
|
!(mi->mbmi.mb_skip_coeff ||
|
|
|
|
vp9_segfeature_active(xd, segment_id, SEG_LVL_SKIP))) {
|
2013-04-10 06:28:27 +02:00
|
|
|
if (bsize >= BLOCK_SIZE_SB32X32) {
|
|
|
|
cpi->txfm_count_32x32p[mi->mbmi.txfm_size]++;
|
|
|
|
} else {
|
|
|
|
cpi->txfm_count_16x16p[mi->mbmi.txfm_size]++;
|
|
|
|
}
|
2013-01-06 03:20:25 +01:00
|
|
|
} else {
|
|
|
|
int x, y;
|
2013-03-04 23:12:17 +01:00
|
|
|
TX_SIZE sz = (cm->txfm_mode == TX_MODE_SELECT) ? TX_32X32 : cm->txfm_mode;
|
2013-04-10 06:28:27 +02:00
|
|
|
|
|
|
|
if (sz == TX_32X32 && bsize < BLOCK_SIZE_SB32X32)
|
|
|
|
sz = TX_16X16;
|
|
|
|
|
|
|
|
for (y = 0; y < bh; y++) {
|
|
|
|
for (x = 0; x < bw; x++) {
|
2013-01-06 03:20:25 +01:00
|
|
|
if (mb_col + x < cm->mb_cols && mb_row + y < cm->mb_rows) {
|
|
|
|
mi[mis * y + x].mbmi.txfm_size = sz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-08 20:03:00 +01:00
|
|
|
}
|
|
|
|
}
|
2012-08-20 23:43:34 +02:00
|
|
|
}
|