2014-06-03 12:47:49 +00:00
/*****************************************************************************
* This file is part of Kvazaar HEVC encoder .
*
2015-02-23 11:18:48 +00:00
* Copyright ( C ) 2013 - 2015 Tampere University of Technology and others ( see
2014-06-03 12:47:49 +00:00
* COPYING file ) .
*
2015-02-23 11:18:48 +00:00
* Kvazaar is free software : you can redistribute it and / or modify it under
* the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation ; either version 2.1 of the License , or ( at your
* option ) any later version .
2014-06-03 12:47:49 +00:00
*
2015-02-23 11:18:48 +00:00
* 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 Lesser General Public License for
* more details .
2014-06-03 12:47:49 +00:00
*
2015-02-23 11:18:48 +00:00
* You should have received a copy of the GNU General Public License along
* with Kvazaar . If not , see < http : //www.gnu.org/licenses/>.
2014-06-03 12:47:49 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-06-04 14:45:46 +00:00
# include "encoder_state-ctors_dtors.h"
2016-04-01 14:14:23 +00:00
# include <stdio.h>
2014-06-04 14:45:46 +00:00
# include <stdlib.h>
2016-04-01 14:14:23 +00:00
# include "bitstream.h"
# include "cabac.h"
# include "cu.h"
# include "encoder.h"
# include "encoder_state-geometry.h"
2014-06-04 14:45:46 +00:00
# include "encoderstate.h"
2016-04-01 14:14:23 +00:00
# include "image.h"
# include "imagelist.h"
2016-08-09 13:16:33 +00:00
# include "kvazaar.h"
2016-04-01 14:14:23 +00:00
# include "threadqueue.h"
# include "videoframe.h"
2014-06-04 14:45:46 +00:00
2014-06-03 12:47:49 +00:00
2016-08-10 00:46:23 +00:00
static int encoder_state_config_frame_init ( encoder_state_t * const state ) {
state - > frame - > ref = kvz_image_list_alloc ( MAX_REF_PIC_COUNT ) ;
if ( ! state - > frame - > ref ) {
2014-06-03 12:47:49 +00:00
fprintf ( stderr , " Failed to allocate the picture list! \n " ) ;
return 0 ;
}
2016-08-10 00:46:23 +00:00
state - > frame - > ref_list = REF_PIC_LIST_0 ;
state - > frame - > num = 0 ;
state - > frame - > poc = 0 ;
state - > frame - > total_bits_coded = 0 ;
state - > frame - > cur_gop_bits_coded = 0 ;
2016-08-21 03:27:58 +00:00
state - > frame - > prepared = 0 ;
state - > frame - > done = 1 ;
2016-08-10 00:46:23 +00:00
state - > frame - > rc_alpha = 3.2003 ;
state - > frame - > rc_beta = - 1.367 ;
2016-08-21 03:27:58 +00:00
2016-08-24 01:16:48 +00:00
const encoder_control_t * const encoder = state - > encoder_control ;
const int num_lcus = encoder - > in . width_in_lcu * encoder - > in . height_in_lcu ;
state - > frame - > lcu_stats = MALLOC ( lcu_stats_t , num_lcus ) ;
2014-06-03 12:47:49 +00:00
return 1 ;
}
2016-08-10 00:46:23 +00:00
static void encoder_state_config_frame_finalize ( encoder_state_t * const state ) {
2017-02-07 03:57:28 +00:00
if ( state - > frame = = NULL ) return ;
2016-08-10 00:46:23 +00:00
kvz_image_list_destroy ( state - > frame - > ref ) ;
2016-08-24 01:16:48 +00:00
FREE_POINTER ( state - > frame - > lcu_stats ) ;
2014-06-03 12:47:49 +00:00
}
2015-03-04 15:00:23 +00:00
static int encoder_state_config_tile_init ( encoder_state_t * const state ,
2014-06-03 12:47:49 +00:00
const int lcu_offset_x , const int lcu_offset_y ,
const int width , const int height , const int width_in_lcu , const int height_in_lcu ) {
2015-03-04 15:00:23 +00:00
const encoder_control_t * const encoder = state - > encoder_control ;
2016-08-25 13:05:46 +00:00
state - > tile - > frame = kvz_videoframe_alloc ( width , height , state - > encoder_control - > chroma_format ) ;
2014-06-12 05:13:37 +00:00
2015-03-04 15:00:23 +00:00
state - > tile - > frame - > rec = NULL ;
2014-06-16 08:42:28 +00:00
2015-05-18 15:21:23 +00:00
state - > tile - > frame - > source = NULL ;
2014-06-03 12:47:49 +00:00
2015-03-04 15:00:23 +00:00
if ( ! state - > tile - > frame ) {
2014-06-05 12:54:58 +00:00
printf ( " Error allocating videoframe! \r \n " ) ;
2014-06-03 12:47:49 +00:00
return 0 ;
}
2017-05-31 10:17:59 +00:00
2015-03-04 15:00:23 +00:00
state - > tile - > lcu_offset_x = lcu_offset_x ;
state - > tile - > lcu_offset_y = lcu_offset_y ;
2017-05-31 10:17:59 +00:00
state - > tile - > offset_x = lcu_offset_x * LCU_WIDTH ;
state - > tile - > offset_y = lcu_offset_y * LCU_WIDTH ;
2015-03-04 15:00:23 +00:00
state - > tile - > lcu_offset_in_ts = encoder - > tiles_ctb_addr_rs_to_ts [ lcu_offset_x + lcu_offset_y * encoder - > in . width_in_lcu ] ;
2014-06-03 12:47:49 +00:00
2016-08-17 13:43:16 +00:00
// hor_buf_search and ver_buf_search store single row/col from each LCU row/col.
// Because these lines are independent, the chroma subsampling only matters in one
// of the directions, .
unsigned luma_size = LCU_WIDTH * state - > tile - > frame - > width_in_lcu * state - > tile - > frame - > height_in_lcu ;
unsigned chroma_sizes_hor [ ] = { 0 , luma_size / 2 , luma_size / 2 , luma_size } ;
unsigned chroma_sizes_ver [ ] = { 0 , luma_size / 2 , luma_size , luma_size } ;
unsigned chroma_size_hor = chroma_sizes_hor [ state - > encoder_control - > chroma_format ] ;
unsigned chroma_size_ver = chroma_sizes_ver [ state - > encoder_control - > chroma_format ] ;
state - > tile - > hor_buf_search = kvz_yuv_t_alloc ( luma_size , chroma_size_hor ) ;
state - > tile - > ver_buf_search = kvz_yuv_t_alloc ( luma_size , chroma_size_ver ) ;
2017-06-30 13:12:52 +00:00
2017-08-11 08:57:09 +00:00
if ( encoder - > cfg . sao_type ) {
2016-08-17 13:43:16 +00:00
state - > tile - > hor_buf_before_sao = kvz_yuv_t_alloc ( luma_size , chroma_size_hor ) ;
2017-06-30 13:12:52 +00:00
state - > tile - > ver_buf_before_sao = kvz_yuv_t_alloc ( luma_size , chroma_size_ver ) ;
2014-06-03 12:47:49 +00:00
} else {
2015-03-04 15:00:23 +00:00
state - > tile - > hor_buf_before_sao = NULL ;
2017-06-30 13:12:52 +00:00
state - > tile - > ver_buf_before_sao = NULL ;
2014-06-03 12:47:49 +00:00
}
2017-06-30 13:12:52 +00:00
2017-02-06 11:00:25 +00:00
if ( encoder - > cfg . wpp ) {
2015-03-04 15:00:23 +00:00
int num_jobs = state - > tile - > frame - > width_in_lcu * state - > tile - > frame - > height_in_lcu ;
state - > tile - > wf_jobs = MALLOC ( threadqueue_job_t * , num_jobs ) ;
2017-02-08 19:27:20 +00:00
for ( int i = 0 ; i < num_jobs ; + + i ) {
state - > tile - > wf_jobs [ i ] = NULL ;
}
2015-03-04 15:00:23 +00:00
if ( ! state - > tile - > wf_jobs ) {
2014-06-03 12:47:49 +00:00
printf ( " Error allocating wf_jobs array! \n " ) ;
return 0 ;
}
} else {
2015-03-04 15:00:23 +00:00
state - > tile - > wf_jobs = NULL ;
2014-06-03 12:47:49 +00:00
}
2015-03-04 15:00:23 +00:00
state - > tile - > id = encoder - > tiles_tile_id [ state - > tile - > lcu_offset_in_ts ] ;
2014-06-03 12:47:49 +00:00
return 1 ;
}
2015-03-04 15:00:23 +00:00
static void encoder_state_config_tile_finalize ( encoder_state_t * const state ) {
2017-02-07 03:57:28 +00:00
if ( state - > tile = = NULL ) return ;
2015-08-26 08:50:27 +00:00
kvz_yuv_t_free ( state - > tile - > hor_buf_search ) ;
kvz_yuv_t_free ( state - > tile - > ver_buf_search ) ;
2017-06-30 13:12:52 +00:00
kvz_yuv_t_free ( state - > tile - > hor_buf_before_sao ) ;
kvz_yuv_t_free ( state - > tile - > ver_buf_before_sao ) ;
2017-04-04 12:36:08 +00:00
if ( state - > encoder_control - > cfg . wpp ) {
int num_jobs = state - > tile - > frame - > width_in_lcu * state - > tile - > frame - > height_in_lcu ;
for ( int i = 0 ; i < num_jobs ; + + i ) {
kvz_threadqueue_free_job ( & state - > tile - > wf_jobs [ i ] ) ;
}
}
2015-08-26 08:50:27 +00:00
kvz_videoframe_free ( state - > tile - > frame ) ;
2015-03-04 15:00:23 +00:00
state - > tile - > frame = NULL ;
FREE_POINTER ( state - > tile - > wf_jobs ) ;
2014-06-03 12:47:49 +00:00
}
2017-04-04 12:36:08 +00:00
static int encoder_state_config_slice_init ( encoder_state_t * const state ,
const int start_address_in_ts ,
const int end_address_in_ts )
{
2015-09-30 22:13:45 +00:00
state - > slice - > id = - 1 ;
for ( int i = 0 ; i < state - > encoder_control - > slice_count ; + + i ) {
2015-03-04 15:00:23 +00:00
if ( state - > encoder_control - > slice_addresses_in_ts [ i ] = = start_address_in_ts ) {
state - > slice - > id = i ;
2014-06-03 12:47:49 +00:00
break ;
}
}
2015-09-30 22:13:45 +00:00
assert ( state - > slice - > id ! = - 1 ) ;
2015-05-05 07:12:01 +00:00
2015-03-04 15:00:23 +00:00
state - > slice - > start_in_ts = start_address_in_ts ;
state - > slice - > end_in_ts = end_address_in_ts ;
2014-06-03 12:47:49 +00:00
2015-03-04 15:00:23 +00:00
state - > slice - > start_in_rs = state - > encoder_control - > tiles_ctb_addr_ts_to_rs [ start_address_in_ts ] ;
state - > slice - > end_in_rs = state - > encoder_control - > tiles_ctb_addr_ts_to_rs [ end_address_in_ts ] ;
2014-06-03 12:47:49 +00:00
return 1 ;
}
2015-03-04 15:00:23 +00:00
static int encoder_state_config_wfrow_init ( encoder_state_t * const state ,
2014-06-03 12:47:49 +00:00
const int lcu_offset_y ) {
2015-03-04 15:00:23 +00:00
state - > wfrow - > lcu_offset_y = lcu_offset_y ;
2014-06-03 12:47:49 +00:00
return 1 ;
}
2015-09-14 09:43:28 +00:00
# ifdef KVZ_DEBUG_PRINT_THREADING_INFO
2015-03-04 15:00:23 +00:00
static void encoder_state_dump_graphviz ( const encoder_state_t * const state ) {
2014-06-03 12:47:49 +00:00
int i ;
2015-03-04 15:00:23 +00:00
if ( ! state - > parent ) {
const encoder_control_t * const encoder = state - > encoder_control ;
2014-06-03 12:47:49 +00:00
int y , x ;
//Empty lines (easier to copy-paste)
printf ( " \n \n \n \n \n " ) ;
//Some styling...
printf ( " digraph EncoderStates { \n " ) ;
printf ( " fontname = \" Bitstream Vera Sans \" \n " ) ;
printf ( " fontsize = 8 \n \n " ) ;
printf ( " node [ \n " ) ;
printf ( " fontname = \" Bitstream Vera Sans \" \n " ) ;
printf ( " fontsize = 8 \n " ) ;
printf ( " shape = \" record \" \n " ) ;
printf ( " ] \n \n " ) ;
printf ( " edge [ \n " ) ;
printf ( " arrowtail = \" empty \" \n " ) ;
printf ( " ] \n \n " ) ;
printf ( " \" Map \" [ \n " ) ;
printf ( " shape=plaintext \n " ) ;
printf ( " label = <<table cellborder= \" 1 \" cellspacing= \" 0 \" border= \" 0 \" > " ) ;
printf ( " <tr><td colspan= \" %d \" height= \" 20 \" valign= \" bottom \" ><b>RS Map</b></td></tr> " , encoder - > in . width_in_lcu ) ;
for ( y = 0 ; y < encoder - > in . height_in_lcu ; + + y ) {
printf ( " <tr> " ) ;
for ( x = 0 ; x < encoder - > in . width_in_lcu ; + + x ) {
const int lcu_id_rs = y * encoder - > in . width_in_lcu + x ;
printf ( " <td>%d</td> " , lcu_id_rs ) ;
}
printf ( " </tr> " ) ;
}
printf ( " <tr><td colspan= \" %d \" height= \" 20 \" valign= \" bottom \" ><b>TS Map</b></td></tr> " , encoder - > in . width_in_lcu ) ;
for ( y = 0 ; y < encoder - > in . height_in_lcu ; + + y ) {
printf ( " <tr> " ) ;
for ( x = 0 ; x < encoder - > in . width_in_lcu ; + + x ) {
const int lcu_id_rs = y * encoder - > in . width_in_lcu + x ;
const int lcu_id_ts = encoder - > tiles_ctb_addr_rs_to_ts [ lcu_id_rs ] ;
printf ( " <td>%d</td> " , lcu_id_ts ) ;
}
printf ( " </tr> " ) ;
}
printf ( " <tr><td colspan= \" %d \" height= \" 20 \" valign= \" bottom \" ><b>Tile map</b></td></tr> " , encoder - > in . width_in_lcu ) ;
for ( y = 0 ; y < encoder - > in . height_in_lcu ; + + y ) {
printf ( " <tr> " ) ;
for ( x = 0 ; x < encoder - > in . width_in_lcu ; + + x ) {
const int lcu_id_rs = y * encoder - > in . width_in_lcu + x ;
const int lcu_id_ts = encoder - > tiles_ctb_addr_rs_to_ts [ lcu_id_rs ] ;
printf ( " <td>%d</td> " , encoder - > tiles_tile_id [ lcu_id_ts ] ) ;
}
printf ( " </tr> " ) ;
}
printf ( " <tr><td colspan= \" %d \" height= \" 20 \" valign= \" bottom \" ><b>Slice map</b></td></tr> " , encoder - > in . width_in_lcu ) ;
for ( y = 0 ; y < encoder - > in . height_in_lcu ; + + y ) {
printf ( " <tr> " ) ;
for ( x = 0 ; x < encoder - > in . width_in_lcu ; + + x ) {
const int lcu_id_rs = y * encoder - > in . width_in_lcu + x ;
const int lcu_id_ts = encoder - > tiles_ctb_addr_rs_to_ts [ lcu_id_rs ] ;
int slice_id = 0 ;
//Not efficient, but who cares
for ( i = 0 ; i < encoder - > slice_count ; + + i ) {
if ( encoder - > slice_addresses_in_ts [ i ] < = lcu_id_ts ) {
slice_id = i ;
}
}
printf ( " <td>%d</td> " , slice_id ) ;
}
printf ( " </tr> " ) ;
}
printf ( " </table>> \n ] \n " ) ;
}
2015-03-04 15:00:23 +00:00
printf ( " \" %p \" [ \n " , state ) ;
2014-06-03 12:47:49 +00:00
printf ( " label = \" {encoder_state| " ) ;
2015-03-04 15:00:23 +00:00
printf ( " + type=%c \\ l " , state - > type ) ;
2016-08-10 00:46:23 +00:00
if ( ! state - > parent | | state - > frame ! = state - > parent - > global ) {
2014-06-03 12:47:49 +00:00
printf ( " |+ global \\ l " ) ;
}
2015-03-04 15:00:23 +00:00
if ( ! state - > parent | | state - > tile ! = state - > parent - > tile ) {
2014-06-03 12:47:49 +00:00
printf ( " |+ tile \\ l " ) ;
2015-03-04 15:00:23 +00:00
printf ( " - id = %d \\ l " , state - > tile - > id ) ;
printf ( " - lcu_offset_x = %d \\ l " , state - > tile - > lcu_offset_x ) ;
printf ( " - lcu_offset_y = %d \\ l " , state - > tile - > lcu_offset_y ) ;
printf ( " - lcu_offset_in_ts = %d \\ l " , state - > tile - > lcu_offset_in_ts ) ;
2014-06-03 12:47:49 +00:00
}
2015-03-04 15:00:23 +00:00
if ( ! state - > parent | | state - > slice ! = state - > parent - > slice ) {
2014-06-03 12:47:49 +00:00
printf ( " |+ slice \\ l " ) ;
2015-03-04 15:00:23 +00:00
printf ( " - id = %d \\ l " , state - > slice - > id ) ;
printf ( " - start_in_ts = %d \\ l " , state - > slice - > start_in_ts ) ;
printf ( " - end_in_ts = %d \\ l " , state - > slice - > end_in_ts ) ;
printf ( " - start_in_rs = %d \\ l " , state - > slice - > start_in_rs ) ;
printf ( " - end_in_rs = %d \\ l " , state - > slice - > end_in_rs ) ;
2014-06-03 12:47:49 +00:00
}
2015-03-04 15:00:23 +00:00
if ( ! state - > parent | | state - > wfrow ! = state - > parent - > wfrow ) {
2014-06-03 12:47:49 +00:00
printf ( " |+ wfrow \\ l " ) ;
2015-03-04 15:00:23 +00:00
printf ( " - lcu_offset_y = %d \\ l " , state - > wfrow - > lcu_offset_y ) ;
2014-06-03 12:47:49 +00:00
}
printf ( " } \" \n " ) ;
printf ( " ] \n " ) ;
2015-03-04 15:00:23 +00:00
if ( state - > parent ) {
printf ( " \" %p \" -> \" %p \" \n " , state - > parent , state ) ;
2014-06-03 12:47:49 +00:00
}
2015-03-04 15:00:23 +00:00
for ( i = 0 ; state - > children [ i ] . encoder_control ; + + i ) {
encoder_state_dump_graphviz ( & state - > children [ i ] ) ;
2014-06-03 12:47:49 +00:00
}
2015-03-04 15:00:23 +00:00
if ( ! state - > parent ) {
2014-06-03 12:47:49 +00:00
printf ( " } \n " ) ;
//Empty lines (easier to copy-paste)
printf ( " \n \n \n \n \n " ) ;
}
}
2015-09-14 09:43:28 +00:00
# endif //KVZ_DEBUG_PRINT_THREADING_INFO
2014-06-03 12:47:49 +00:00
2015-08-26 08:50:27 +00:00
int kvz_encoder_state_init ( encoder_state_t * const child_state , encoder_state_t * const parent_state ) {
2014-06-03 12:47:49 +00:00
//We require that, if parent_state is NULL:
//child_state->encoder_control is set
//
//If parent_state is not NULL, the following variable should either be set to NULL,
//in order to inherit from parent, or should point to a valid structure:
2016-08-10 00:46:23 +00:00
//child_state->frame
2014-06-03 12:47:49 +00:00
//child_state->tile
//child_state->slice
//child_state->wfrow
child_state - > parent = parent_state ;
2015-03-04 10:25:42 +00:00
child_state - > children = MALLOC ( encoder_state_t , 1 ) ;
2014-06-03 12:47:49 +00:00
child_state - > children [ 0 ] . encoder_control = NULL ;
2017-05-23 11:01:48 +00:00
child_state - > crypto_hdl = NULL ;
2017-05-08 07:54:06 +00:00
child_state - > must_code_qp_delta = false ;
2014-06-13 09:58:12 +00:00
child_state - > tqj_bitstream_written = NULL ;
child_state - > tqj_recon_done = NULL ;
2014-06-03 12:47:49 +00:00
if ( ! parent_state ) {
2015-03-04 10:26:57 +00:00
const encoder_control_t * const encoder = child_state - > encoder_control ;
2014-06-03 12:47:49 +00:00
child_state - > type = ENCODER_STATE_TYPE_MAIN ;
assert ( child_state - > encoder_control ) ;
2016-08-10 00:46:23 +00:00
child_state - > frame = MALLOC ( encoder_state_config_frame_t , 1 ) ;
if ( ! child_state - > frame | | ! encoder_state_config_frame_init ( child_state ) ) {
fprintf ( stderr , " Could not initialize encoder_state->frame! \n " ) ;
2014-06-03 12:47:49 +00:00
return 0 ;
}
2015-03-04 11:48:58 +00:00
child_state - > tile = MALLOC ( encoder_state_config_tile_t , 1 ) ;
2014-06-03 12:47:49 +00:00
if ( ! child_state - > tile | | ! encoder_state_config_tile_init ( child_state , 0 , 0 , encoder - > in . width , encoder - > in . height , encoder - > in . width_in_lcu , encoder - > in . height_in_lcu ) ) {
fprintf ( stderr , " Could not initialize encoder_state->tile! \n " ) ;
return 0 ;
}
2016-11-15 22:43:04 +00:00
2015-03-04 11:48:58 +00:00
child_state - > slice = MALLOC ( encoder_state_config_slice_t , 1 ) ;
2014-06-03 12:47:49 +00:00
if ( ! child_state - > slice | | ! encoder_state_config_slice_init ( child_state , 0 , encoder - > in . width_in_lcu * encoder - > in . height_in_lcu - 1 ) ) {
fprintf ( stderr , " Could not initialize encoder_state->slice! \n " ) ;
return 0 ;
}
2015-03-04 11:48:58 +00:00
child_state - > wfrow = MALLOC ( encoder_state_config_wfrow_t , 1 ) ;
2014-06-03 12:47:49 +00:00
if ( ! child_state - > wfrow | | ! encoder_state_config_wfrow_init ( child_state , 0 ) ) {
fprintf ( stderr , " Could not initialize encoder_state->wfrow! \n " ) ;
return 0 ;
}
} else {
child_state - > encoder_control = parent_state - > encoder_control ;
2016-08-10 00:46:23 +00:00
if ( ! child_state - > frame ) child_state - > frame = parent_state - > frame ;
2014-06-03 12:47:49 +00:00
if ( ! child_state - > tile ) child_state - > tile = parent_state - > tile ;
if ( ! child_state - > slice ) child_state - > slice = parent_state - > slice ;
if ( ! child_state - > wfrow ) child_state - > wfrow = parent_state - > wfrow ;
}
2015-08-26 08:50:27 +00:00
kvz_bitstream_init ( & child_state - > stream ) ;
2014-06-03 12:47:49 +00:00
// Set CABAC output bitstream
child_state - > cabac . stream = & child_state - > stream ;
//Create sub-encoders
{
2015-03-04 10:26:57 +00:00
const encoder_control_t * const encoder = child_state - > encoder_control ;
2014-06-03 12:47:49 +00:00
int child_count = 0 ;
//We first check the type of this element.
//If it's a MAIN, it can allow both slices or tiles as child
//If it's a TILE, it can allow slices as child, if its parent is not a slice, or wavefront rows if there is no other children
//If it's a SLICE, it can allow tiles as child, if its parent is not a tile, or wavefront rows if there is no other children
//If it's a WAVEFRONT_ROW, it doesn't allow any children
int children_allow_wavefront_row = 0 ;
int children_allow_slice = 0 ;
int children_allow_tile = 0 ;
int range_start ;
2017-02-08 19:27:20 +00:00
// First index of this encoder state in tile scan order.
int start_in_ts ;
// Index of the first LCU after this state in tile scan order.
int end_in_ts ;
2014-06-03 12:47:49 +00:00
switch ( child_state - > type ) {
case ENCODER_STATE_TYPE_MAIN :
children_allow_slice = 1 ;
children_allow_tile = 1 ;
start_in_ts = 0 ;
2014-06-05 12:54:58 +00:00
end_in_ts = child_state - > tile - > frame - > width_in_lcu * child_state - > tile - > frame - > height_in_lcu ;
2014-06-03 12:47:49 +00:00
break ;
case ENCODER_STATE_TYPE_SLICE :
assert ( child_state - > parent ) ;
if ( child_state - > parent - > type ! = ENCODER_STATE_TYPE_TILE ) children_allow_tile = 1 ;
start_in_ts = child_state - > slice - > start_in_ts ;
2017-02-08 19:27:20 +00:00
end_in_ts = child_state - > slice - > end_in_ts + 1 ;
int num_wpp_rows = ( end_in_ts - start_in_ts ) / child_state - > tile - > frame - > width_in_lcu ;
2017-02-06 11:00:25 +00:00
children_allow_wavefront_row = encoder - > cfg . wpp & & num_wpp_rows > 1 ;
2014-06-03 12:47:49 +00:00
break ;
case ENCODER_STATE_TYPE_TILE :
assert ( child_state - > parent ) ;
if ( child_state - > parent - > type ! = ENCODER_STATE_TYPE_SLICE ) children_allow_slice = 1 ;
2017-02-06 11:00:25 +00:00
children_allow_wavefront_row =
encoder - > cfg . wpp & & child_state - > tile - > frame - > height_in_lcu > 1 ;
2014-06-03 12:47:49 +00:00
start_in_ts = child_state - > tile - > lcu_offset_in_ts ;
2014-06-05 12:54:58 +00:00
end_in_ts = child_state - > tile - > lcu_offset_in_ts + child_state - > tile - > frame - > width_in_lcu * child_state - > tile - > frame - > height_in_lcu ;
2014-06-03 12:47:49 +00:00
break ;
case ENCODER_STATE_TYPE_WAVEFRONT_ROW :
//GCC tries to be too clever...
start_in_ts = - 1 ;
end_in_ts = - 1 ;
break ;
default :
fprintf ( stderr , " Invalid encoder_state->type %d! \n " , child_state - > type ) ;
assert ( 0 ) ;
return 0 ;
}
range_start = start_in_ts ;
//printf("%c-%p: start_in_ts=%d, end_in_ts=%d\n",child_state->type, child_state, start_in_ts, end_in_ts);
while ( range_start < end_in_ts & & ( children_allow_slice | | children_allow_tile ) ) {
2015-03-04 10:25:42 +00:00
encoder_state_t * new_child = NULL ;
2014-06-03 12:47:49 +00:00
int range_end_slice = range_start ; //Will be incremented to get the range of the "thing"
int range_end_tile = range_start ; //Will be incremented to get the range of the "thing"
2015-08-26 08:50:27 +00:00
int tile_allowed = kvz_lcu_at_tile_start ( encoder , range_start ) & & children_allow_tile ;
int slice_allowed = kvz_lcu_at_slice_start ( encoder , range_start ) & & children_allow_slice ;
2014-06-03 12:47:49 +00:00
//Find the smallest structure following the cursor
if ( slice_allowed ) {
2015-08-26 08:50:27 +00:00
while ( ! kvz_lcu_at_slice_end ( encoder , range_end_slice ) ) {
2014-06-03 12:47:49 +00:00
+ + range_end_slice ;
}
}
if ( tile_allowed ) {
2015-08-26 08:50:27 +00:00
while ( ! kvz_lcu_at_tile_end ( encoder , range_end_tile ) ) {
2014-06-03 12:47:49 +00:00
+ + range_end_tile ;
}
}
//printf("range_start=%d, range_end_slice=%d, range_end_tile=%d, tile_allowed=%d, slice_allowed=%d end_in_ts=%d\n",range_start,range_end_slice,range_end_tile,tile_allowed,slice_allowed,end_in_ts);
if ( ( ! tile_allowed | | ( range_end_slice > = range_end_tile ) ) & & ! new_child & & slice_allowed ) {
//Create a slice
new_child = & child_state - > children [ child_count ] ;
new_child - > encoder_control = encoder ;
2016-08-10 00:46:23 +00:00
new_child - > type = ENCODER_STATE_TYPE_SLICE ;
new_child - > frame = child_state - > frame ;
new_child - > tile = child_state - > tile ;
2014-06-03 12:47:49 +00:00
new_child - > wfrow = child_state - > wfrow ;
2015-03-04 11:48:58 +00:00
new_child - > slice = MALLOC ( encoder_state_config_slice_t , 1 ) ;
2014-06-03 12:47:49 +00:00
if ( ! new_child - > slice | | ! encoder_state_config_slice_init ( new_child , range_start , range_end_slice ) ) {
fprintf ( stderr , " Could not initialize encoder_state->slice! \n " ) ;
return 0 ;
}
}
if ( ( ! slice_allowed | | ( range_end_slice < range_end_tile ) ) & & ! new_child & & tile_allowed ) {
//Create a tile
int tile_id = encoder - > tiles_tile_id [ range_start ] ;
2017-02-06 11:00:25 +00:00
int tile_x = tile_id % encoder - > cfg . tiles_width_count ;
int tile_y = tile_id / encoder - > cfg . tiles_width_count ;
2014-06-03 12:47:49 +00:00
int lcu_offset_x = encoder - > tiles_col_bd [ tile_x ] ;
int lcu_offset_y = encoder - > tiles_row_bd [ tile_y ] ;
int width_in_lcu = encoder - > tiles_col_bd [ tile_x + 1 ] - encoder - > tiles_col_bd [ tile_x ] ;
int height_in_lcu = encoder - > tiles_row_bd [ tile_y + 1 ] - encoder - > tiles_row_bd [ tile_y ] ;
int width = MIN ( width_in_lcu * LCU_WIDTH , encoder - > in . width - lcu_offset_x * LCU_WIDTH ) ;
int height = MIN ( height_in_lcu * LCU_WIDTH , encoder - > in . height - lcu_offset_y * LCU_WIDTH ) ;
new_child = & child_state - > children [ child_count ] ;
new_child - > encoder_control = encoder ;
2016-08-10 00:46:23 +00:00
new_child - > type = ENCODER_STATE_TYPE_TILE ;
new_child - > frame = child_state - > frame ;
new_child - > tile = MALLOC ( encoder_state_config_tile_t , 1 ) ;
2014-06-03 12:47:49 +00:00
new_child - > slice = child_state - > slice ;
new_child - > wfrow = child_state - > wfrow ;
if ( ! new_child - > tile | | ! encoder_state_config_tile_init ( new_child , lcu_offset_x , lcu_offset_y , width , height , width_in_lcu , height_in_lcu ) ) {
fprintf ( stderr , " Could not initialize encoder_state->tile! \n " ) ;
return 0 ;
}
}
if ( new_child ) {
2015-03-04 10:25:42 +00:00
child_state - > children = realloc ( child_state - > children , sizeof ( encoder_state_t ) * ( 2 + child_count ) ) ;
2014-06-03 12:47:49 +00:00
if ( ! child_state - > children ) {
fprintf ( stderr , " Failed to allocate memory for children... \n " ) ;
return 0 ;
}
2015-05-05 06:40:24 +00:00
child_state - > children [ 1 + child_count ] . encoder_control = NULL ;
2014-06-03 12:47:49 +00:00
//Fix children parent (since we changed the address), except for the last one which is not ready yet
{
int i , j ;
for ( i = 0 ; child_state - > children [ i ] . encoder_control & & i < child_count ; + + i ) {
for ( j = 0 ; child_state - > children [ i ] . children [ j ] . encoder_control ; + + j ) {
child_state - > children [ i ] . children [ j ] . parent = & child_state - > children [ i ] ;
}
for ( j = 0 ; j < child_state - > children [ i ] . lcu_order_count ; + + j ) {
child_state - > children [ i ] . lcu_order [ j ] . encoder_state = & child_state - > children [ i ] ;
}
child_state - > children [ i ] . cabac . stream = & child_state - > children [ i ] . stream ;
}
}
2015-08-26 08:50:27 +00:00
if ( ! kvz_encoder_state_init ( & child_state - > children [ child_count ] , child_state ) ) {
2014-06-03 12:47:49 +00:00
fprintf ( stderr , " Unable to init child... \n " ) ;
return 0 ;
}
child_count + = 1 ;
}
range_start = MAX ( range_end_slice , range_end_tile ) + 1 ;
}
//We create wavefronts only if we have no children
if ( children_allow_wavefront_row & & child_count = = 0 ) {
int first_row = encoder - > tiles_ctb_addr_ts_to_rs [ start_in_ts ] / encoder - > in . width_in_lcu ;
int last_row = encoder - > tiles_ctb_addr_ts_to_rs [ start_in_ts ] / encoder - > in . width_in_lcu ;
int num_rows ;
int i ;
assert ( ! ( children_allow_slice | | children_allow_tile ) ) ;
assert ( child_count = = 0 ) ;
for ( i = start_in_ts ; i < end_in_ts ; + + i ) {
const int row = encoder - > tiles_ctb_addr_ts_to_rs [ i ] / encoder - > in . width_in_lcu ;
if ( row < first_row ) first_row = row ;
if ( row > last_row ) last_row = row ;
}
num_rows = last_row - first_row + 1 ;
//When entropy_coding_sync_enabled_flag is equal to 1 and the first coding tree block in a slice is not the first coding
//tree block of a row of coding tree blocks in a tile, it is a requirement of bitstream conformance that the last coding tree
//block in the slice shall belong to the same row of coding tree blocks as the first coding tree block in the slice.
if ( encoder - > tiles_ctb_addr_ts_to_rs [ start_in_ts ] % encoder - > in . width_in_lcu ! = child_state - > tile - > lcu_offset_x ) {
if ( num_rows > 1 ) {
fprintf ( stderr , " Invalid: first CTB in slice %d is not at the tile %d edge, and the slice spans on more than one row. \n " , child_state - > slice - > id , child_state - > tile - > id ) ;
return 0 ;
}
}
//FIXME Do the same kind of check if we implement slice segments
child_count = num_rows ;
2015-03-04 10:25:42 +00:00
child_state - > children = realloc ( child_state - > children , sizeof ( encoder_state_t ) * ( num_rows + 1 ) ) ;
2014-06-03 12:47:49 +00:00
child_state - > children [ num_rows ] . encoder_control = NULL ;
for ( i = 0 ; i < num_rows ; + + i ) {
2015-03-04 10:25:42 +00:00
encoder_state_t * new_child = & child_state - > children [ i ] ;
2014-06-03 12:47:49 +00:00
new_child - > encoder_control = encoder ;
2016-08-10 00:46:23 +00:00
new_child - > type = ENCODER_STATE_TYPE_WAVEFRONT_ROW ;
new_child - > frame = child_state - > frame ;
new_child - > tile = child_state - > tile ;
2014-06-03 12:47:49 +00:00
new_child - > slice = child_state - > slice ;
2015-03-04 11:48:58 +00:00
new_child - > wfrow = MALLOC ( encoder_state_config_wfrow_t , 1 ) ;
2014-06-03 12:47:49 +00:00
if ( ! new_child - > wfrow | | ! encoder_state_config_wfrow_init ( new_child , i ) ) {
fprintf ( stderr , " Could not initialize encoder_state->wfrow! \n " ) ;
return 0 ;
}
2015-08-26 08:50:27 +00:00
if ( ! kvz_encoder_state_init ( new_child , child_state ) ) {
2014-06-03 12:47:49 +00:00
fprintf ( stderr , " Unable to init child... \n " ) ;
return 0 ;
}
}
}
child_state - > is_leaf = ( child_count = = 0 ) ;
//This node is a leaf, compute LCU-order
if ( child_state - > is_leaf ) {
//All LCU computations are relative to the tile
//Remark: this could be optimized, but since it's run only once, it's better to do it in a understandable way.
//By default, the full tile
int i ;
int lcu_id ;
int lcu_start = 0 ;
//End is the element AFTER the end (iterate < lcu_end)
2014-06-05 12:54:58 +00:00
int lcu_end = child_state - > tile - > frame - > width_in_lcu * child_state - > tile - > frame - > height_in_lcu ;
2014-06-03 12:47:49 +00:00
//Restrict to the current slice if needed
lcu_start = MAX ( lcu_start , child_state - > slice - > start_in_ts - child_state - > tile - > lcu_offset_in_ts ) ;
lcu_end = MIN ( lcu_end , child_state - > slice - > end_in_ts - child_state - > tile - > lcu_offset_in_ts + 1 ) ;
//Restrict to the current wavefront row if needed
if ( child_state - > type = = ENCODER_STATE_TYPE_WAVEFRONT_ROW ) {
2014-06-05 12:54:58 +00:00
lcu_start = MAX ( lcu_start , ( child_state - > wfrow - > lcu_offset_y ) * child_state - > tile - > frame - > width_in_lcu ) ;
lcu_end = MIN ( lcu_end , ( child_state - > wfrow - > lcu_offset_y + 1 ) * child_state - > tile - > frame - > width_in_lcu ) ;
2014-06-03 12:47:49 +00:00
}
child_state - > lcu_order_count = lcu_end - lcu_start ;
2015-03-04 11:49:59 +00:00
child_state - > lcu_order = MALLOC ( lcu_order_element_t , child_state - > lcu_order_count ) ;
2014-06-03 12:47:49 +00:00
assert ( child_state - > lcu_order ) ;
for ( i = 0 ; i < child_state - > lcu_order_count ; + + i ) {
lcu_id = lcu_start + i ;
child_state - > lcu_order [ i ] . encoder_state = child_state ;
child_state - > lcu_order [ i ] . id = lcu_id ;
child_state - > lcu_order [ i ] . index = i ;
2014-06-05 12:54:58 +00:00
child_state - > lcu_order [ i ] . position . x = lcu_id % child_state - > tile - > frame - > width_in_lcu ;
child_state - > lcu_order [ i ] . position . y = lcu_id / child_state - > tile - > frame - > width_in_lcu ;
2014-06-03 12:47:49 +00:00
child_state - > lcu_order [ i ] . position_px . x = child_state - > lcu_order [ i ] . position . x * LCU_WIDTH ;
child_state - > lcu_order [ i ] . position_px . y = child_state - > lcu_order [ i ] . position . y * LCU_WIDTH ;
child_state - > lcu_order [ i ] . size . x = MIN ( LCU_WIDTH , encoder - > in . width - ( child_state - > tile - > lcu_offset_x * LCU_WIDTH + child_state - > lcu_order [ i ] . position_px . x ) ) ;
child_state - > lcu_order [ i ] . size . y = MIN ( LCU_WIDTH , encoder - > in . height - ( child_state - > tile - > lcu_offset_y * LCU_WIDTH + child_state - > lcu_order [ i ] . position_px . y ) ) ;
2015-08-26 08:50:27 +00:00
child_state - > lcu_order [ i ] . first_row = kvz_lcu_in_first_row ( child_state , child_state - > tile - > lcu_offset_in_ts + lcu_id ) ;
child_state - > lcu_order [ i ] . last_row = kvz_lcu_in_last_row ( child_state , child_state - > tile - > lcu_offset_in_ts + lcu_id ) ;
child_state - > lcu_order [ i ] . first_column = kvz_lcu_in_first_column ( child_state , child_state - > tile - > lcu_offset_in_ts + lcu_id ) ;
child_state - > lcu_order [ i ] . last_column = kvz_lcu_in_last_column ( child_state , child_state - > tile - > lcu_offset_in_ts + lcu_id ) ;
2014-06-03 12:47:49 +00:00
child_state - > lcu_order [ i ] . above = NULL ;
child_state - > lcu_order [ i ] . below = NULL ;
child_state - > lcu_order [ i ] . left = NULL ;
child_state - > lcu_order [ i ] . right = NULL ;
if ( ! child_state - > lcu_order [ i ] . first_row ) {
//Find LCU above
if ( child_state - > type = = ENCODER_STATE_TYPE_WAVEFRONT_ROW ) {
int j ;
//For all previous wavefront rows
for ( j = 0 ; & child_state - > parent - > children [ j ] ! = child_state & & child_state - > parent - > children [ j ] . encoder_control ; + + j ) {
if ( child_state - > parent - > children [ j ] . wfrow - > lcu_offset_y = = child_state - > wfrow - > lcu_offset_y - 1 ) {
int k ;
for ( k = 0 ; k < child_state - > parent - > children [ j ] . lcu_order_count ; + + k ) {
if ( child_state - > parent - > children [ j ] . lcu_order [ k ] . position . x = = child_state - > lcu_order [ i ] . position . x ) {
assert ( child_state - > parent - > children [ j ] . lcu_order [ k ] . position . y = = child_state - > lcu_order [ i ] . position . y - 1 ) ;
child_state - > lcu_order [ i ] . above = & child_state - > parent - > children [ j ] . lcu_order [ k ] ;
}
}
}
}
} else {
2014-06-05 12:54:58 +00:00
child_state - > lcu_order [ i ] . above = & child_state - > lcu_order [ i - child_state - > tile - > frame - > width_in_lcu ] ;
2014-06-03 12:47:49 +00:00
}
assert ( child_state - > lcu_order [ i ] . above ) ;
child_state - > lcu_order [ i ] . above - > below = & child_state - > lcu_order [ i ] ;
}
if ( ! child_state - > lcu_order [ i ] . first_column ) {
child_state - > lcu_order [ i ] . left = & child_state - > lcu_order [ i - 1 ] ;
assert ( child_state - > lcu_order [ i ] . left - > position . x = = child_state - > lcu_order [ i ] . position . x - 1 ) ;
child_state - > lcu_order [ i ] . left - > right = & child_state - > lcu_order [ i ] ;
}
}
} else {
child_state - > lcu_order_count = 0 ;
child_state - > lcu_order = NULL ;
}
}
//Validate the structure
if ( child_state - > type = = ENCODER_STATE_TYPE_TILE ) {
if ( child_state - > tile - > lcu_offset_in_ts < child_state - > slice - > start_in_ts ) {
fprintf ( stderr , " Tile %d starts before slice %d, in which it should be included! \n " , child_state - > tile - > id , child_state - > slice - > id ) ;
return 0 ;
}
2014-06-05 12:54:58 +00:00
if ( child_state - > tile - > lcu_offset_in_ts + child_state - > tile - > frame - > width_in_lcu * child_state - > tile - > frame - > height_in_lcu - 1 > child_state - > slice - > end_in_ts ) {
2014-06-03 12:47:49 +00:00
fprintf ( stderr , " Tile %d ends after slice %d, in which it should be included! \n " , child_state - > tile - > id , child_state - > slice - > id ) ;
return 0 ;
}
}
if ( child_state - > type = = ENCODER_STATE_TYPE_SLICE ) {
if ( child_state - > slice - > start_in_ts < child_state - > tile - > lcu_offset_in_ts ) {
fprintf ( stderr , " Slice %d starts before tile %d, in which it should be included! \n " , child_state - > slice - > id , child_state - > tile - > id ) ;
return 0 ;
}
2014-06-05 12:54:58 +00:00
if ( child_state - > slice - > end_in_ts > child_state - > tile - > lcu_offset_in_ts + child_state - > tile - > frame - > width_in_lcu * child_state - > tile - > frame - > height_in_lcu - 1 ) {
2014-06-03 12:47:49 +00:00
fprintf ( stderr , " Slice %d ends after tile %d, in which it should be included! \n " , child_state - > slice - > id , child_state - > tile - > id ) ;
return 0 ;
}
}
2015-09-14 09:43:28 +00:00
# ifdef KVZ_DEBUG_PRINT_THREADING_INFO
2014-06-03 12:47:49 +00:00
if ( ! parent_state ) encoder_state_dump_graphviz ( child_state ) ;
2015-09-14 09:43:28 +00:00
# endif //KVZ_DEBUG_PRINT_THREADING_INFO
2014-06-03 12:47:49 +00:00
return 1 ;
}
2015-08-26 08:50:27 +00:00
void kvz_encoder_state_finalize ( encoder_state_t * const state ) {
2015-03-04 15:00:23 +00:00
if ( state - > children ) {
2014-06-03 12:47:49 +00:00
int i = 0 ;
2015-03-04 15:00:23 +00:00
for ( i = 0 ; state - > children [ i ] . encoder_control ; + + i ) {
2015-08-26 08:50:27 +00:00
kvz_encoder_state_finalize ( & state - > children [ i ] ) ;
2014-06-03 12:47:49 +00:00
}
2019-08-28 15:45:58 +00:00
2015-03-04 15:00:23 +00:00
FREE_POINTER ( state - > children ) ;
2014-06-03 12:47:49 +00:00
}
2015-03-04 15:00:23 +00:00
FREE_POINTER ( state - > lcu_order ) ;
state - > lcu_order_count = 0 ;
2014-06-03 12:47:49 +00:00
2015-03-04 15:00:23 +00:00
if ( ! state - > parent | | ( state - > parent - > wfrow ! = state - > wfrow ) ) {
FREE_POINTER ( state - > wfrow ) ;
2014-06-03 12:47:49 +00:00
}
2015-03-04 15:00:23 +00:00
if ( ! state - > parent | | ( state - > parent - > slice ! = state - > slice ) ) {
FREE_POINTER ( state - > slice ) ;
2014-06-03 12:47:49 +00:00
}
2015-03-04 15:00:23 +00:00
if ( ! state - > parent | | ( state - > parent - > tile ! = state - > tile ) ) {
encoder_state_config_tile_finalize ( state ) ;
FREE_POINTER ( state - > tile ) ;
2014-06-03 12:47:49 +00:00
}
2016-08-10 00:46:23 +00:00
if ( ! state - > parent | | ( state - > parent - > frame ! = state - > frame ) ) {
encoder_state_config_frame_finalize ( state ) ;
FREE_POINTER ( state - > frame ) ;
2014-06-03 12:47:49 +00:00
}
2019-08-28 15:45:58 +00:00
if ( ! state - > parent ) {
// End of the constraint structure
kvz_end_const ( state ) ;
}
2015-08-26 08:50:27 +00:00
kvz_bitstream_finalize ( & state - > stream ) ;
2017-04-04 12:36:08 +00:00
kvz_threadqueue_free_job ( & state - > tqj_recon_done ) ;
kvz_threadqueue_free_job ( & state - > tqj_bitstream_written ) ;
2015-04-29 11:24:33 +00:00
}