2014-01-24 10:37:15 +00:00
/*****************************************************************************
* This file is part of Kvazaar HEVC encoder .
2013-09-18 14:29:30 +00:00
*
2014-01-24 10:37:15 +00:00
* Copyright ( C ) 2013 - 2014 Tampere University of Technology and others ( see
* 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/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* \ file
2013-04-16 08:23:03 +00:00
*/
2013-09-18 09:16:03 +00:00
# include "search.h"
2013-04-16 08:23:03 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2013-09-18 09:16:03 +00:00
2013-04-16 08:23:03 +00:00
# include "config.h"
# include "bitstream.h"
# include "picture.h"
2013-04-16 12:10:43 +00:00
# include "intra.h"
2013-09-05 12:02:53 +00:00
# include "inter.h"
2013-04-16 08:23:03 +00:00
# include "filter.h"
2013-09-18 08:07:48 +00:00
# include "debug.h"
2013-04-16 12:10:43 +00:00
2013-09-16 14:34:20 +00:00
2013-09-16 16:18:24 +00:00
// Temporarily for debugging.
2013-11-13 06:45:53 +00:00
# define USE_INTRA_IN_P 1
2013-10-01 16:55:45 +00:00
//#define RENDER_CU encoder->frame==2
2013-09-25 14:48:02 +00:00
# define RENDER_CU 0
2013-10-22 16:00:36 +00:00
# define SEARCH_MV_FULL_RADIUS 0
2013-09-16 16:18:24 +00:00
2013-09-30 07:47:05 +00:00
# define IN_FRAME(x, y, width, height, block_width, block_height) \
( ( x ) > = 0 & & ( y ) > = 0 \
& & ( x ) + ( block_width ) < = ( width ) \
& & ( y ) + ( block_height ) < = ( height ) )
2013-09-25 14:47:40 +00:00
2013-10-08 09:30:25 +00:00
/**
* This is used in the hexagon_search to select 3 points to search .
*
* The start of the hexagonal pattern has been repeated at the end so that
* the indices between 1 - 6 can be used as the start of a 3 - point list of new
* points to search .
*
* 6 o - o 1 / 7
* / \
* 5 o 0 o 2 / 8
* \ /
* 4 o - o 3
*/
const vector2d large_hexbs [ 10 ] = {
{ 0 , 0 } ,
{ 1 , - 2 } , { 2 , 0 } , { 1 , 2 } , { - 1 , 2 } , { - 2 , 0 } , { - 1 , - 2 } ,
{ 1 , - 2 } , { 2 , 0 }
} ;
/**
* This is used as the last step of the hexagon search .
*/
const vector2d small_hexbs [ 5 ] = {
{ 0 , 0 } ,
{ - 1 , - 1 } , { - 1 , 0 } , { 1 , 0 } , { 1 , 1 }
} ;
2013-10-22 10:08:08 +00:00
int calc_mvd_cost ( int x , int y , const vector2d * pred )
{
2013-10-22 16:00:36 +00:00
int cost = 0 ;
2013-10-22 10:08:08 +00:00
// Get the absolute difference vector and count the bits.
x = abs ( abs ( x ) - abs ( pred - > x ) ) ;
y = abs ( abs ( y ) - abs ( pred - > y ) ) ;
while ( x > > = 1 ) {
+ + cost ;
}
while ( y > > = 1 ) {
+ + cost ;
}
2013-10-22 16:00:36 +00:00
// I don't know what is a good cost function for this. It probably doesn't
// have to aproximate the actual cost of encoding the vector, but it's a
// place to start.
// Add two for quarter pixel resolution and multiply by two for Exp-Golomb.
return ( cost ? ( cost + 2 ) < < 1 : 0 ) ;
2013-10-22 10:08:08 +00:00
}
2013-10-22 08:40:24 +00:00
/**
* \ brief Do motion search using the HEXBS algorithm .
*
* \ param depth log2 depth of the search
* \ param pic Picture motion vector is searched for .
* \ param ref Picture motion vector is searched from .
* \ param orig Top left corner of the searched for block .
* \ param mv_in_out Predicted mv in and best out . Quarter pixel precision .
*
* \ returns Cost of the motion vector .
*
* Motion vector is searched by first searching iteratively with the large
* hexagon pattern until the best match is at the center of the hexagon .
* As a final step a smaller hexagon is used to check the adjacent pixels .
*
* If a non 0 , 0 predicted motion vector predictor is given as mv_in_out ,
* the 0 , 0 vector is also tried . This is hoped to help in the case where
* the predicted motion vector is way off . In the future even more additional
* points like 0 , 0 might be used , such as vectors from top or left .
*/
2013-10-18 13:30:36 +00:00
unsigned hexagon_search ( unsigned depth ,
2013-10-18 14:51:53 +00:00
const picture * pic , const picture * ref ,
const vector2d * orig , vector2d * mv_in_out )
2013-10-08 09:30:25 +00:00
{
2013-10-18 13:43:28 +00:00
vector2d mv = { mv_in_out - > x > > 2 , mv_in_out - > y > > 2 } ;
2013-10-08 09:30:25 +00:00
int block_width = CU_WIDTH_FROM_DEPTH ( depth ) ;
unsigned best_cost = - 1 ;
unsigned i ;
2013-10-18 13:30:36 +00:00
unsigned best_index = 0 ; // Index of large_hexbs or finally small_hexbs.
2013-10-08 09:30:25 +00:00
// Search the initial 7 points of the hexagon.
for ( i = 0 ; i < 7 ; + + i ) {
2013-10-22 08:40:24 +00:00
const vector2d * pattern = & large_hexbs [ i ] ;
2013-10-18 13:30:36 +00:00
unsigned cost = calc_sad ( pic , ref , orig - > x , orig - > y ,
2013-10-18 13:43:28 +00:00
orig - > x + mv . x + pattern - > x , orig - > y + mv . y + pattern - > y ,
2013-10-11 12:19:21 +00:00
block_width , block_width ) ;
2013-10-22 10:08:08 +00:00
cost + = calc_mvd_cost ( mv . x + pattern - > x , orig - > y + mv . y + pattern - > y , mv_in_out ) ;
2013-10-22 08:40:24 +00:00
if ( cost < best_cost ) {
2013-10-08 09:30:25 +00:00
best_cost = cost ;
best_index = i ;
}
}
2013-10-08 13:11:00 +00:00
// Try the 0,0 vector.
2013-10-18 13:43:28 +00:00
if ( ! ( mv . x = = 0 & & mv . y = = 0 ) ) {
2013-10-18 13:30:36 +00:00
unsigned cost = calc_sad ( pic , ref , orig - > x , orig - > y ,
orig - > x , orig - > y ,
2013-10-11 12:19:21 +00:00
block_width , block_width ) ;
2013-10-22 10:08:08 +00:00
cost + = calc_mvd_cost ( 0 , 0 , mv_in_out ) ;
2013-10-22 08:40:24 +00:00
// If the 0,0 is better, redo the hexagon around that point.
if ( cost < best_cost ) {
2013-10-08 13:11:00 +00:00
best_cost = cost ;
best_index = 0 ;
2013-10-18 13:43:28 +00:00
mv . x = 0 ;
mv . y = 0 ;
2013-10-08 13:11:00 +00:00
for ( i = 1 ; i < 7 ; + + i ) {
2013-10-22 08:40:24 +00:00
const vector2d * pattern = & large_hexbs [ i ] ;
2013-10-18 13:30:36 +00:00
unsigned cost = calc_sad ( pic , ref , orig - > x , orig - > y ,
2013-10-22 08:40:24 +00:00
orig - > x + pattern - > x ,
orig - > y + pattern - > y ,
2013-10-11 12:19:21 +00:00
block_width , block_width ) ;
2013-10-22 10:08:08 +00:00
cost + = calc_mvd_cost ( pattern - > x , pattern - > y , mv_in_out ) ;
2013-10-22 08:40:24 +00:00
if ( cost < best_cost ) {
2013-10-08 13:11:00 +00:00
best_cost = cost ;
best_index = i ;
}
}
}
}
2013-10-08 09:30:25 +00:00
// Iteratively search the 3 new points around the best match, until the best
// match is in the center.
while ( best_index ! = 0 ) {
unsigned start ; // Starting point of the 3 offsets to be searched.
if ( best_index = = 1 ) {
start = 6 ;
} else if ( best_index = = 8 ) {
start = 1 ;
} else {
start = best_index - 1 ;
}
// Move the center to the best match.
2013-10-18 13:43:28 +00:00
mv . x + = large_hexbs [ best_index ] . x ;
mv . y + = large_hexbs [ best_index ] . y ;
2013-10-08 09:30:25 +00:00
best_index = 0 ;
// Iterate through the next 3 points.
for ( i = 0 ; i < 3 ; + + i ) {
2013-10-22 08:40:24 +00:00
const vector2d * offset = & large_hexbs [ start + i ] ;
2013-10-18 13:30:36 +00:00
unsigned cost = calc_sad ( pic , ref , orig - > x , orig - > y ,
2013-10-18 13:43:28 +00:00
orig - > x + mv . x + offset - > x ,
orig - > y + mv . y + offset - > y ,
2013-10-11 12:19:21 +00:00
block_width , block_width ) ;
2013-10-22 10:08:08 +00:00
cost + = calc_mvd_cost ( mv . x + offset - > x , mv . y + offset - > y , mv_in_out ) ;
2013-10-22 08:40:24 +00:00
if ( cost < best_cost ) {
2013-10-08 09:30:25 +00:00
best_cost = cost ;
best_index = start + i ;
}
+ + offset ;
}
}
2013-10-22 08:40:24 +00:00
// Move the center to the best match.
2013-10-18 13:43:28 +00:00
mv . x + = large_hexbs [ best_index ] . x ;
mv . y + = large_hexbs [ best_index ] . y ;
2013-10-08 09:30:25 +00:00
best_index = 0 ;
2013-10-22 08:40:24 +00:00
// Do the final step of the search with a small pattern.
2013-10-08 09:30:25 +00:00
for ( i = 1 ; i < 5 ; + + i ) {
2013-10-22 08:40:24 +00:00
const vector2d * offset = & small_hexbs [ i ] ;
2013-10-18 13:30:36 +00:00
unsigned cost = calc_sad ( pic , ref , orig - > x , orig - > y ,
2013-10-22 08:40:24 +00:00
orig - > x + mv . x + offset - > x ,
orig - > y + mv . y + offset - > y ,
2013-10-11 12:19:21 +00:00
block_width , block_width ) ;
2013-10-22 10:08:08 +00:00
cost + = calc_mvd_cost ( mv . x + offset - > x , mv . y + offset - > y , mv_in_out ) ;
2013-10-08 09:30:25 +00:00
if ( cost > 0 & & cost < best_cost ) {
best_cost = cost ;
best_index = i ;
}
}
2013-10-22 08:40:24 +00:00
// Adjust the movement vector according to the final best match.
2013-10-18 13:43:28 +00:00
mv . x + = small_hexbs [ best_index ] . x ;
mv . y + = small_hexbs [ best_index ] . y ;
2013-10-22 08:40:24 +00:00
// Return final movement vector in quarter-pixel precision.
2013-10-18 13:43:28 +00:00
mv_in_out - > x = mv . x < < 2 ;
mv_in_out - > y = mv . y < < 2 ;
2013-10-18 13:30:36 +00:00
return best_cost ;
2013-10-08 09:30:25 +00:00
}
2013-10-22 16:00:36 +00:00
unsigned search_mv_full ( unsigned depth ,
const picture * pic , const picture * ref ,
const vector2d * orig , vector2d * mv_in_out )
{
vector2d mv = { mv_in_out - > x > > 2 , mv_in_out - > y > > 2 } ;
int block_width = CU_WIDTH_FROM_DEPTH ( depth ) ;
unsigned best_cost = - 1 ;
int x , y ;
vector2d min_mv , max_mv ;
/*if (abs(mv.x) > SEARCH_MV_FULL_RADIUS || abs(mv.y) > SEARCH_MV_FULL_RADIUS) {
best_cost = calc_sad ( pic , ref , orig - > x , orig - > y ,
orig - > x , orig - > y ,
block_width , block_width ) ;
mv . x = 0 ;
mv . y = 0 ;
} */
min_mv . x = mv . x - SEARCH_MV_FULL_RADIUS ;
min_mv . y = mv . y - SEARCH_MV_FULL_RADIUS ;
max_mv . x = mv . x + SEARCH_MV_FULL_RADIUS ;
max_mv . y = mv . y + SEARCH_MV_FULL_RADIUS ;
for ( y = min_mv . y ; y < max_mv . y ; + + y ) {
for ( x = min_mv . x ; x < max_mv . x ; + + x ) {
unsigned cost = calc_sad ( pic , ref , orig - > x , orig - > y ,
orig - > x + x ,
orig - > y + y ,
block_width , block_width ) ;
cost + = calc_mvd_cost ( x , y , mv_in_out ) ;
if ( cost < best_cost ) {
best_cost = cost ;
mv . x = x ;
mv . y = y ;
}
}
}
mv_in_out - > x = mv . x < < 2 ;
mv_in_out - > y = mv . y < < 2 ;
return best_cost ;
}
2013-09-20 09:17:13 +00:00
/**
* \ brief
*/
2014-01-03 08:14:26 +00:00
void search_buildReferenceBorder ( picture * pic , int32_t x , int32_t y ,
2013-10-18 11:23:21 +00:00
int16_t outwidth , pixel * dst ,
2013-09-20 09:17:13 +00:00
int32_t dststride , int8_t chroma )
2013-04-18 11:04:15 +00:00
{
2013-09-20 09:17:13 +00:00
int32_t left_col ; // left column iterator
2013-10-18 11:23:21 +00:00
pixel val ; // variable to store extrapolated value
2013-09-20 09:17:13 +00:00
int32_t i ; // index iterator
2013-10-18 11:23:21 +00:00
pixel dc_val = 1 < < ( g_bitdepth - 1 ) ; // default predictor value
2013-09-20 09:17:13 +00:00
int32_t top_row ; // top row iterator
int32_t src_width = ( pic - > width > > ( chroma ? 1 : 0 ) ) ; // source picture width
int32_t src_height = ( pic - > height > > ( chroma ? 1 : 0 ) ) ; // source picture height
2013-10-14 14:27:25 +00:00
pixel * src_pic = ( ! chroma ) ? pic - > y_data : ( ( chroma = = 1 ) ? pic - > u_data : pic - > v_data ) ; // input picture pointer
2013-09-20 09:17:13 +00:00
int16_t scu_width = LCU_WIDTH > > ( MAX_DEPTH + ( chroma ? 1 : 0 ) ) ; // Smallest Coding Unit width
2014-01-03 11:01:13 +00:00
int x_ctb = x > > MIN_SIZE ;
int y_ctb = y > > MIN_SIZE ;
pixel * src_shifted = & src_pic [ x_ctb * scu_width + y_ctb * scu_width * src_width ] ; // input picture pointer shifted to start from the left-top corner of the current block
2013-09-20 09:17:13 +00:00
int32_t width_in_scu = pic - > width_in_lcu < < MAX_DEPTH ; // picture width in SCU
// Fill left column
if ( x_ctb ) {
// Loop SCU's
for ( left_col = 1 ; left_col < outwidth / scu_width ; left_col + + ) {
// If over the picture height or block not yet searched, stop
if ( ( y_ctb + left_col ) * scu_width > = src_height
2013-09-25 13:11:31 +00:00
| | pic - > cu_array [ MAX_DEPTH ] [ x_ctb - 1 + ( y_ctb + left_col ) * width_in_scu ] . type = = CU_NOTSET ) {
2013-04-18 11:04:15 +00:00
break ;
}
}
2013-09-20 09:17:13 +00:00
// Copy the pixels to output
for ( i = 0 ; i < left_col * scu_width - 1 ; i + + ) {
dst [ ( i + 1 ) * dststride ] = src_shifted [ i * src_width - 1 ] ;
2013-04-18 11:04:15 +00:00
}
2013-09-20 09:17:13 +00:00
// if the loop was not completed, extrapolate the last pixel pushed to output
if ( left_col ! = outwidth / scu_width ) {
val = src_shifted [ ( left_col * scu_width - 1 ) * src_width - 1 ] ;
for ( i = ( left_col * scu_width ) ; i < outwidth ; i + + ) {
dst [ i * dststride ] = val ;
2013-04-18 11:04:15 +00:00
}
2013-09-20 09:17:13 +00:00
}
} else { // If left column not available, copy from toprow or use the default predictor
val = y_ctb ? src_shifted [ - src_width ] : dc_val ;
for ( i = 0 ; i < outwidth ; i + + ) {
dst [ i * dststride ] = val ;
2013-04-18 11:04:15 +00:00
}
}
2013-09-20 09:17:13 +00:00
if ( y_ctb ) {
// Loop top SCU's
for ( top_row = 1 ; top_row < outwidth / scu_width ; top_row + + ) {
if ( ( x_ctb + top_row ) * scu_width > = src_width
2013-09-25 13:11:31 +00:00
| | pic - > cu_array [ MAX_DEPTH ] [ x_ctb + top_row + ( y_ctb - 1 ) * width_in_scu ] . type
2013-09-20 09:17:13 +00:00
= = CU_NOTSET ) {
2013-04-18 11:04:15 +00:00
break ;
}
}
2013-09-20 09:17:13 +00:00
for ( i = 0 ; i < top_row * scu_width - 1 ; i + + ) {
dst [ i + 1 ] = src_shifted [ i - src_width ] ;
2013-04-18 11:04:15 +00:00
}
2013-09-20 09:17:13 +00:00
if ( top_row ! = outwidth / scu_width ) {
val = src_shifted [ ( top_row * scu_width ) - src_width - 1 ] ;
for ( i = ( top_row * scu_width ) ; i < outwidth ; i + + ) {
2013-04-18 11:04:15 +00:00
dst [ i ] = val ;
}
}
2013-09-20 09:17:13 +00:00
} else {
val = x_ctb ? src_shifted [ - 1 ] : dc_val ;
for ( i = 1 ; i < outwidth ; i + + ) {
2013-04-18 11:04:15 +00:00
dst [ i ] = val ;
}
}
2013-09-20 09:17:13 +00:00
// Topleft corner
dst [ 0 ] = ( x_ctb & & y_ctb ) ? src_shifted [ - src_width - 1 ] : dst [ dststride ] ;
2013-04-18 11:04:15 +00:00
}
2013-12-17 09:32:28 +00:00
void search_inter ( encoder_control * encoder , uint16_t x_ctb , uint16_t y_ctb , uint8_t depth ) {
picture * cur_pic = encoder - > in . cur_pic ;
picture * ref_pic = encoder - > ref - > pics [ 0 ] ;
unsigned width_in_scu = NO_SCU_IN_LCU ( ref_pic - > width_in_lcu ) ;
cu_info * ref_cu = & ref_pic - > cu_array [ MAX_DEPTH ] [ y_ctb * width_in_scu + x_ctb ] ;
cu_info * cur_cu = & cur_pic - > cu_array [ depth ] [ x_ctb + y_ctb * ( encoder - > in . width_in_lcu < < MAX_DEPTH ) ] ;
vector2d orig , mv ;
orig . x = x_ctb * CU_MIN_SIZE_PIXELS ;
orig . y = y_ctb * CU_MIN_SIZE_PIXELS ;
mv . x = 0 ;
mv . y = 0 ;
if ( ref_cu - > type = = CU_INTER ) {
mv . x = ref_cu - > inter . mv [ 0 ] ;
mv . y = ref_cu - > inter . mv [ 1 ] ;
}
# if SEARCH_MV_FULL_RADIUS
cur_cu - > inter . cost = search_mv_full ( depth , cur_pic , ref_pic , & orig , & mv ) ;
# else
cur_cu - > inter . cost = hexagon_search ( depth , cur_pic , ref_pic , & orig , & mv ) ;
# endif
cur_cu - > inter . mv_dir = 1 ;
cur_cu - > inter . mv [ 0 ] = mv . x ;
cur_cu - > inter . mv [ 1 ] = mv . y ;
}
void search_intra ( encoder_control * encoder , uint16_t x_ctb , uint16_t y_ctb , uint8_t depth )
{
2014-01-03 08:14:26 +00:00
int x = x_ctb * ( LCU_WIDTH > > MAX_DEPTH ) ;
int y = y_ctb * ( LCU_WIDTH > > MAX_DEPTH ) ;
2013-12-17 09:32:28 +00:00
picture * cur_pic = encoder - > in . cur_pic ;
uint32_t width = LCU_WIDTH > > depth ;
cu_info * cur_cu = & cur_pic - > cu_array [ depth ] [ x_ctb + y_ctb * ( encoder - > in . width_in_lcu < < MAX_DEPTH ) ] ;
// INTRAPREDICTION
pixel pred [ LCU_WIDTH * LCU_WIDTH + 1 ] ;
2014-01-21 18:48:59 +00:00
pixel rec [ ( LCU_WIDTH * 2 + 1 ) * ( LCU_WIDTH * 2 + 1 ) ] ;
2013-12-17 09:32:28 +00:00
pixel * recShift = & rec [ ( LCU_WIDTH > > ( depth ) ) * 2 + 8 + 1 ] ;
// Build reconstructed block to use in prediction with extrapolated borders
2014-01-03 08:14:26 +00:00
search_buildReferenceBorder ( encoder - > in . cur_pic , x , y ,
width * 2 + 8 , rec , width * 2 + 8 , 0 ) ;
2014-01-02 13:02:17 +00:00
cur_cu - > intra [ 0 ] . mode = ( uint8_t ) intra_prediction ( encoder - > in . cur_pic - > y_data ,
2014-01-03 08:14:26 +00:00
encoder - > in . width , recShift , width * 2 + 8 , x , y ,
2014-01-02 13:02:17 +00:00
width , pred , width , & cur_cu - > intra [ 0 ] . cost ) ;
2014-01-21 18:48:59 +00:00
cur_cu - > part_size = SIZE_2Nx2N ;
2014-01-03 08:14:26 +00:00
// Do search for NxN split.
2014-01-29 14:15:13 +00:00
// This feature doesn't work yet so it is disabled.
if ( 0 & & depth = = MAX_DEPTH ) { // Disabled because coding NxN doesn't work yet.
2014-01-03 08:14:26 +00:00
// Save 2Nx2N information to compare with NxN.
int nn_cost = cur_cu - > intra [ 0 ] . cost ;
int nn_mode = cur_cu - > intra [ 0 ] . mode ;
int i ;
2014-01-21 18:48:59 +00:00
int cost = g_lambda_cost [ encoder - > QP ] < < 8 ;
2014-01-03 08:14:26 +00:00
static vector2d offsets [ 4 ] = { { 0 , 0 } , { 1 , 0 } , { 0 , 1 } , { 1 , 1 } } ;
width = 4 ;
recShift = & rec [ width * 2 + 8 + 1 ] ;
for ( i = 0 ; i < 4 ; + + i ) {
int x_pos = x + offsets [ i ] . x * width ;
int y_pos = y + offsets [ i ] . y * width ;
search_buildReferenceBorder ( encoder - > in . cur_pic , x_pos , y_pos ,
width * 2 + 8 , rec , width * 2 + 8 , 0 ) ;
cur_cu - > intra [ i ] . mode = ( uint8_t ) intra_prediction ( encoder - > in . cur_pic - > y_data ,
encoder - > in . width , recShift , width * 2 + 8 , x_pos , y_pos ,
width , pred , width , & cur_cu - > intra [ i ] . cost ) ;
cost + = cur_cu - > intra [ i ] . cost ;
}
// Choose between 2Nx2N and NxN.
if ( nn_cost < = cost ) {
cur_cu - > intra [ 0 ] . cost = nn_cost ;
cur_cu - > intra [ 0 ] . mode = nn_mode ;
} else {
2014-01-21 18:48:59 +00:00
cur_cu - > intra [ 0 ] . cost = cost ;
2014-01-03 08:14:26 +00:00
cur_cu - > part_size = SIZE_NxN ;
}
}
2013-12-17 09:32:28 +00:00
}
2013-09-20 09:17:13 +00:00
/**
* \ brief
*/
void search_tree ( encoder_control * encoder ,
uint16_t x_ctb , uint16_t y_ctb , uint8_t depth )
{
uint8_t border_x = ( ( encoder - > in . width ) < ( x_ctb * ( LCU_WIDTH > > MAX_DEPTH ) + ( LCU_WIDTH > > depth ) ) ) ? 1 : 0 ;
uint8_t border_y = ( ( encoder - > in . height ) < ( y_ctb * ( LCU_WIDTH > > MAX_DEPTH ) + ( LCU_WIDTH > > depth ) ) ) ? 1 : 0 ;
uint8_t border_split_x = ( ( encoder - > in . width ) < ( ( x_ctb + 1 ) * ( LCU_WIDTH > > MAX_DEPTH ) + ( LCU_WIDTH > > ( depth + 1 ) ) ) ) ? 0 : 1 ;
uint8_t border_split_y = ( ( encoder - > in . height ) < ( ( y_ctb + 1 ) * ( LCU_WIDTH > > MAX_DEPTH ) + ( LCU_WIDTH > > ( depth + 1 ) ) ) ) ? 0 : 1 ;
uint8_t border = border_x | border_y ; // are we in any border CU
2013-10-18 12:19:22 +00:00
picture * cur_pic = encoder - > in . cur_pic ;
cu_info * cur_cu = & cur_pic - > cu_array [ depth ] [ x_ctb + y_ctb * ( encoder - > in . width_in_lcu < < MAX_DEPTH ) ] ;
2013-09-20 09:17:13 +00:00
2014-01-02 13:02:17 +00:00
cur_cu - > intra [ 0 ] . cost = 0xffffffff ;
2013-09-20 09:17:13 +00:00
cur_cu - > inter . cost = 0xffffffff ;
// Force split on border
if ( depth ! = MAX_DEPTH ) {
if ( border ) {
uint8_t change = 1 < < ( MAX_DEPTH - 1 - depth ) ;
search_tree ( encoder , x_ctb , y_ctb , depth + 1 ) ;
if ( ! border_x | | border_split_x ) {
search_tree ( encoder , x_ctb + change , y_ctb , depth + 1 ) ;
2013-04-16 12:10:43 +00:00
}
2013-09-20 09:17:13 +00:00
if ( ! border_y | | border_split_y ) {
search_tree ( encoder , x_ctb , y_ctb + change , depth + 1 ) ;
2013-04-16 12:10:43 +00:00
}
2013-09-20 09:17:13 +00:00
if ( ! border | | ( border_split_x & & border_split_y ) ) {
search_tree ( encoder , x_ctb + change , y_ctb + change , depth + 1 ) ;
2013-04-16 12:10:43 +00:00
}
return ;
}
}
2013-09-20 09:17:13 +00:00
2013-10-18 12:19:22 +00:00
if ( cur_pic - > slicetype ! = SLICE_I
& & depth > = MIN_INTER_SEARCH_DEPTH & & depth < = MAX_INTER_SEARCH_DEPTH ) {
2013-12-17 09:32:28 +00:00
search_inter ( encoder , x_ctb , y_ctb , depth ) ;
2013-04-16 12:10:43 +00:00
}
2013-09-20 09:17:13 +00:00
if ( depth > = MIN_INTRA_SEARCH_DEPTH & & depth < = MAX_INTRA_SEARCH_DEPTH
2013-09-18 09:26:51 +00:00
& & ( encoder - > in . cur_pic - > slicetype = = SLICE_I | | USE_INTRA_IN_P ) ) {
2013-12-17 09:32:28 +00:00
search_intra ( encoder , x_ctb , y_ctb , depth ) ;
2013-04-16 12:10:43 +00:00
}
2013-09-20 09:17:13 +00:00
// Split and search to max_depth
if ( depth < MAX_INTRA_SEARCH_DEPTH & & depth < MAX_INTER_SEARCH_DEPTH ) {
// Split blocks and remember to change x and y block positions
uint8_t change = 1 < < ( MAX_DEPTH - 1 - depth ) ;
search_tree ( encoder , x_ctb , y_ctb , depth + 1 ) ;
search_tree ( encoder , x_ctb + change , y_ctb , depth + 1 ) ;
search_tree ( encoder , x_ctb , y_ctb + change , depth + 1 ) ;
search_tree ( encoder , x_ctb + change , y_ctb + change , depth + 1 ) ;
2013-04-16 12:10:43 +00:00
}
}
2013-09-20 09:17:13 +00:00
/**
* \ brief
*/
uint32_t search_best_mode ( encoder_control * encoder ,
uint16_t x_ctb , uint16_t y_ctb , uint8_t depth )
2013-04-16 12:10:43 +00:00
{
2013-10-18 12:23:17 +00:00
cu_info * cur_cu = & encoder - > in . cur_pic - > cu_array [ depth ]
[ x_ctb + y_ctb * ( encoder - > in . width_in_lcu < < MAX_DEPTH ) ] ;
2014-01-02 13:02:17 +00:00
uint32_t best_intra_cost = cur_cu - > intra [ 0 ] . cost ;
2013-09-20 09:17:13 +00:00
uint32_t best_inter_cost = cur_cu - > inter . cost ;
2013-10-18 12:23:17 +00:00
uint32_t lambda_cost = ( 4 * g_lambda_cost [ encoder - > QP ] ) < < 4 ; //<<5; //TODO: Correct cost calculation
2013-09-20 09:17:13 +00:00
2013-10-18 12:23:17 +00:00
if ( depth < MAX_INTRA_SEARCH_DEPTH & & depth < MAX_INTER_SEARCH_DEPTH ) {
uint32_t cost = lambda_cost ;
2013-09-20 09:17:13 +00:00
uint8_t change = 1 < < ( MAX_DEPTH - 1 - depth ) ;
2013-10-22 16:02:00 +00:00
cost + = search_best_mode ( encoder , x_ctb , y_ctb , depth + 1 ) ;
2013-09-20 09:17:13 +00:00
cost + = search_best_mode ( encoder , x_ctb + change , y_ctb , depth + 1 ) ;
cost + = search_best_mode ( encoder , x_ctb , y_ctb + change , depth + 1 ) ;
cost + = search_best_mode ( encoder , x_ctb + change , y_ctb + change , depth + 1 ) ;
2013-10-18 12:23:17 +00:00
if ( cost < best_intra_cost & & cost < best_inter_cost )
2013-04-16 12:10:43 +00:00
{
2013-10-18 12:23:17 +00:00
// Better value was found at a lower level.
return cost ;
2013-09-05 12:02:53 +00:00
}
2013-10-18 12:23:17 +00:00
}
2013-10-18 12:19:22 +00:00
// If search hasn't been peformed at all for this block, the cost will be
// max value, so it is safe to just compare costs. It just has to be made
// sure that no value overflows.
2013-10-18 12:23:17 +00:00
if ( best_inter_cost < = best_intra_cost ) {
2013-09-20 09:17:13 +00:00
inter_set_block ( encoder - > in . cur_pic , x_ctb , y_ctb , depth , cur_cu ) ;
2013-10-18 12:23:17 +00:00
return best_inter_cost ;
2013-09-20 09:17:13 +00:00
} else {
intra_set_block_mode ( encoder - > in . cur_pic , x_ctb , y_ctb , depth ,
2014-01-03 11:01:13 +00:00
cur_cu - > intra [ 0 ] . mode , cur_cu - > part_size ) ;
2013-10-18 12:23:17 +00:00
return best_intra_cost ;
2013-04-17 14:08:52 +00:00
}
2013-04-16 12:10:43 +00:00
}
2013-10-22 13:27:50 +00:00
2013-09-20 09:17:13 +00:00
/**
* \ brief
*/
void search_slice_data ( encoder_control * encoder )
2013-04-16 12:10:43 +00:00
{
2013-09-20 09:17:13 +00:00
int16_t x_lcu , y_lcu ;
2013-09-18 08:07:48 +00:00
FILE * fp = 0 , * fp2 = 0 ;
2013-10-01 16:55:45 +00:00
if ( RENDER_CU ) {
2013-09-18 08:07:48 +00:00
fp = open_cu_file ( " cu_search.html " ) ;
fp2 = open_cu_file ( " cu_best.html " ) ;
}
2013-09-20 09:17:13 +00:00
// Loop through every LCU in the slice
for ( y_lcu = 0 ; y_lcu < encoder - > in . height_in_lcu ; y_lcu + + ) {
for ( x_lcu = 0 ; x_lcu < encoder - > in . width_in_lcu ; x_lcu + + ) {
2013-04-16 12:10:43 +00:00
uint8_t depth = 0 ;
2013-09-20 09:17:13 +00:00
// Recursive function for looping through all the sub-blocks
search_tree ( encoder , x_lcu < < MAX_DEPTH , y_lcu < < MAX_DEPTH , depth ) ;
2013-10-01 16:55:45 +00:00
if ( RENDER_CU ) {
render_cu_file ( encoder , encoder - > in . cur_pic , depth , x_lcu < < MAX_DEPTH , y_lcu < < MAX_DEPTH , fp ) ;
2013-09-20 09:17:13 +00:00
}
2013-04-16 12:10:43 +00:00
2013-09-20 09:17:13 +00:00
// Decide actual coding modes
search_best_mode ( encoder , x_lcu < < MAX_DEPTH , y_lcu < < MAX_DEPTH , depth ) ;
2013-10-01 16:55:45 +00:00
if ( RENDER_CU ) {
render_cu_file ( encoder , encoder - > in . cur_pic , depth , x_lcu < < MAX_DEPTH , y_lcu < < MAX_DEPTH , fp2 ) ;
2013-09-20 09:17:13 +00:00
}
2013-10-22 13:27:50 +00:00
encode_block_residual ( encoder , x_lcu < < MAX_DEPTH , y_lcu < < MAX_DEPTH , depth ) ;
2013-04-16 12:10:43 +00:00
}
}
2013-09-18 08:07:48 +00:00
2013-10-22 13:27:50 +00:00
2013-09-18 08:07:48 +00:00
if ( RENDER_CU & & fp ) {
close_cu_file ( fp ) ;
fp = 0 ;
}
if ( RENDER_CU & & fp2 ) {
close_cu_file ( fp2 ) ;
fp2 = 0 ;
}
2013-09-16 14:34:20 +00:00
}