2014-01-24 10:37:15 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
* This file is part of Kvazaar HEVC encoder.
|
2014-02-21 13:00:20 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2013-2014 Tampere University of Technology and others (see
|
2014-01-24 10:37:15 +00:00
|
|
|
* COPYING file).
|
|
|
|
*
|
|
|
|
* Kvazaar is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as published
|
|
|
|
* by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* Kvazaar is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with Kvazaar. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
****************************************************************************/
|
|
|
|
|
2012-06-11 15:43:29 +00:00
|
|
|
/**
|
2013-09-18 14:29:30 +00:00
|
|
|
* \file
|
|
|
|
* \brief Functions for handling intra frames.
|
2012-06-11 15:43:29 +00:00
|
|
|
*/
|
|
|
|
|
2013-09-18 09:16:03 +00:00
|
|
|
#include "intra.h"
|
|
|
|
|
2014-04-17 12:01:43 +00:00
|
|
|
#include <assert.h>
|
2013-03-07 15:42:00 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2013-09-18 09:16:03 +00:00
|
|
|
|
2013-03-07 15:42:00 +00:00
|
|
|
#include "config.h"
|
|
|
|
#include "encoder.h"
|
2014-04-09 12:56:10 +00:00
|
|
|
#include "transform.h"
|
|
|
|
#include "rdo.h"
|
2013-03-07 15:42:00 +00:00
|
|
|
|
2013-03-19 15:12:43 +00:00
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
const uint8_t intra_hor_ver_dist_thres[5] = {0,7,1,0,0};
|
2013-03-19 15:12:43 +00:00
|
|
|
|
2013-04-17 14:08:52 +00:00
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
/**
|
|
|
|
* \brief Set intrablock mode (and init typedata)
|
|
|
|
* \param pic picture to use
|
|
|
|
* \param xCtb x CU position (smallest CU)
|
|
|
|
* \param yCtb y CU position (smallest CU)
|
|
|
|
* \param depth current CU depth
|
|
|
|
* \param mode mode to set
|
|
|
|
* \returns Void
|
|
|
|
*/
|
2014-01-03 11:01:13 +00:00
|
|
|
void intra_set_block_mode(picture *pic,uint32_t x_cu, uint32_t y_cu, uint8_t depth, uint8_t mode, uint8_t part_mode)
|
2013-03-07 15:42:00 +00:00
|
|
|
{
|
2014-02-21 13:00:20 +00:00
|
|
|
uint32_t x, y;
|
2013-09-19 13:21:45 +00:00
|
|
|
int width_in_scu = pic->width_in_lcu<<MAX_DEPTH; //!< Width in smallest CU
|
|
|
|
int block_scu_width = (LCU_WIDTH>>depth)/(LCU_WIDTH>>MAX_DEPTH);
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2014-01-21 18:48:59 +00:00
|
|
|
if (part_mode == SIZE_NxN) {
|
2014-04-28 07:18:22 +00:00
|
|
|
cu_info *cur_cu = &pic->cu_array[x_cu + y_cu * width_in_scu];
|
2014-01-21 18:48:59 +00:00
|
|
|
// Modes are already set.
|
|
|
|
cur_cu->depth = depth;
|
|
|
|
cur_cu->type = CU_INTRA;
|
|
|
|
cur_cu->tr_depth = depth + 1;
|
|
|
|
return;
|
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
|
|
|
|
// Loop through all the blocks in the area of cur_cu
|
|
|
|
for (y = y_cu; y < y_cu + block_scu_width; y++) {
|
|
|
|
for (x = x_cu; x < x_cu + block_scu_width; x++) {
|
2014-04-28 07:18:22 +00:00
|
|
|
cu_info *cur_cu = &pic->cu_array[x + y * width_in_scu];
|
2014-01-21 18:48:59 +00:00
|
|
|
cur_cu->depth = depth;
|
|
|
|
cur_cu->type = CU_INTRA;
|
|
|
|
cur_cu->intra[0].mode = mode;
|
|
|
|
cur_cu->intra[1].mode = mode;
|
|
|
|
cur_cu->intra[2].mode = mode;
|
|
|
|
cur_cu->intra[3].mode = mode;
|
|
|
|
cur_cu->part_size = part_mode;
|
|
|
|
cur_cu->tr_depth = depth;
|
2013-03-07 15:42:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
/**
|
|
|
|
* \brief get intrablock mode
|
|
|
|
* \param pic picture data to use
|
|
|
|
* \param picwidth width of the picture data
|
|
|
|
* \param xpos x-position
|
|
|
|
* \param ypos y-position
|
|
|
|
* \param width block width
|
|
|
|
* \returns DC prediction
|
2013-03-07 15:42:00 +00:00
|
|
|
*/
|
2014-02-14 15:14:35 +00:00
|
|
|
pixel intra_get_dc_pred(pixel *pic, uint16_t picwidth, uint8_t width)
|
2013-03-07 15:42:00 +00:00
|
|
|
{
|
2013-09-19 13:21:45 +00:00
|
|
|
int32_t i, sum = 0;
|
2013-03-14 15:55:06 +00:00
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
// pixels on top and left
|
|
|
|
for (i = -picwidth; i < width - picwidth; i++) {
|
|
|
|
sum += pic[i];
|
|
|
|
}
|
|
|
|
for (i = -1; i < width * picwidth - 1; i += picwidth) {
|
|
|
|
sum += pic[i];
|
2013-03-14 15:55:06 +00:00
|
|
|
}
|
2013-03-08 23:49:42 +00:00
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
// return the average
|
2014-02-14 15:14:35 +00:00
|
|
|
return (pixel)((sum + width) / (width + width));
|
2013-03-07 15:42:00 +00:00
|
|
|
}
|
|
|
|
|
2014-02-21 13:00:20 +00:00
|
|
|
/**
|
2013-09-19 13:21:45 +00:00
|
|
|
* \brief Function for deriving intra luma predictions
|
|
|
|
* \param pic picture to use
|
|
|
|
* \param x_cu x CU position (smallest CU)
|
|
|
|
* \param y_cu y CU position (smallest CU)
|
2014-02-21 13:00:20 +00:00
|
|
|
* \param preds output buffer for 3 predictions
|
2013-09-19 13:21:45 +00:00
|
|
|
* \returns (predictions are found)?1:0
|
|
|
|
*/
|
2014-02-26 12:57:57 +00:00
|
|
|
int8_t intra_get_dir_luma_predictor(uint32_t x, uint32_t y, int8_t* preds,
|
|
|
|
cu_info* cur_cu, cu_info* left_cu, cu_info* above_cu)
|
2013-03-07 15:42:00 +00:00
|
|
|
{
|
2014-02-25 12:16:32 +00:00
|
|
|
int y_cu = y>>3;
|
2014-01-17 15:06:24 +00:00
|
|
|
|
|
|
|
// The default mode if block is not coded yet is INTRA_DC.
|
2014-02-14 15:14:35 +00:00
|
|
|
int8_t left_intra_dir = 1;
|
|
|
|
int8_t above_intra_dir = 1;
|
2014-03-06 16:14:01 +00:00
|
|
|
|
2014-03-11 17:19:20 +00:00
|
|
|
if (x & 4) {
|
2014-01-21 18:48:59 +00:00
|
|
|
// If current CU is NxN and PU is on the right half, take mode from the
|
|
|
|
// left half of the same CU.
|
2014-03-11 17:19:20 +00:00
|
|
|
left_intra_dir = cur_cu->intra[PU_INDEX(0, y >> 2)].mode;
|
2014-01-17 15:06:24 +00:00
|
|
|
} else if (left_cu && left_cu->type == CU_INTRA) {
|
2014-01-21 18:48:59 +00:00
|
|
|
// Otherwise take the mode from the right side of the CU on the left.
|
2014-03-11 17:19:20 +00:00
|
|
|
left_intra_dir = left_cu->intra[PU_INDEX(1, y >> 2)].mode;
|
2014-01-17 15:06:24 +00:00
|
|
|
}
|
|
|
|
|
2014-03-11 17:19:20 +00:00
|
|
|
if (y & 4) {
|
2014-01-21 18:48:59 +00:00
|
|
|
// If current CU is NxN and PU is on the bottom half, take mode from the
|
|
|
|
// top half of the same CU.
|
2014-03-11 17:19:20 +00:00
|
|
|
above_intra_dir = cur_cu->intra[PU_INDEX(x >> 2, 0)].mode;
|
2014-01-21 18:48:59 +00:00
|
|
|
} else if (above_cu && above_cu->type == CU_INTRA &&
|
|
|
|
(y_cu * (LCU_WIDTH>>MAX_DEPTH)) % LCU_WIDTH != 0)
|
2014-01-17 15:06:24 +00:00
|
|
|
{
|
2014-01-21 18:48:59 +00:00
|
|
|
// Otherwise take the mode from the bottom half of the CU above.
|
2014-03-11 17:19:20 +00:00
|
|
|
above_intra_dir = above_cu->intra[PU_INDEX(x >> 2, 1)].mode;
|
2014-01-21 18:48:59 +00:00
|
|
|
}
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
// If the predictions are the same, add new predictions
|
2014-02-21 13:00:20 +00:00
|
|
|
if (left_intra_dir == above_intra_dir) {
|
2013-09-19 13:21:45 +00:00
|
|
|
if (left_intra_dir > 1) { // angular modes
|
|
|
|
preds[0] = left_intra_dir;
|
|
|
|
preds[1] = ((left_intra_dir + 29) % 32) + 2;
|
|
|
|
preds[2] = ((left_intra_dir - 1 ) % 32) + 2;
|
|
|
|
} else { //non-angular
|
2013-03-07 15:42:00 +00:00
|
|
|
preds[0] = 0;//PLANAR_IDX;
|
|
|
|
preds[1] = 1;//DC_IDX;
|
2014-02-21 13:00:20 +00:00
|
|
|
preds[2] = 26;//VER_IDX;
|
2013-03-07 15:42:00 +00:00
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
} else { // If we have two distinct predictions
|
|
|
|
preds[0] = left_intra_dir;
|
|
|
|
preds[1] = above_intra_dir;
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
// add planar mode if it's not yet present
|
|
|
|
if (left_intra_dir && above_intra_dir ) {
|
|
|
|
preds[2] = 0; // PLANAR_IDX;
|
2014-03-11 17:19:20 +00:00
|
|
|
} else { // Add DC mode if it's not present, otherwise 26.
|
2013-09-19 13:21:45 +00:00
|
|
|
preds[2] = (left_intra_dir+above_intra_dir)<2? 26 : 1;
|
2013-03-07 15:42:00 +00:00
|
|
|
}
|
2013-04-17 14:08:52 +00:00
|
|
|
}
|
2013-03-07 15:42:00 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-02-21 13:00:20 +00:00
|
|
|
/**
|
2013-09-19 13:21:45 +00:00
|
|
|
* \brief Intra filtering of the border samples
|
|
|
|
* \param ref reference picture data
|
|
|
|
* \param x_cu x CU position (smallest CU)
|
|
|
|
* \param y_cu y CU position (smallest CU)
|
|
|
|
* \param depth current CU depth
|
2014-02-21 13:00:20 +00:00
|
|
|
* \param preds output buffer for 3 predictions
|
2013-09-19 13:21:45 +00:00
|
|
|
* \returns (predictions are found)?1:0
|
|
|
|
*/
|
2013-10-18 11:23:21 +00:00
|
|
|
void intra_filter(pixel *ref, int32_t stride,int32_t width, int8_t mode)
|
2013-03-19 13:45:50 +00:00
|
|
|
{
|
2013-03-25 15:17:24 +00:00
|
|
|
#define FWIDTH (LCU_WIDTH*2+1)
|
2013-10-18 11:23:21 +00:00
|
|
|
pixel filtered[FWIDTH * FWIDTH]; //!< temporary buffer for filtered samples
|
|
|
|
pixel *filteredShift = &filtered[FWIDTH+1]; //!< pointer to temporary buffer with offset (1,1)
|
2013-03-19 13:45:50 +00:00
|
|
|
int x,y;
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
if (!mode) {
|
|
|
|
// pF[ -1 ][ -1 ] = ( p[ -1 ][ 0 ] + 2*p[ -1 ][ -1 ] + p[ 0 ][ -1 ] + 2 ) >> 2 (8 35)
|
|
|
|
filteredShift[-FWIDTH-1] = (ref[-1] + 2*ref[-(int32_t)stride-1] + ref[-(int32_t)stride] + 2) >> 2;
|
|
|
|
|
|
|
|
// pF[ -1 ][ y ] = ( p[ -1 ][ y + 1 ] + 2*p[ -1 ][ y ] + p[ -1 ][ y - 1 ] + 2 ) >> 2 for y = 0..nTbS * 2 - 2 (8 36)
|
|
|
|
for (y = 0; y < (int32_t)width * 2 - 1; y++) {
|
|
|
|
filteredShift[y*FWIDTH-1] = (ref[(y + 1) * stride - 1] + 2*ref[y * stride - 1] + ref[(y - 1) * stride - 1] + 2) >> 2;
|
2013-03-19 13:45:50 +00:00
|
|
|
}
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
// pF[ -1 ][ nTbS * 2 - 1 ] = p[ -1 ][ nTbS * 2 - 1 ] (8 37)
|
|
|
|
filteredShift[(width * 2 - 1) * FWIDTH - 1] = ref[(width * 2 - 1) * stride - 1];
|
2013-03-19 13:45:50 +00:00
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
// pF[ x ][ -1 ] = ( p[ x - 1 ][ -1 ] + 2*p[ x ][ -1 ] + p[ x + 1 ][ -1 ] + 2 ) >> 2 for x = 0..nTbS * 2 - 2 (8 38)
|
|
|
|
for(x = 0; x < (int32_t)width*2-1; x++) {
|
|
|
|
filteredShift[x - FWIDTH] = (ref[x - 1 - stride] + 2*ref[x - stride] + ref[x + 1 - stride] + 2) >> 2;
|
2013-03-19 13:45:50 +00:00
|
|
|
}
|
|
|
|
|
2014-02-21 13:00:20 +00:00
|
|
|
// pF[ nTbS * 2 - 1 ][ -1 ] = p[ nTbS * 2 - 1 ][ -1 ]
|
2013-09-19 13:21:45 +00:00
|
|
|
filteredShift[(width * 2 - 1) - FWIDTH] = ref[(width * 2 - 1) - stride];
|
2013-03-19 14:23:33 +00:00
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
// Copy filtered samples to the input array
|
|
|
|
for (x = -1; x < (int32_t)width * 2; x++) {
|
|
|
|
ref[x - stride] = filtered[x + 1];
|
2013-03-19 13:45:50 +00:00
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
for(y = 0; y < (int32_t)width * 2; y++) {
|
|
|
|
ref[y * stride - 1] = filtered[(y + 1) * FWIDTH];
|
2013-03-19 13:45:50 +00:00
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
} else {
|
2013-03-19 13:45:50 +00:00
|
|
|
printf("UNHANDLED: %s: %d\r\n", __FILE__, __LINE__);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
#undef FWIDTH
|
|
|
|
}
|
|
|
|
|
2014-03-06 16:14:01 +00:00
|
|
|
/**
|
2014-02-24 13:28:37 +00:00
|
|
|
* \brief Helper function to find intra merge costs
|
|
|
|
* \returns intra mode coding cost in bits
|
|
|
|
*/
|
2014-02-25 12:16:32 +00:00
|
|
|
static uint32_t intra_pred_ratecost(int16_t mode, int8_t *intra_preds)
|
2014-02-24 13:28:37 +00:00
|
|
|
{
|
|
|
|
// merge mode -1 means they are not used -> cost 0
|
2014-02-25 11:32:33 +00:00
|
|
|
if(intra_preds[0] == -1) return 0;
|
2014-02-24 13:28:37 +00:00
|
|
|
|
|
|
|
// First candidate needs only one bit and two other need two
|
2014-02-25 11:32:33 +00:00
|
|
|
if(intra_preds[0] == mode) {
|
2014-03-06 16:14:01 +00:00
|
|
|
return 1;
|
2014-02-25 11:32:33 +00:00
|
|
|
} else if(intra_preds[1] == mode || intra_preds[2] == mode) {
|
2014-02-24 13:28:37 +00:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
// Without merging the cost is 5 bits
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
2014-04-10 08:27:15 +00:00
|
|
|
|
2014-04-09 12:56:10 +00:00
|
|
|
/**
|
|
|
|
* \brief Function to compare RDO costs
|
|
|
|
* \param rdo_costs array of current costs
|
|
|
|
* \param cost new cost to check
|
|
|
|
* \returns -1 if cost is worse than the one in the array or array position for worst cost
|
|
|
|
|
|
|
|
This function derives the prediction samples for planar mode (intra coding).
|
|
|
|
*/
|
2014-04-10 12:20:49 +00:00
|
|
|
static int intra_rdo_cost_compare(uint32_t *rdo_costs,int8_t rdo_modes_to_check, uint32_t cost)
|
2014-04-09 12:56:10 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int found = 0;
|
|
|
|
|
2014-04-10 12:20:49 +00:00
|
|
|
for(i = 0; i < rdo_modes_to_check; i++) {
|
2014-04-09 12:56:10 +00:00
|
|
|
if(rdo_costs[i] > cost) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-04-10 12:20:49 +00:00
|
|
|
// Search for worst cost
|
2014-04-09 12:56:10 +00:00
|
|
|
if(found) {
|
2014-04-10 12:20:49 +00:00
|
|
|
uint32_t worst_cost = 0;
|
|
|
|
int worst_mode = -1;
|
|
|
|
for(i = 0; i < rdo_modes_to_check; i++) {
|
|
|
|
if(rdo_costs[i] > worst_cost) {
|
|
|
|
worst_cost = rdo_costs[i];
|
2014-04-10 13:26:06 +00:00
|
|
|
worst_mode = i;
|
2014-04-10 12:20:49 +00:00
|
|
|
}
|
2014-04-10 13:26:06 +00:00
|
|
|
}
|
2014-04-10 12:20:49 +00:00
|
|
|
return worst_mode;
|
2014-04-09 12:56:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-04-10 08:27:15 +00:00
|
|
|
/**
|
|
|
|
* \param rec Reference pixel. 0 points to unfiltered and 1 to filtered.
|
|
|
|
* \param recstride Stride for rec pixel arrays.
|
2014-04-10 13:26:06 +00:00
|
|
|
* \param dst
|
2014-04-10 08:27:15 +00:00
|
|
|
*/
|
2014-04-17 08:28:20 +00:00
|
|
|
static void intra_get_pred(const encoder_control * const encoder, pixel *rec[2], int recstride, pixel *dst, int width, int mode, int is_chroma)
|
2014-04-10 08:27:15 +00:00
|
|
|
{
|
2014-04-10 08:55:32 +00:00
|
|
|
pixel *ref_pixels = rec[0];
|
|
|
|
if (is_chroma || mode == 1 || width == 4) {
|
|
|
|
// For chroma, DC and 4x4 blocks, always use unfiltered reference.
|
|
|
|
} else if (mode == 0) {
|
|
|
|
// Otherwise, use filtered for planar.
|
|
|
|
ref_pixels = rec[1];
|
|
|
|
} else {
|
|
|
|
// Angular modes use smoothed reference pixels, unless the mode is close
|
|
|
|
// to being either vertical or horizontal.
|
|
|
|
int filter_threshold = intra_hor_ver_dist_thres[g_to_bits[width]];
|
|
|
|
int dist_from_vert_or_hor = MIN(abs(mode - 26), abs(mode - 10));
|
|
|
|
if (dist_from_vert_or_hor > filter_threshold) {
|
|
|
|
ref_pixels = rec[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-10 08:27:15 +00:00
|
|
|
if (mode == 0) {
|
2014-04-10 08:55:32 +00:00
|
|
|
intra_get_planar_pred(ref_pixels, recstride, width, dst, width);
|
2014-04-10 08:27:15 +00:00
|
|
|
} else if (mode == 1) {
|
|
|
|
int i;
|
2014-04-10 08:55:32 +00:00
|
|
|
pixel val = intra_get_dc_pred(ref_pixels, recstride, width);
|
2014-04-10 08:27:15 +00:00
|
|
|
for (i = 0; i < width * width; i++) {
|
|
|
|
dst[i] = val;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int filter_threshold = intra_hor_ver_dist_thres[g_to_bits[width]];
|
|
|
|
int dist_from_vert_or_hor = MIN(abs(mode - 26), abs(mode - 10));
|
2014-04-10 08:55:32 +00:00
|
|
|
int filter = !is_chroma && width < 32;
|
2014-04-10 08:27:15 +00:00
|
|
|
if (dist_from_vert_or_hor <= filter_threshold) {
|
2014-04-17 08:28:20 +00:00
|
|
|
intra_get_angular_pred(encoder, ref_pixels, recstride, dst, width, width, mode, filter);
|
2014-04-10 08:27:15 +00:00
|
|
|
} else {
|
2014-04-17 08:28:20 +00:00
|
|
|
intra_get_angular_pred(encoder, ref_pixels, recstride, dst, width, width, mode, filter);
|
2014-04-10 08:27:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
/**
|
|
|
|
* \brief Function to test best intra prediction mode
|
|
|
|
* \param orig original picture data
|
|
|
|
* \param origstride original picture stride
|
|
|
|
* \param rec reconstructed picture data
|
|
|
|
* \param recstride reconstructed picture stride
|
|
|
|
* \param xpos source x-position
|
|
|
|
* \param ypos source y-position
|
|
|
|
* \param width block size to predict
|
|
|
|
* \param sad_out sad value of best mode
|
|
|
|
* \returns best intra mode
|
2013-03-12 15:06:21 +00:00
|
|
|
*/
|
2014-04-22 09:46:53 +00:00
|
|
|
int16_t intra_prediction(encoder_state * const encoder_state, pixel *orig, int32_t origstride, pixel *rec, int16_t recstride,
|
2014-04-09 14:12:28 +00:00
|
|
|
uint8_t width, uint32_t *sad_out,
|
2014-04-22 09:46:53 +00:00
|
|
|
int8_t *intra_preds, uint32_t *bitcost_out)
|
2013-03-12 15:06:21 +00:00
|
|
|
{
|
2013-09-19 13:21:45 +00:00
|
|
|
uint32_t best_sad = 0xffffffff;
|
|
|
|
uint32_t sad = 0;
|
|
|
|
int16_t best_mode = 1;
|
2014-03-11 10:15:50 +00:00
|
|
|
uint32_t best_bitcost = 0;
|
2014-04-09 14:12:28 +00:00
|
|
|
int16_t mode;
|
2014-04-17 12:42:20 +00:00
|
|
|
int8_t rdo = encoder_state->encoder_control->rdo;
|
2013-10-16 12:08:53 +00:00
|
|
|
|
2014-04-10 12:20:49 +00:00
|
|
|
// Check 8 modes for 4x4 and 8x8, 3 for others
|
|
|
|
int8_t rdo_modes_to_check = (width == 4 || width == 8)? 8 : 3;
|
2014-04-10 12:59:36 +00:00
|
|
|
int8_t rdo_modes[11] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
|
|
|
uint32_t rdo_costs[11] = {UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX,
|
|
|
|
UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX,
|
|
|
|
UINT_MAX, UINT_MAX, UINT_MAX};
|
2014-04-09 12:56:10 +00:00
|
|
|
|
2013-10-21 14:42:55 +00:00
|
|
|
cost_16bit_nxn_func cost_func = get_sad_16bit_nxn_func(width);
|
2013-09-19 13:21:45 +00:00
|
|
|
|
|
|
|
// Temporary block arrays
|
2014-02-21 13:00:20 +00:00
|
|
|
pixel pred[LCU_WIDTH * LCU_WIDTH + 1];
|
|
|
|
pixel orig_block[LCU_WIDTH * LCU_WIDTH + 1];
|
2013-10-18 11:23:21 +00:00
|
|
|
pixel rec_filtered_temp[(LCU_WIDTH * 2 + 8) * (LCU_WIDTH * 2 + 8) + 1];
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2014-04-10 08:27:15 +00:00
|
|
|
pixel *ref[2] = {rec, &rec_filtered_temp[recstride + 1]};
|
2013-09-19 13:21:45 +00:00
|
|
|
|
|
|
|
// Store original block for SAD computation
|
2014-04-09 14:12:28 +00:00
|
|
|
picture_blit_pixels(orig, orig_block, width, width, origstride, width);
|
2013-05-16 12:27:54 +00:00
|
|
|
|
2014-04-09 14:12:28 +00:00
|
|
|
// Generate filtered reference pixels.
|
2014-02-14 15:14:35 +00:00
|
|
|
{
|
2014-04-09 14:12:28 +00:00
|
|
|
int16_t x, y;
|
|
|
|
for (y = -1; y < recstride; y++) {
|
2014-04-10 08:27:15 +00:00
|
|
|
ref[1][y*recstride - 1] = rec[y*recstride - 1];
|
2014-04-10 09:36:49 +00:00
|
|
|
}
|
2014-04-09 14:12:28 +00:00
|
|
|
for (x = 0; x < recstride; x++) {
|
2014-04-10 08:27:15 +00:00
|
|
|
ref[1][x - recstride] = rec[x - recstride];
|
2013-03-19 13:45:50 +00:00
|
|
|
}
|
2014-04-10 08:27:15 +00:00
|
|
|
intra_filter(ref[1], recstride, width, 0);
|
2013-08-02 13:35:30 +00:00
|
|
|
}
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2014-04-09 14:12:28 +00:00
|
|
|
// Try all modes and select the best one.
|
|
|
|
for (mode = 0; mode < 35; mode++) {
|
2014-04-10 09:36:49 +00:00
|
|
|
uint32_t mode_cost = intra_pred_ratecost(mode, intra_preds);
|
2014-04-17 12:42:20 +00:00
|
|
|
intra_get_pred(encoder_state->encoder_control, ref, recstride, pred, width, mode, 0);
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2014-04-10 09:36:49 +00:00
|
|
|
sad = cost_func(pred, orig_block);
|
2014-05-06 08:13:18 +00:00
|
|
|
sad += mode_cost * (int)(encoder_state->global->cur_lambda_cost + 0.5);
|
2014-04-10 12:20:49 +00:00
|
|
|
// When rdo == 2, store best costs to an array and do full RDO later
|
2014-04-17 12:42:20 +00:00
|
|
|
if(rdo == 2) {
|
2014-04-10 12:20:49 +00:00
|
|
|
int rdo_mode = intra_rdo_cost_compare(rdo_costs, rdo_modes_to_check, sad);
|
2014-04-10 09:36:49 +00:00
|
|
|
if(rdo_mode != -1) {
|
|
|
|
rdo_modes[rdo_mode] = mode; rdo_costs[rdo_mode] = sad;
|
|
|
|
}
|
2014-04-10 12:20:49 +00:00
|
|
|
// Without rdo compare costs
|
|
|
|
} else if (sad < best_sad) {
|
2014-04-10 09:36:49 +00:00
|
|
|
best_bitcost = mode_cost;
|
|
|
|
best_sad = sad;
|
|
|
|
best_mode = mode;
|
2014-04-10 13:26:06 +00:00
|
|
|
}
|
2013-04-04 12:08:28 +00:00
|
|
|
}
|
|
|
|
|
2014-04-09 12:56:10 +00:00
|
|
|
// Select from three best modes if using RDO
|
2014-04-17 12:42:20 +00:00
|
|
|
if(rdo == 2) {
|
2014-04-09 12:56:10 +00:00
|
|
|
int rdo_mode;
|
2014-04-10 12:59:36 +00:00
|
|
|
int pred_mode;
|
|
|
|
// Check that the predicted modes are in the RDO mode list
|
|
|
|
for(pred_mode = 0; pred_mode < 3; pred_mode++) {
|
|
|
|
int mode_found = 0;
|
|
|
|
for(rdo_mode = 0; rdo_mode < rdo_modes_to_check; rdo_mode ++) {
|
|
|
|
if(intra_preds[pred_mode] == rdo_modes[rdo_mode]) {
|
|
|
|
mode_found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Add this prediction mode to RDO checking
|
|
|
|
if(!mode_found) {
|
|
|
|
rdo_modes[rdo_modes_to_check] = intra_preds[pred_mode];
|
|
|
|
rdo_modes_to_check++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-09 12:56:10 +00:00
|
|
|
best_sad = UINT_MAX;
|
2014-04-10 12:20:49 +00:00
|
|
|
for(rdo_mode = 0; rdo_mode < rdo_modes_to_check; rdo_mode ++) {
|
2014-04-10 13:26:06 +00:00
|
|
|
int rdo_bitcost;
|
2014-04-09 12:56:10 +00:00
|
|
|
// The reconstruction is calculated again here, it could be saved from before..
|
2014-04-17 12:42:20 +00:00
|
|
|
intra_recon(encoder_state->encoder_control, rec, recstride, width, pred, width, rdo_modes[rdo_mode], 0);
|
2014-04-22 09:46:53 +00:00
|
|
|
rdo_costs[rdo_mode] = rdo_cost_intra(encoder_state,pred,orig_block,width,rdo_modes[rdo_mode]);
|
2014-04-10 13:26:06 +00:00
|
|
|
// Bitcost also calculated again for this mode
|
|
|
|
rdo_bitcost = intra_pred_ratecost(rdo_modes[rdo_mode],intra_preds);
|
|
|
|
// Add bitcost * lambda
|
2014-05-06 08:13:18 +00:00
|
|
|
rdo_costs[rdo_mode] += rdo_bitcost * (int)(encoder_state->global->cur_lambda_cost + 0.5);
|
2014-04-10 13:26:06 +00:00
|
|
|
|
2014-04-09 12:56:10 +00:00
|
|
|
if(rdo_costs[rdo_mode] < best_sad) {
|
|
|
|
best_sad = rdo_costs[rdo_mode];
|
2014-04-10 13:26:06 +00:00
|
|
|
best_bitcost = rdo_bitcost;
|
2014-04-09 12:56:10 +00:00
|
|
|
best_mode = rdo_modes[rdo_mode];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
// assign final sad to output
|
2014-03-11 10:15:50 +00:00
|
|
|
*sad_out = best_sad;
|
|
|
|
*bitcost_out = best_bitcost;
|
2013-09-19 13:21:45 +00:00
|
|
|
|
|
|
|
return best_mode;
|
2013-03-13 13:56:43 +00:00
|
|
|
}
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
/**
|
|
|
|
* \brief Reconstruct intra block according to prediction
|
|
|
|
* \param rec reconstructed picture data
|
|
|
|
* \param recstride reconstructed picture stride
|
|
|
|
* \param width block size to predict
|
|
|
|
* \param dst destination buffer for best prediction
|
|
|
|
* \param dststride destination width
|
|
|
|
* \param mode intra mode to use
|
|
|
|
* \param chroma chroma-block flag
|
|
|
|
|
|
|
|
*/
|
2014-04-17 08:28:20 +00:00
|
|
|
void intra_recon(const encoder_control * const encoder, pixel* rec, int32_t recstride, uint32_t width, pixel* dst, int32_t dststride, int8_t mode, int8_t chroma)
|
2013-03-13 13:56:43 +00:00
|
|
|
{
|
2013-10-18 11:23:21 +00:00
|
|
|
pixel pred[LCU_WIDTH * LCU_WIDTH];
|
2014-04-10 08:55:32 +00:00
|
|
|
pixel rec_filtered_temp[(LCU_WIDTH * 2 + 8) * (LCU_WIDTH * 2 + 8) + 1];
|
|
|
|
pixel *ref[2] = {rec, &rec_filtered_temp[recstride + 1]};
|
2013-09-19 13:21:45 +00:00
|
|
|
|
2014-04-10 08:55:32 +00:00
|
|
|
// Generate filtered reference pixels.
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
for (y = -1; y < recstride; y++) {
|
|
|
|
ref[1][y*recstride - 1] = rec[y*recstride - 1];
|
2013-03-19 15:12:43 +00:00
|
|
|
}
|
2014-04-10 08:55:32 +00:00
|
|
|
for (x = 0; x < recstride; x++) {
|
|
|
|
ref[1][x - recstride] = rec[x - recstride];
|
2014-04-10 12:23:32 +00:00
|
|
|
}
|
2014-04-10 09:36:49 +00:00
|
|
|
intra_filter(ref[1], recstride, width, 0);
|
2014-04-10 12:23:32 +00:00
|
|
|
}
|
2013-03-13 13:56:43 +00:00
|
|
|
|
2014-04-17 08:28:20 +00:00
|
|
|
intra_get_pred(encoder, ref, recstride, pred, width, mode, chroma);
|
2014-04-10 08:55:32 +00:00
|
|
|
|
|
|
|
picture_blit_pixels(pred, dst, width, width, width, dststride);
|
2014-04-10 12:23:32 +00:00
|
|
|
}
|
2013-03-13 13:56:43 +00:00
|
|
|
|
2014-02-21 13:00:20 +00:00
|
|
|
/**
|
2014-01-22 13:57:19 +00:00
|
|
|
* \brief Build top and left borders for a reference block.
|
|
|
|
* \param pic picture to use as a source
|
2013-09-19 13:21:45 +00:00
|
|
|
* \param outwidth width of the prediction block
|
2014-02-21 13:00:20 +00:00
|
|
|
* \param chroma signaling if chroma is used, 0 = luma, 1 = U and 2 = V
|
2013-09-19 13:21:45 +00:00
|
|
|
*
|
2014-01-21 18:48:59 +00:00
|
|
|
* The end result is 2*width+8 x 2*width+8 array, with only the top and left
|
|
|
|
* edge pixels filled with the reconstructed pixels.
|
2013-09-19 13:21:45 +00:00
|
|
|
*/
|
2014-04-17 08:28:20 +00:00
|
|
|
void intra_build_reference_border(const encoder_control * const encoder, int32_t x_luma, int32_t y_luma, int16_t out_width,
|
2014-02-25 11:26:54 +00:00
|
|
|
pixel *dst, int32_t dst_stride, int8_t chroma,
|
|
|
|
int32_t pic_width, int32_t pic_height,
|
|
|
|
lcu_t *lcu)
|
2013-03-14 15:55:06 +00:00
|
|
|
{
|
2014-01-22 13:57:19 +00:00
|
|
|
// Some other function might make use of the arrays num_ref_pixels_top and
|
|
|
|
// num_ref_pixels_left in the future, but until that happens lets leave
|
|
|
|
// them here.
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Table for looking up the number of intra reference pixels based on
|
|
|
|
* prediction units coordinate within an LCU.
|
|
|
|
*
|
|
|
|
* This table was generated by "tools/generate_ref_pixel_tables.py".
|
|
|
|
*/
|
|
|
|
static const uint8_t num_ref_pixels_top[16][16] = {
|
|
|
|
{ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 },
|
|
|
|
{ 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 16, 12, 8, 4, 16, 12, 8, 4, 16, 12, 8, 4, 16, 12, 8, 4 },
|
|
|
|
{ 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 32, 28, 24, 20, 16, 12, 8, 4, 32, 28, 24, 20, 16, 12, 8, 4 },
|
|
|
|
{ 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 16, 12, 8, 4, 16, 12, 8, 4, 16, 12, 8, 4, 16, 12, 8, 4 },
|
|
|
|
{ 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 64, 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4 },
|
|
|
|
{ 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 16, 12, 8, 4, 16, 12, 8, 4, 16, 12, 8, 4, 16, 12, 8, 4 },
|
|
|
|
{ 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 32, 28, 24, 20, 16, 12, 8, 4, 32, 28, 24, 20, 16, 12, 8, 4 },
|
|
|
|
{ 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 16, 12, 8, 4, 16, 12, 8, 4, 16, 12, 8, 4, 16, 12, 8, 4 },
|
|
|
|
{ 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 }
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Table for looking up the number of intra reference pixels based on
|
|
|
|
* prediction units coordinate within an LCU.
|
|
|
|
*
|
|
|
|
* This table was generated by "tools/generate_ref_pixel_tables.py".
|
|
|
|
*/
|
|
|
|
static const uint8_t num_ref_pixels_left[16][16] = {
|
|
|
|
{ 64, 4, 8, 4, 16, 4, 8, 4, 32, 4, 8, 4, 16, 4, 8, 4 },
|
|
|
|
{ 64, 4, 4, 4, 12, 4, 4, 4, 28, 4, 4, 4, 12, 4, 4, 4 },
|
|
|
|
{ 64, 4, 8, 4, 8, 4, 8, 4, 24, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 64, 4, 4, 4, 4, 4, 4, 4, 20, 4, 4, 4, 4, 4, 4, 4 },
|
|
|
|
{ 64, 4, 8, 4, 16, 4, 8, 4, 16, 4, 8, 4, 16, 4, 8, 4 },
|
|
|
|
{ 64, 4, 4, 4, 12, 4, 4, 4, 12, 4, 4, 4, 12, 4, 4, 4 },
|
|
|
|
{ 64, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 },
|
|
|
|
{ 64, 4, 8, 4, 16, 4, 8, 4, 32, 4, 8, 4, 16, 4, 8, 4 },
|
|
|
|
{ 64, 4, 4, 4, 12, 4, 4, 4, 28, 4, 4, 4, 12, 4, 4, 4 },
|
|
|
|
{ 64, 4, 8, 4, 8, 4, 8, 4, 24, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 64, 4, 4, 4, 4, 4, 4, 4, 20, 4, 4, 4, 4, 4, 4, 4 },
|
|
|
|
{ 64, 4, 8, 4, 16, 4, 8, 4, 16, 4, 8, 4, 16, 4, 8, 4 },
|
|
|
|
{ 64, 4, 4, 4, 12, 4, 4, 4, 12, 4, 4, 4, 12, 4, 4, 4 },
|
|
|
|
{ 64, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 },
|
|
|
|
{ 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }
|
|
|
|
};
|
|
|
|
|
2014-04-17 08:28:20 +00:00
|
|
|
const pixel dc_val = 1 << (encoder->bitdepth - 1);
|
2014-01-22 13:57:19 +00:00
|
|
|
const int is_chroma = chroma ? 1 : 0;
|
|
|
|
|
|
|
|
// input picture pointer
|
2014-02-03 16:21:57 +00:00
|
|
|
//const pixel * const src = (!chroma) ? pic->y_recdata : ((chroma == 1) ? pic->u_recdata : pic->v_recdata);
|
2014-01-22 13:57:19 +00:00
|
|
|
|
|
|
|
// Convert luma coordinates to chroma coordinates for chroma.
|
|
|
|
const int x = chroma ? x_luma / 2 : x_luma;
|
|
|
|
const int y = chroma ? y_luma / 2 : y_luma;
|
|
|
|
|
|
|
|
const int y_in_lcu = y_luma % LCU_WIDTH;
|
|
|
|
const int x_in_lcu = x_luma % LCU_WIDTH;
|
|
|
|
|
2014-02-28 13:24:47 +00:00
|
|
|
int x_local = (x_luma&0x3f)>>is_chroma, y_local = (y_luma&0x3f)>>is_chroma;
|
2014-02-25 11:26:54 +00:00
|
|
|
|
2014-02-28 13:24:47 +00:00
|
|
|
pixel *left_ref = !chroma ? &lcu->left_ref.y[1] : (chroma == 1) ? &lcu->left_ref.u[1] : &lcu->left_ref.v[1];
|
|
|
|
pixel *top_ref = !chroma ? &lcu->top_ref.y[1] : (chroma == 1) ? &lcu->top_ref.u[1] : &lcu->top_ref.v[1];
|
|
|
|
pixel *rec_ref = !chroma ? lcu->rec.y : (chroma == 1) ? lcu->rec.u : lcu->rec.v;
|
2014-02-25 11:26:54 +00:00
|
|
|
|
2014-02-28 13:24:47 +00:00
|
|
|
pixel *left_border = &left_ref[y_local];
|
|
|
|
pixel *top_border = &top_ref[x_local];
|
2014-02-25 11:26:54 +00:00
|
|
|
uint32_t left_stride = 1;
|
|
|
|
|
|
|
|
if(x_local) {
|
2014-02-28 13:24:47 +00:00
|
|
|
left_border = &rec_ref[x_local - 1 + y_local * (LCU_WIDTH>>is_chroma)];
|
|
|
|
left_stride = LCU_WIDTH>>is_chroma;
|
2014-02-25 11:26:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(y_local) {
|
2014-02-28 13:24:47 +00:00
|
|
|
top_border = &rec_ref[x_local + (y_local - 1) * (LCU_WIDTH>>is_chroma)];
|
2014-02-25 11:26:54 +00:00
|
|
|
}
|
|
|
|
|
2014-01-22 13:57:19 +00:00
|
|
|
// Copy pixels for left edge.
|
|
|
|
if (x > 0) {
|
|
|
|
// Get the number of reference pixels based on the PU coordinate within the LCU.
|
|
|
|
int num_ref_pixels = num_ref_pixels_left[y_in_lcu / 4][x_in_lcu / 4] >> is_chroma;
|
|
|
|
int i;
|
|
|
|
pixel nearest_pixel;
|
|
|
|
|
|
|
|
// Max pixel we can copy from src is yy + outwidth - 1 because the dst
|
|
|
|
// extends one pixel to the left.
|
2014-02-25 11:26:54 +00:00
|
|
|
num_ref_pixels = MIN(num_ref_pixels, out_width - 1);
|
2014-02-10 12:41:06 +00:00
|
|
|
// There are no coded pixels below the frame.
|
2014-02-25 11:26:54 +00:00
|
|
|
num_ref_pixels = MIN(num_ref_pixels, pic_height - y);
|
2014-02-10 12:41:06 +00:00
|
|
|
// There are no coded pixels below the bottom of the LCU due to raster
|
|
|
|
// scan order.
|
|
|
|
num_ref_pixels = MIN(num_ref_pixels, (LCU_WIDTH - y_in_lcu) >> is_chroma);
|
2014-01-22 13:57:19 +00:00
|
|
|
|
2014-01-21 18:48:59 +00:00
|
|
|
// Copy pixels from coded CUs.
|
2014-01-22 13:57:19 +00:00
|
|
|
for (i = 0; i < num_ref_pixels; ++i) {
|
2014-02-25 11:26:54 +00:00
|
|
|
dst[(i + 1) * dst_stride] = left_border[i*left_stride];
|
2013-03-14 15:55:06 +00:00
|
|
|
}
|
2014-01-22 13:57:19 +00:00
|
|
|
// Extend the last pixel for the rest of the reference values.
|
2014-02-25 11:26:54 +00:00
|
|
|
nearest_pixel = dst[i * dst_stride];
|
|
|
|
for (i = num_ref_pixels; i < out_width - 1; ++i) {
|
|
|
|
dst[i * dst_stride] = nearest_pixel;
|
2014-01-22 13:57:19 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If we are on the left edge, extend the first pixel of the top row.
|
2014-02-28 12:21:50 +00:00
|
|
|
pixel nearest_pixel = y > 0 ? top_border[0] : dc_val;
|
2014-01-22 13:57:19 +00:00
|
|
|
int i;
|
2014-02-25 11:26:54 +00:00
|
|
|
for (i = 1; i < out_width - 1; i++) {
|
|
|
|
dst[i * dst_stride] = nearest_pixel;
|
2013-03-14 15:55:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-22 13:57:19 +00:00
|
|
|
// Copy pixels for top edge.
|
|
|
|
if (y > 0) {
|
|
|
|
// Get the number of reference pixels based on the PU coordinate within the LCU.
|
|
|
|
int num_ref_pixels = num_ref_pixels_top[y_in_lcu / 4][x_in_lcu / 4] >> is_chroma;
|
|
|
|
int i;
|
|
|
|
pixel nearest_pixel;
|
|
|
|
|
|
|
|
// Max pixel we can copy from src is yy + outwidth - 1 because the dst
|
|
|
|
// extends one pixel to the left.
|
2014-02-25 11:26:54 +00:00
|
|
|
num_ref_pixels = MIN(num_ref_pixels, out_width - 1);
|
2014-01-22 13:57:19 +00:00
|
|
|
// All LCUs in the row above have been coded.
|
2014-02-25 11:26:54 +00:00
|
|
|
num_ref_pixels = MIN(num_ref_pixels, pic_width - x);
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2014-01-22 13:57:19 +00:00
|
|
|
// Copy pixels from coded CUs.
|
|
|
|
for (i = 0; i < num_ref_pixels; ++i) {
|
2014-02-25 11:26:54 +00:00
|
|
|
dst[i + 1] = top_border[i];
|
2013-03-14 15:55:06 +00:00
|
|
|
}
|
2014-01-22 13:57:19 +00:00
|
|
|
// Extend the last pixel for the rest of the reference values.
|
2014-02-25 11:26:54 +00:00
|
|
|
nearest_pixel = top_border[num_ref_pixels - 1];
|
|
|
|
for (; i < out_width - 1; ++i) {
|
2014-01-22 13:57:19 +00:00
|
|
|
dst[i + 1] = nearest_pixel;
|
2013-03-14 15:55:06 +00:00
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
} else {
|
2014-01-22 13:57:19 +00:00
|
|
|
// Extend nearest pixel.
|
2014-02-28 12:21:50 +00:00
|
|
|
pixel nearest_pixel = x > 0 ? left_border[0] : dc_val;
|
2014-01-22 13:57:19 +00:00
|
|
|
int i;
|
2014-02-25 11:26:54 +00:00
|
|
|
for(i = 1; i < out_width; i++)
|
2013-03-14 15:55:06 +00:00
|
|
|
{
|
2014-01-22 13:57:19 +00:00
|
|
|
dst[i] = nearest_pixel;
|
2013-03-14 15:55:06 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
|
2014-01-23 14:44:42 +00:00
|
|
|
// If top-left corner sample doesn't exist, use the sample from below.
|
|
|
|
// Unavailable samples on the left boundary are copied from below if
|
|
|
|
// available. This is the only place they are available because we don't
|
|
|
|
// support constrained intra prediction.
|
2014-02-28 13:27:25 +00:00
|
|
|
if (x > 0 && y > 0) {
|
|
|
|
// Make sure we always take the top-left pixel from the LCU reference
|
|
|
|
// pixel arrays if they are available.
|
|
|
|
if (x_local == 0) {
|
|
|
|
dst[0] = left_border[-1];
|
|
|
|
} else {
|
|
|
|
dst[0] = top_border[-1];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dst[0] = dst[dst_stride];
|
|
|
|
}
|
2013-03-14 15:55:06 +00:00
|
|
|
}
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
const int32_t ang_table[9] = {0, 2, 5, 9, 13, 17, 21, 26, 32};
|
|
|
|
const int32_t inv_ang_table[9] = {0, 4096, 1638, 910, 630, 482, 390, 315, 256}; // (256 * 32) / Angle
|
2013-05-20 14:26:57 +00:00
|
|
|
|
2014-02-21 13:00:20 +00:00
|
|
|
/**
|
2013-09-19 13:21:45 +00:00
|
|
|
* \brief this functions constructs the angular intra prediction from border samples
|
|
|
|
*
|
|
|
|
*/
|
2014-04-17 08:28:20 +00:00
|
|
|
void intra_get_angular_pred(const encoder_control * const encoder, pixel* src, int32_t src_stride, pixel* dst, int32_t dst_stride, int32_t width, int32_t dir_mode, int8_t filter)
|
2013-03-13 13:56:43 +00:00
|
|
|
{
|
|
|
|
int32_t k,l;
|
2013-09-19 13:21:45 +00:00
|
|
|
int32_t blk_size = width;
|
2013-03-13 13:56:43 +00:00
|
|
|
|
|
|
|
// Map the mode index to main prediction direction and angle
|
2013-09-19 13:21:45 +00:00
|
|
|
int8_t mode_hor = dir_mode < 18;
|
|
|
|
int8_t mode_ver = !mode_hor;
|
|
|
|
int32_t intra_pred_angle = mode_ver ? (int32_t)dir_mode - 26 : mode_hor ? -((int32_t)dir_mode - 10) : 0;
|
|
|
|
int32_t abs_ang = abs(intra_pred_angle);
|
|
|
|
int32_t sign_ang = intra_pred_angle < 0 ? -1 : 1;
|
2013-03-13 13:56:43 +00:00
|
|
|
|
|
|
|
// Set bitshifts and scale the angle parameter to block size
|
2013-09-19 13:21:45 +00:00
|
|
|
int32_t inv_angle = inv_ang_table[abs_ang];
|
2013-03-13 13:56:43 +00:00
|
|
|
|
|
|
|
// Do angular predictions
|
2013-10-18 11:23:21 +00:00
|
|
|
pixel *ref_main;
|
|
|
|
pixel *ref_side;
|
|
|
|
pixel ref_above[2 * LCU_WIDTH + 1];
|
|
|
|
pixel ref_left[2 * LCU_WIDTH + 1];
|
2013-03-13 13:56:43 +00:00
|
|
|
|
2014-04-17 12:01:43 +00:00
|
|
|
// Tell clang-analyzer that everything is ok.
|
|
|
|
assert(width == 4 || width == 8 || width == 16 || width == 32);
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
abs_ang = ang_table[abs_ang];
|
|
|
|
intra_pred_angle = sign_ang * abs_ang;
|
2013-03-13 13:56:43 +00:00
|
|
|
|
|
|
|
// Initialise the Main and Left reference array.
|
2013-09-19 13:21:45 +00:00
|
|
|
if (intra_pred_angle < 0) {
|
|
|
|
int32_t invAngleSum = 128; // rounding for (shift by 8)
|
|
|
|
for (k = 0; k < blk_size + 1; k++) {
|
|
|
|
ref_above[k + blk_size - 1] = src[k - src_stride - 1];
|
|
|
|
ref_left[k + blk_size - 1] = src[(k - 1) * src_stride - 1];
|
2013-03-13 13:56:43 +00:00
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
|
|
|
|
ref_main = (mode_ver ? ref_above : ref_left) + (blk_size - 1);
|
|
|
|
ref_side = (mode_ver ? ref_left : ref_above) + (blk_size - 1);
|
2013-03-13 13:56:43 +00:00
|
|
|
|
2014-02-21 13:00:20 +00:00
|
|
|
// Extend the Main reference to the left.
|
2014-02-21 13:52:10 +00:00
|
|
|
for (k = -1; k > blk_size * intra_pred_angle>>5; k--) {
|
2013-09-19 13:21:45 +00:00
|
|
|
invAngleSum += inv_angle;
|
|
|
|
ref_main[k] = ref_side[invAngleSum>>8];
|
2013-03-13 13:56:43 +00:00
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
} else {
|
|
|
|
for (k = 0; k < 2 * blk_size + 1; k++) {
|
|
|
|
ref_above[k] = src[k - src_stride - 1];
|
|
|
|
ref_left[k] = src[(k - 1) * src_stride - 1];
|
2013-03-13 13:56:43 +00:00
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
ref_main = mode_ver ? ref_above : ref_left;
|
|
|
|
ref_side = mode_ver ? ref_left : ref_above;
|
2013-03-13 13:56:43 +00:00
|
|
|
}
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
if (intra_pred_angle == 0) {
|
|
|
|
for (k = 0; k < blk_size; k++) {
|
|
|
|
for (l = 0; l < blk_size; l++) {
|
|
|
|
dst[k * dst_stride + l] = ref_main[l + 1];
|
2013-03-13 13:56:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
if (filter) {
|
|
|
|
for (k=0;k<blk_size;k++) {
|
2014-04-17 08:28:20 +00:00
|
|
|
dst[k * dst_stride] = CLIP(0, (1<<encoder->bitdepth) - 1, dst[k * dst_stride] + (( ref_side[k + 1] - ref_side[0]) >> 1));
|
2013-03-13 13:56:43 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
} else {
|
|
|
|
int32_t delta_pos=0;
|
|
|
|
int32_t delta_int;
|
|
|
|
int32_t delta_fract;
|
|
|
|
int32_t minus_delta_fract;
|
|
|
|
int32_t ref_main_index;
|
|
|
|
for (k = 0; k < blk_size; k++) {
|
|
|
|
delta_pos += intra_pred_angle;
|
|
|
|
delta_int = delta_pos >> 5;
|
|
|
|
delta_fract = delta_pos & (32 - 1);
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2013-03-13 13:56:43 +00:00
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
if (delta_fract) {
|
|
|
|
minus_delta_fract = (32 - delta_fract);
|
2013-03-13 13:56:43 +00:00
|
|
|
// Do linear filtering
|
2013-09-19 13:21:45 +00:00
|
|
|
for (l = 0; l < blk_size; l++) {
|
|
|
|
ref_main_index = l + delta_int + 1;
|
2013-10-18 11:23:21 +00:00
|
|
|
dst[k * dst_stride + l] = (pixel) ( (minus_delta_fract * ref_main[ref_main_index]
|
2013-09-19 13:21:45 +00:00
|
|
|
+ delta_fract * ref_main[ref_main_index + 1] + 16) >> 5);
|
2013-03-13 13:56:43 +00:00
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
} else {
|
2013-03-13 13:56:43 +00:00
|
|
|
// Just copy the integer samples
|
2013-09-19 13:21:45 +00:00
|
|
|
for (l = 0; l < blk_size; l++) {
|
|
|
|
dst[k * dst_stride + l] = ref_main[l + delta_int + 1];
|
2013-03-13 13:56:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flip the block if this is the horizontal mode
|
2013-09-19 13:21:45 +00:00
|
|
|
if (mode_hor) {
|
2013-10-18 11:23:21 +00:00
|
|
|
pixel tmp;
|
2013-09-19 13:21:45 +00:00
|
|
|
for (k=0;k<blk_size-1;k++) {
|
|
|
|
for (l=k+1;l<blk_size;l++) {
|
|
|
|
tmp = dst[k * dst_stride + l];
|
|
|
|
dst[k * dst_stride + l] = dst[l * dst_stride + k];
|
|
|
|
dst[l * dst_stride + k] = tmp;
|
2013-03-13 13:56:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-12 15:06:21 +00:00
|
|
|
}
|
2013-03-11 14:26:09 +00:00
|
|
|
|
2013-03-13 13:56:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2013-10-18 11:23:21 +00:00
|
|
|
void intra_dc_pred_filtering(pixel *src, int32_t src_stride, pixel *dst, int32_t dst_stride, int32_t width, int32_t height )
|
2013-03-11 14:26:09 +00:00
|
|
|
{
|
2013-09-19 13:21:45 +00:00
|
|
|
int32_t x, y, dst_stride2, src_stride2;
|
2013-03-11 14:26:09 +00:00
|
|
|
|
|
|
|
// boundary pixels processing
|
2013-09-19 13:21:45 +00:00
|
|
|
dst[0] = ((src[-src_stride] + src[-1] + 2 * dst[0] + 2) >> 2);
|
2013-03-11 14:26:09 +00:00
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
for (x = 1; x < width; x++) {
|
|
|
|
dst[x] = ((src[x - src_stride] + 3 * dst[x] + 2) >> 2);
|
2013-03-11 14:26:09 +00:00
|
|
|
}
|
2013-09-19 13:21:45 +00:00
|
|
|
for ( y = 1, dst_stride2 = dst_stride, src_stride2 = src_stride-1;
|
|
|
|
y < height; y++, dst_stride2+=dst_stride, src_stride2+=src_stride ) {
|
|
|
|
dst[dst_stride2] = ((src[src_stride2] + 3 * dst[dst_stride2] + 2) >> 2);
|
2013-03-11 14:26:09 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-19 13:21:45 +00:00
|
|
|
/**
|
|
|
|
* \brief Function for deriving planar intra prediction.
|
|
|
|
* \param src source pixel array
|
|
|
|
* \param srcstride source width
|
|
|
|
* \param width block size to predict
|
|
|
|
* \param dst destination buffer for prediction
|
|
|
|
* \param dststride destination width
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2013-03-07 15:42:00 +00:00
|
|
|
This function derives the prediction samples for planar mode (intra coding).
|
|
|
|
*/
|
2014-02-14 15:14:35 +00:00
|
|
|
void intra_get_planar_pred(pixel* src, int32_t srcstride, uint32_t width, pixel* dst, int32_t dststride)
|
2013-03-07 15:42:00 +00:00
|
|
|
{
|
2013-09-19 13:21:45 +00:00
|
|
|
int32_t k, l, bottom_left, top_right;
|
|
|
|
int32_t hor_pred;
|
|
|
|
int32_t left_column[LCU_WIDTH+1], top_row[LCU_WIDTH+1], bottom_row[LCU_WIDTH+1], right_column[LCU_WIDTH+1];
|
|
|
|
uint32_t blk_size = width;
|
|
|
|
uint32_t offset_2d = width;
|
|
|
|
uint32_t shift_1d = g_convert_to_bit[ width ] + 2;
|
|
|
|
uint32_t shift_2d = shift_1d + 1;
|
2013-03-12 15:06:21 +00:00
|
|
|
|
|
|
|
// Get left and above reference column and row
|
2013-09-19 13:21:45 +00:00
|
|
|
for (k = 0; k < (int32_t)blk_size + 1; k++) {
|
|
|
|
top_row[k] = src[k - srcstride];
|
|
|
|
left_column[k] = src[k * srcstride - 1];
|
2014-02-21 13:00:20 +00:00
|
|
|
}
|
2013-03-07 15:42:00 +00:00
|
|
|
|
|
|
|
// Prepare intermediate variables used in interpolation
|
2013-09-19 13:21:45 +00:00
|
|
|
bottom_left = left_column[blk_size];
|
|
|
|
top_right = top_row[blk_size];
|
|
|
|
for (k = 0; k < (int32_t)blk_size; k++) {
|
|
|
|
bottom_row[k] = bottom_left - top_row[k];
|
|
|
|
right_column[k] = top_right - left_column[k];
|
|
|
|
top_row[k] <<= shift_1d;
|
|
|
|
left_column[k] <<= shift_1d;
|
2013-03-07 15:42:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generate prediction signal
|
2013-09-19 13:21:45 +00:00
|
|
|
for (k = 0; k < (int32_t)blk_size; k++) {
|
|
|
|
hor_pred = left_column[k] + offset_2d;
|
|
|
|
for (l = 0; l < (int32_t)blk_size; l++) {
|
|
|
|
hor_pred += right_column[k];
|
|
|
|
top_row[l] += bottom_row[l];
|
2014-02-14 15:14:35 +00:00
|
|
|
dst[k * dststride + l] = (pixel)((hor_pred + top_row[l]) >> shift_2d);
|
2013-03-07 15:42:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-25 10:08:07 +00:00
|
|
|
|
2014-05-15 14:37:17 +00:00
|
|
|
void intra_recon_lcu(encoder_state * const encoder_state, int x, int y, int depth, lcu_t *lcu)
|
2014-02-25 10:08:07 +00:00
|
|
|
{
|
2014-04-17 12:42:20 +00:00
|
|
|
const encoder_control * const encoder = encoder_state->encoder_control;
|
2014-05-15 14:37:17 +00:00
|
|
|
const vector2d lcu_px = { x & 0x3f, y & 0x3f };
|
|
|
|
cu_info *cur_cu = &lcu->cu[LCU_CU_OFFSET + (lcu_px.x>>3) + (lcu_px.y>>3)*LCU_T_CU_WIDTH];
|
|
|
|
const int8_t width = LCU_WIDTH >> depth;
|
|
|
|
const int8_t width_c = (depth == MAX_PU_DEPTH ? width : width / 2);
|
|
|
|
const int pu_index = PU_INDEX(x >> 2, y >> 2);
|
|
|
|
|
|
|
|
if (depth == 0 || cur_cu->tr_depth > depth) {
|
|
|
|
int offset = width / 2;
|
|
|
|
|
|
|
|
intra_recon_lcu(encoder_state, x, y, depth+1, lcu);
|
|
|
|
intra_recon_lcu(encoder_state, x + offset, y, depth+1, lcu);
|
|
|
|
intra_recon_lcu(encoder_state, x, y + offset, depth+1, lcu);
|
|
|
|
intra_recon_lcu(encoder_state, x + offset, y + offset, depth+1, lcu);
|
|
|
|
|
|
|
|
if (depth < MAX_DEPTH) {
|
|
|
|
cu_info *cu_a = &lcu->cu[LCU_CU_OFFSET + ((lcu_px.x + offset)>>3) + (lcu_px.y>>3) *LCU_T_CU_WIDTH];
|
|
|
|
cu_info *cu_b = &lcu->cu[LCU_CU_OFFSET + (lcu_px.x>>3) + ((lcu_px.y+offset)>>3)*LCU_T_CU_WIDTH];
|
|
|
|
cu_info *cu_c = &lcu->cu[LCU_CU_OFFSET + ((lcu_px.x + offset)>>3) + ((lcu_px.y+offset)>>3)*LCU_T_CU_WIDTH];
|
|
|
|
if (cbf_is_set(cu_a->cbf.y, depth+1) || cbf_is_set(cu_b->cbf.y, depth+1) || cbf_is_set(cu_c->cbf.y, depth+1)) {
|
|
|
|
cbf_set(&cur_cu->cbf.y, depth);
|
|
|
|
}
|
|
|
|
if (cbf_is_set(cu_a->cbf.u, depth+1) || cbf_is_set(cu_b->cbf.u, depth+1) || cbf_is_set(cu_c->cbf.u, depth+1)) {
|
|
|
|
cbf_set(&cur_cu->cbf.u, depth);
|
|
|
|
}
|
|
|
|
if (cbf_is_set(cu_a->cbf.v, depth+1) || cbf_is_set(cu_b->cbf.v, depth+1) || cbf_is_set(cu_c->cbf.v, depth+1)) {
|
|
|
|
cbf_set(&cur_cu->cbf.v, depth);
|
|
|
|
}
|
|
|
|
}
|
2014-03-11 17:19:20 +00:00
|
|
|
|
2014-05-15 14:37:17 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
const uint32_t pic_width = encoder_state->tile->cur_pic->width;
|
|
|
|
const uint32_t pic_height = encoder_state->tile->cur_pic->height;
|
|
|
|
|
|
|
|
// Pointers to reconstruction arrays
|
|
|
|
pixel *recbase_y = &lcu->rec.y[lcu_px.x + lcu_px.y * LCU_WIDTH];
|
|
|
|
pixel *recbase_u = &lcu->rec.u[lcu_px.x/2 + (lcu_px.y * LCU_WIDTH)/4];
|
|
|
|
pixel *recbase_v = &lcu->rec.v[lcu_px.x/2 + (lcu_px.y * LCU_WIDTH)/4];
|
|
|
|
|
|
|
|
pixel rec[(LCU_WIDTH*2+8)*(LCU_WIDTH*2+8)];
|
|
|
|
pixel *rec_shift = &rec[width * 2 + 8 + 1];
|
|
|
|
|
|
|
|
int32_t rec_stride = LCU_WIDTH;
|
|
|
|
|
|
|
|
// Reconstruct chroma.
|
|
|
|
if (!(x & 4 || y & 4)) {
|
|
|
|
pixel *rec_shift_c = &rec[width_c * 2 + 8 + 1];
|
|
|
|
intra_build_reference_border(encoder, x, y,(int16_t)width_c * 2 + 8, rec, (int16_t)width_c * 2 + 8, 1,
|
|
|
|
pic_width/2, pic_height/2, lcu);
|
|
|
|
intra_recon(encoder,
|
|
|
|
rec_shift_c,
|
|
|
|
width_c * 2 + 8,
|
|
|
|
width_c,
|
|
|
|
recbase_u,
|
|
|
|
rec_stride >> 1,
|
|
|
|
cur_cu->intra[0].mode_chroma,
|
|
|
|
1);
|
|
|
|
|
|
|
|
intra_build_reference_border(encoder, x, y,(int16_t)width_c * 2 + 8, rec, (int16_t)width_c * 2 + 8, 2,
|
|
|
|
pic_width/2, pic_height/2, lcu);
|
|
|
|
intra_recon(encoder,
|
|
|
|
rec_shift_c,
|
|
|
|
width_c * 2 + 8,
|
|
|
|
width_c,
|
|
|
|
recbase_v,
|
|
|
|
rec_stride >> 1,
|
|
|
|
cur_cu->intra[0].mode_chroma,
|
|
|
|
2);
|
|
|
|
}
|
|
|
|
|
|
|
|
intra_build_reference_border(encoder, x, y,(int16_t)width * 2 + 8, rec, (int16_t)width * 2 + 8, 0,
|
|
|
|
pic_width, pic_height, lcu);
|
|
|
|
intra_recon(encoder, rec_shift, width * 2 + 8,
|
|
|
|
width, recbase_y, rec_stride, cur_cu->intra[pu_index].mode, 0);
|
|
|
|
|
|
|
|
// Filter DC-prediction
|
|
|
|
if (cur_cu->intra[pu_index].mode == 1 && width < 32) {
|
|
|
|
intra_dc_pred_filtering(rec_shift, width * 2 + 8, recbase_y,
|
|
|
|
rec_stride, width, width);
|
|
|
|
}
|
|
|
|
|
|
|
|
quantize_lcu_luma_residual(encoder_state, x, y, depth, lcu);
|
|
|
|
quantize_lcu_chroma_residual(encoder_state, x, y, depth, lcu);
|
2014-02-26 13:45:00 +00:00
|
|
|
}
|
2014-02-25 10:08:07 +00:00
|
|
|
}
|