high and 422 profile checks. did some trellis quant changes. ITU has the h.262 spec from 2000 up on their site now for free.
This commit is contained in:
parent
df475dedd7
commit
ae31172c03
6 changed files with 507 additions and 112 deletions
|
@ -1125,7 +1125,7 @@ int32_t y262_ratectrl_get_slice_mb_quantizer( y262_t *ps_y262, y262_slice_encode
|
|||
{
|
||||
i_baseline = ( ps_slice_rc->i_slice_num_accumulated_quantizer * 5 );
|
||||
i_adjusted_slice_coded_size = ps_slice_rc->i_slice_coded_size - i_baseline;
|
||||
i_adjusted_slice_coded_size = MAX( 0, i_adjusted_slice_coded_size );
|
||||
i_adjusted_slice_coded_size = MAX( 100, i_adjusted_slice_coded_size );
|
||||
|
||||
i_extra_bits = ( int32_t )( ( ps_slice_rc->i_slice_bit_budget_extra * 0.8 ) * ( ( ( double )ps_slice_rc->i_slice_coded_scaled_satd ) / ps_slice_rc->i_slice_scaled_satd ) );
|
||||
i_extra_bits += ( int32_t )( ( ps_slice_rc->i_slice_bit_budget_extra * 0.2 ) * MAX( 0.0,
|
||||
|
@ -1155,6 +1155,7 @@ int32_t y262_ratectrl_get_slice_mb_quantizer( y262_t *ps_y262, y262_slice_encode
|
|||
if( ( ps_slice_rc->i_slice_bit_budget + i_extra_bits - i_adjusted_slice_coded_size ) > ( 512 + 9 ) )
|
||||
{
|
||||
double d_scale;
|
||||
d_scale = 1.0;
|
||||
if( i_adjusted_slice_coded_size > 0 && i_adjusted_slice_predicted_size > 0 )
|
||||
{
|
||||
d_scale = i_adjusted_slice_coded_size / ( double ) i_adjusted_slice_predicted_size;
|
||||
|
|
|
@ -612,19 +612,155 @@ void y262_quant8x8_trellis_copy_int16( int16_t *pi16_dst, const int16_t *pi16_sr
|
|||
}
|
||||
|
||||
|
||||
|
||||
typedef struct y262_trellis_node_s
|
||||
{
|
||||
struct y262_trellis_node_s *ps_next;
|
||||
int32_t i_cost;
|
||||
int16_t i16_num_level;
|
||||
int16_t i16_last_scan_idx;
|
||||
|
||||
int16_t rgi16_idx[ 8 * 8 ];
|
||||
int16_t rgi16_level[ 8 * 8 ];
|
||||
} y262_trellis_node_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t i_lambda;
|
||||
#define Y262_TRELLIS_MAX_ACTIVE_NODES 3
|
||||
#define Y262_RDOQ_NUM_NODES ( Y262_TRELLIS_MAX_ACTIVE_NODES * 3 )
|
||||
y262_trellis_node_t rgs_nodes[ Y262_RDOQ_NUM_NODES ];
|
||||
y262_trellis_node_t *ps_active_nodes;
|
||||
y262_trellis_node_t *ps_next_nodes;
|
||||
y262_trellis_node_t *ps_free_nodes;
|
||||
} y262_trellis_t;
|
||||
|
||||
|
||||
void y262_quant8x8_trellis_init( y262_t *ps_y262, y262_trellis_t *ps_trellis, int32_t i_lambda )
|
||||
{
|
||||
int32_t i_idx;
|
||||
|
||||
ps_trellis->i_lambda = i_lambda;
|
||||
ps_trellis->ps_free_nodes = NULL;
|
||||
for( i_idx = 0; i_idx < Y262_RDOQ_NUM_NODES - 1; i_idx++ )
|
||||
{
|
||||
ps_trellis->rgs_nodes[ i_idx ].ps_next = ps_trellis->ps_free_nodes;
|
||||
ps_trellis->ps_free_nodes = &ps_trellis->rgs_nodes[ i_idx ];
|
||||
}
|
||||
ps_trellis->rgs_nodes[ i_idx ].ps_next = NULL;
|
||||
ps_trellis->rgs_nodes[ i_idx ].i_cost = 0;
|
||||
ps_trellis->rgs_nodes[ i_idx ].i16_num_level = 0;
|
||||
ps_trellis->rgs_nodes[ i_idx ].i16_last_scan_idx = -1;
|
||||
ps_trellis->ps_active_nodes = &ps_trellis->rgs_nodes[ i_idx ];
|
||||
|
||||
}
|
||||
|
||||
void y262_trellis_spawn_trellis( y262_trellis_t *ps_trellis, y262_trellis_node_t *ps_from, int32_t i_ssd, int32_t i_co_idx, int32_t i_scan_idx, int32_t i_level )
|
||||
{
|
||||
y262_trellis_node_t *ps_to;
|
||||
int32_t i_new_cost;
|
||||
|
||||
ps_to = ps_trellis->ps_free_nodes;
|
||||
ps_trellis->ps_free_nodes = ps_to->ps_next;
|
||||
|
||||
ps_to->i16_num_level = ps_from->i16_num_level;
|
||||
ps_to->i16_last_scan_idx = ps_from->i16_last_scan_idx;
|
||||
ps_to->i_cost = ps_from->i_cost;
|
||||
memcpy( ps_to->rgi16_idx, ps_from->rgi16_idx, ps_from->i16_num_level * sizeof( int16_t ) );
|
||||
memcpy( ps_to->rgi16_level, ps_from->rgi16_level, ps_from->i16_num_level * sizeof( int16_t ) );
|
||||
|
||||
i_new_cost = ps_from->i_cost;
|
||||
if( i_level )
|
||||
{
|
||||
int32_t i_bits, i_bit_cost, i_run;
|
||||
|
||||
i_run = i_scan_idx - ps_from->i16_last_scan_idx - 1;
|
||||
i_bits = y262_size_run_level( i_run, i_level );
|
||||
i_bit_cost = ( ( i_bits * ps_trellis->i_lambda ) >> ( Y262_LAMBDA_BITS ) );
|
||||
i_new_cost += i_bit_cost;
|
||||
|
||||
ps_to->i16_last_scan_idx = i_scan_idx;
|
||||
ps_to->rgi16_idx[ ps_to->i16_num_level ] = i_co_idx;
|
||||
ps_to->rgi16_level[ ps_to->i16_num_level ] = i_level;
|
||||
ps_to->i16_num_level++;
|
||||
}
|
||||
i_new_cost += i_ssd;
|
||||
ps_to->i_cost = i_new_cost;
|
||||
ps_to->ps_next = ps_trellis->ps_next_nodes;
|
||||
ps_trellis->ps_next_nodes = ps_to;
|
||||
}
|
||||
|
||||
|
||||
void y262_trellis_shrink_trellis( y262_trellis_t *ps_trellis )
|
||||
{
|
||||
int32_t i_num_nodes;
|
||||
y262_trellis_node_t *ps_node, *ps_new_list, **pps_new_list, *ps_list;
|
||||
|
||||
ps_list = ps_trellis->ps_active_nodes;
|
||||
|
||||
ps_new_list = NULL;
|
||||
while( ps_list )
|
||||
{
|
||||
ps_node = ps_list;
|
||||
ps_list = ps_list->ps_next;
|
||||
|
||||
pps_new_list = &ps_new_list;
|
||||
while( *pps_new_list && ( *pps_new_list )->i_cost < ps_node->i_cost )
|
||||
{
|
||||
pps_new_list = &( *pps_new_list )->ps_next;
|
||||
}
|
||||
|
||||
if( *pps_new_list )
|
||||
{
|
||||
ps_node->ps_next = ( *pps_new_list );
|
||||
}
|
||||
else
|
||||
{
|
||||
ps_node->ps_next = NULL;
|
||||
}
|
||||
|
||||
*pps_new_list = ps_node;
|
||||
}
|
||||
ps_list = ps_new_list;
|
||||
i_num_nodes = 0;
|
||||
ps_trellis->ps_active_nodes = NULL;
|
||||
while( ps_list && i_num_nodes < Y262_TRELLIS_MAX_ACTIVE_NODES )
|
||||
{
|
||||
ps_node = ps_list;
|
||||
ps_list = ps_list->ps_next;
|
||||
|
||||
ps_node->ps_next = ps_trellis->ps_active_nodes;
|
||||
ps_trellis->ps_active_nodes = ps_node;
|
||||
i_num_nodes++;
|
||||
}
|
||||
while( ps_list )
|
||||
{
|
||||
ps_node = ps_list;
|
||||
ps_list = ps_list->ps_next;
|
||||
|
||||
ps_node->ps_next = ps_trellis->ps_free_nodes;
|
||||
ps_trellis->ps_free_nodes = ps_node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t y262_quant8x8_trellis_fw( y262_t *ps_y262, y262_slice_t *ps_slice, int16_t *pi_coeffs, int32_t i_stride, int32_t i_quantizer, bool_t b_intra )
|
||||
{
|
||||
int32_t i_dc, i_nz;
|
||||
int32_t i_coeff, i_start, i_num_coeff, i_last_coeff, i_idx, i_idx2, i_run, i_level;
|
||||
int32_t i_dc, i_nz, i_num_active_nodes;
|
||||
int32_t i_coeff, i_start, i_num_coeff, i_last_coeff, i_idx, i_run, i_level;
|
||||
int16_t rgi16_levels[ 64 ];
|
||||
int16_t rgi16_coeffs[ 64 ];
|
||||
int8_t rgi8_idx[ 64 ];
|
||||
int16_t rgi16_level[ 64 ];
|
||||
uint8_t *pui8_qmat;
|
||||
y262_macroblock_t *ps_mb;
|
||||
y262_trellis_t s_trellis;
|
||||
y262_trellis_node_t *ps_node, *ps_next, *ps_best;
|
||||
|
||||
int32_t i_active_toggle;
|
||||
int32_t i_candidate_level, i_dir, i_end, i_ssd, i_bits, i_cost, i_lambda;
|
||||
int32_t i_cost, i_lambda, i_ssd, i_candidate_level, i_dir, i_end;
|
||||
|
||||
assert( i_stride == 8 );
|
||||
|
||||
ps_mb = &ps_slice->s_macroblock;
|
||||
|
||||
|
@ -687,11 +823,7 @@ int32_t y262_quant8x8_trellis_fw( y262_t *ps_y262, y262_slice_t *ps_slice, int16
|
|||
return i_dc;
|
||||
}
|
||||
|
||||
memset( &ps_y262->trellis.rgi8_path_active, 0, sizeof( ps_y262->trellis.rgi8_path_active ) );
|
||||
memset( &ps_y262->trellis.rgi_path_cost, 0, sizeof( ps_y262->trellis.rgi_path_cost ) );
|
||||
|
||||
i_active_toggle = 0;
|
||||
ps_y262->trellis.rgi8_path_active[ i_active_toggle ][ 0 ] = 1;
|
||||
y262_quant8x8_trellis_init( ps_y262, &s_trellis, i_lambda );
|
||||
|
||||
for( i_idx = 0; i_idx < i_num_coeff; i_idx++ )
|
||||
{
|
||||
|
@ -706,6 +838,9 @@ int32_t y262_quant8x8_trellis_fw( y262_t *ps_y262, y262_slice_t *ps_slice, int16
|
|||
i_dir = 1;
|
||||
}
|
||||
i_end = i_level + i_dir * 2;
|
||||
i_num_active_nodes = 0;
|
||||
s_trellis.ps_next_nodes = NULL;
|
||||
|
||||
for( i_candidate_level = i_level; i_candidate_level != i_end; i_candidate_level += i_dir )
|
||||
{
|
||||
int32_t i_qm, i_qt, i_x, i_y;
|
||||
|
@ -741,72 +876,41 @@ int32_t y262_quant8x8_trellis_fw( y262_t *ps_y262, y262_slice_t *ps_slice, int16
|
|||
|
||||
i_ssd = ( i_coeff - rgi16_coeffs[ i_idx ] ) * ( i_coeff - rgi16_coeffs[ i_idx ] );
|
||||
|
||||
for( i_idx2 = i_idx; i_idx2 >= 0; i_idx2-- )
|
||||
for( ps_node = s_trellis.ps_active_nodes; ps_node; ps_node = ps_node->ps_next )
|
||||
{
|
||||
if( ps_y262->trellis.rgi8_path_active[ i_active_toggle ][ i_idx2 ] )
|
||||
{
|
||||
if( i_candidate_level != 0 )
|
||||
{
|
||||
int32_t i_run;
|
||||
if( i_idx2 > 0 )
|
||||
{
|
||||
i_run = rgi8_idx[ i_idx ] - ps_y262->trellis.rgi8_path_idx[ i_idx2 ][ i_idx2 ] - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
i_run = rgi8_idx[ i_idx ];
|
||||
}
|
||||
i_bits = y262_size_run_level( i_run, i_candidate_level );
|
||||
i_cost = ps_y262->trellis.rgi_path_cost[ i_idx2 ] + ( ( i_bits * i_lambda ) >> Y262_LAMBDA_BITS ) + i_ssd;
|
||||
|
||||
if( !ps_y262->trellis.rgi8_path_active[ !i_active_toggle ][ i_idx2 + 1 ] || i_cost < ps_y262->trellis.rgi_path_cost[ i_idx2 + 1 ] )
|
||||
{
|
||||
y262_quant8x8_trellis_copy_int8( &ps_y262->trellis.rgi8_path_idx[ i_idx2 + 1 ][ 0 ], &ps_y262->trellis.rgi8_path_idx[ i_idx2 ][ 0 ], ( i_idx2 + 1 ) );
|
||||
y262_quant8x8_trellis_copy_int16( &ps_y262->trellis.rgi16_path_level[ i_idx2 + 1 ][ 0 ], &ps_y262->trellis.rgi16_path_level[ i_idx2 ][ 0 ], ( i_idx2 + 1 ) );
|
||||
ps_y262->trellis.rgi8_path_idx[ i_idx2 + 1 ][ i_idx2 + 1 ] = rgi8_idx[ i_idx ];
|
||||
ps_y262->trellis.rgi16_path_level[ i_idx2 + 1 ][ i_idx2 + 1 ] = i_candidate_level;
|
||||
ps_y262->trellis.rgi8_path_active[ !i_active_toggle ][ i_idx2 + 1 ] = 1;
|
||||
ps_y262->trellis.rgi_path_cost[ i_idx2 + 1 ] = i_cost;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* last coeff candidate iter, we can overwrite/activate current path */
|
||||
i_cost = ps_y262->trellis.rgi_path_cost[ i_idx2 ] + i_ssd;
|
||||
if( !ps_y262->trellis.rgi8_path_active[ !i_active_toggle ][ i_idx2 ] || i_cost < ps_y262->trellis.rgi_path_cost[ i_idx2 ] )
|
||||
{
|
||||
ps_y262->trellis.rgi8_path_active[ !i_active_toggle ][ i_idx2 ] = 1;
|
||||
ps_y262->trellis.rgi_path_cost[ i_idx2 ] = i_cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
y262_trellis_spawn_trellis( &s_trellis, ps_node, i_ssd, rgui8_y262_scan_0_table[ rgi8_idx[ i_idx ] ], rgi8_idx[ i_idx ], i_candidate_level );
|
||||
i_num_active_nodes++;
|
||||
}
|
||||
}
|
||||
memset( &ps_y262->trellis.rgi8_path_active[ i_active_toggle ][ 0 ], 0, sizeof( int8_t ) * 65 );
|
||||
i_active_toggle = i_active_toggle^1;
|
||||
for( ps_node = s_trellis.ps_active_nodes; ps_node; ps_node = ps_next )
|
||||
{
|
||||
ps_next = ps_node->ps_next;
|
||||
ps_node->ps_next = s_trellis.ps_free_nodes;
|
||||
s_trellis.ps_free_nodes = ps_node;
|
||||
}
|
||||
s_trellis.ps_active_nodes = s_trellis.ps_next_nodes;
|
||||
|
||||
|
||||
if( i_num_active_nodes > Y262_TRELLIS_MAX_ACTIVE_NODES )
|
||||
{
|
||||
y262_trellis_shrink_trellis( &s_trellis );
|
||||
}
|
||||
}
|
||||
|
||||
i_cost = MAX_COST;
|
||||
i_idx2 = 0;
|
||||
for( i_idx = 0; i_idx <= i_num_coeff; i_idx++ )
|
||||
for( ps_node = s_trellis.ps_active_nodes; ps_node; ps_node = ps_node->ps_next )
|
||||
{
|
||||
if( ps_y262->trellis.rgi8_path_active[ i_active_toggle ][ i_idx ] && ps_y262->trellis.rgi_path_cost[ i_idx ] < i_cost )
|
||||
if( ps_node->i_cost < i_cost )
|
||||
{
|
||||
i_idx2 = i_idx;
|
||||
i_cost = ps_y262->trellis.rgi_path_cost[ i_idx ];
|
||||
i_cost = ps_node->i_cost;
|
||||
ps_best = ps_node;
|
||||
}
|
||||
}
|
||||
for( i_idx = 1; i_idx <= i_idx2; i_idx++ )
|
||||
for( i_idx = 0; i_idx < ps_best->i16_num_level; i_idx++ )
|
||||
{
|
||||
int32_t i_x, i_y;
|
||||
if( ps_y262->trellis.rgi16_path_level[ i_idx2 ][ i_idx ] != rgi16_level[ i_idx - 1 ] )
|
||||
{
|
||||
i_idx = i_idx;
|
||||
}
|
||||
i_x = rgui8_y262_scan_0_table[ ps_y262->trellis.rgi8_path_idx[ i_idx2 ][ i_idx ] ] % 8;
|
||||
i_y = rgui8_y262_scan_0_table[ ps_y262->trellis.rgi8_path_idx[ i_idx2 ][ i_idx ] ] / 8;
|
||||
pi_coeffs[ i_x + i_y * i_stride ] = ps_y262->trellis.rgi16_path_level[ i_idx2 ][ i_idx ];
|
||||
pi_coeffs[ ps_best->rgi16_idx[ i_idx ] ] = ps_best->rgi16_level[ i_idx ];
|
||||
}
|
||||
return i_idx2 != 0;
|
||||
return ( ps_best->i16_num_level > 0 );
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -768,11 +768,4 @@ typedef struct y262_s {
|
|||
int32_t i_psyrd_strength;
|
||||
int32_t i_quality_for_speed;
|
||||
|
||||
struct {
|
||||
int8_t rgi8_path_active[ 2 ][ 65 ];
|
||||
int8_t rgi8_path_idx[ 65 ][ 65 ];
|
||||
int16_t rgi16_path_level[ 65 ][ 65 ];
|
||||
int32_t rgi_path_cost[ 65 ];
|
||||
} trellis;
|
||||
|
||||
} y262_t;
|
||||
|
|
|
@ -114,14 +114,14 @@ void *y262_create( y262_configuration_t *ps_config )
|
|||
}
|
||||
|
||||
|
||||
bool_t y262_validate_level( y262_t *ps_y262, int32_t i_level, bool_t b_forderive )
|
||||
bool_t y262_validate_level_simple_main_profile( y262_t *ps_y262, int32_t i_level, bool_t b_forderive )
|
||||
{
|
||||
int32_t i_idx, i_luma_sample_rate;
|
||||
int32_t rgi_max_hfcode[ 4 ] = { 7, 8, 9, 9 };
|
||||
int32_t rgi_max_vfcode[ 4 ] = { 4, 5, 5, 5 };
|
||||
int32_t rgi_max_frcode[ 4 ] = { 5, 5, 8, 8 };
|
||||
int32_t rgi_max_pic_width[ 4 ] = { 352, 720, 1440, 1920 };
|
||||
int32_t rgi_max_pic_height[ 4 ] = { 288, 576, 1152, 1152 };
|
||||
int32_t rgi_max_pic_height[ 4 ] = { 288, 576, 1088, 1088 };
|
||||
int32_t rgi_fr[ 16 ] = { 100, 24, 24, 25, 30, 30, 50, 60, 60, 100, 100, 100, 100, 100, 100, 100 };
|
||||
int32_t rgi_max_fr[ 4 ] = { 30, 30, 60, 60 };
|
||||
int32_t rgi_max_luma_sample_rate[ 4 ] = { 3041280, 10368000, 47001600, 62668800 };
|
||||
|
@ -186,40 +186,260 @@ bool_t y262_validate_level( y262_t *ps_y262, int32_t i_level, bool_t b_forderive
|
|||
}
|
||||
i_luma_sample_rate = ( int32_t )( ( ( ( int64_t )( ps_y262->i_sequence_width * ps_y262->i_sequence_height ) ) * ps_y262->i_sequence_derived_timescale ) / ps_y262->i_sequence_derived_picture_duration );
|
||||
|
||||
if( i_luma_sample_rate > rgi_max_luma_sample_rate[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t *)"luma sample rate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->s_ratectrl.i_vbvrate > rgi_max_bitrate[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t *)"maximum bitrate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->s_ratectrl.i_vbv_size > rgi_max_buffer_size[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t *)"video buffer size exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool_t y262_validate_level_high_profile( y262_t *ps_y262, int32_t i_level, bool_t b_forderive )
|
||||
{
|
||||
int32_t i_idx, i_luma_sample_rate;
|
||||
int32_t rgi_max_hfcode[ 4 ] = { 0, 7, 8, 8 };
|
||||
int32_t rgi_max_vfcode[ 4 ] = { 0, 5, 5, 5 };
|
||||
int32_t rgi_max_frcode[ 4 ] = { 0, 5, 8, 8 };
|
||||
int32_t rgi_max_pic_width[ 4 ] = { 0, 720, 1440, 1920 };
|
||||
int32_t rgi_max_pic_height[ 4 ] = { 0, 576, 1088, 1088 };
|
||||
int32_t rgi_fr[ 16 ] = { 100, 24, 24, 25, 30, 30, 50, 60, 60, 100, 100, 100, 100, 100, 100, 100 };
|
||||
int32_t rgi_max_fr[ 4 ] = { 0, 30, 60, 60 };
|
||||
int32_t rgi_max_luma_sample_rate_420[ 4 ] = { 0, 14745600, 62668800, 83558400 };
|
||||
int32_t rgi_max_luma_sample_rate_422[ 4 ] = { 0, 11059200, 47001600, 62668800 };
|
||||
int32_t rgi_max_bitrate[ 4 ] = { 0, 15000000, 60000000, 80000000 };
|
||||
int32_t rgi_max_buffer_size[ 4 ] = { 0, 2441216, 9781248, 12222464 }; /* enhancement 2 ? */
|
||||
|
||||
i_idx = -1;
|
||||
switch( i_level )
|
||||
{
|
||||
case Y262_LEVEL_MAIN:
|
||||
i_idx = 1;
|
||||
break;
|
||||
case Y262_LEVEL_HIGH1440:
|
||||
i_idx = 2;
|
||||
break;
|
||||
case Y262_LEVEL_HIGH:
|
||||
i_idx = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if( i_idx == -1 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->rgi_fcode[ 0 ][ 0 ] < 1 || ps_y262->rgi_fcode[ 0 ][ 0 ] > rgi_max_hfcode[ i_idx ] ||
|
||||
ps_y262->rgi_fcode[ 1 ][ 0 ] < 1 || ps_y262->rgi_fcode[ 1 ][ 0 ] > rgi_max_hfcode[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "horizontal fcode exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->rgi_fcode[ 0 ][ 1 ] < 1 || ps_y262->rgi_fcode[ 0 ][ 1 ] > rgi_max_vfcode[ i_idx ] ||
|
||||
ps_y262->rgi_fcode[ 1 ][ 1 ] < 1 || ps_y262->rgi_fcode[ 1 ][ 1 ] > rgi_max_vfcode[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "vertical fcode exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->i_sequence_frame_rate_code < 1 || ps_y262->i_sequence_frame_rate_code > rgi_max_frcode[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "frame rate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->i_sequence_width > rgi_max_pic_width[ i_idx ] ||
|
||||
ps_y262->i_sequence_height > rgi_max_pic_height[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "picture size exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
i_luma_sample_rate = ( int32_t ) ( ( ( ( int64_t ) ( ps_y262->i_sequence_width * ps_y262->i_sequence_height ) ) * ps_y262->i_sequence_derived_timescale ) / ps_y262->i_sequence_derived_picture_duration );
|
||||
|
||||
if( ps_y262->i_sequence_chroma_format == Y262_CHROMA_FORMAT_420 )
|
||||
{
|
||||
if( i_luma_sample_rate > rgi_max_luma_sample_rate[ i_idx ] )
|
||||
if( i_luma_sample_rate > rgi_max_luma_sample_rate_420[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t *)"luma sample rate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->s_ratectrl.i_vbvrate > rgi_max_bitrate[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t *)"maximum bitrate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->s_ratectrl.i_vbv_size > rgi_max_buffer_size[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t *)"video buffer size exceeds level limit" );
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "luma sample rate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 422/444 level limits where ? */
|
||||
if( i_luma_sample_rate > rgi_max_luma_sample_rate_422[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "luma sample rate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if( ps_y262->s_ratectrl.i_vbvrate > rgi_max_bitrate[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "maximum bitrate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->s_ratectrl.i_vbv_size > rgi_max_buffer_size[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "video buffer size exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
bool_t y262_validate_level_422_profile( y262_t *ps_y262, int32_t i_level, bool_t b_forderive )
|
||||
{
|
||||
int32_t i_idx, i_luma_sample_rate;
|
||||
int32_t rgi_max_hfcode[ 4 ] = { 7, 8 };
|
||||
int32_t rgi_max_vfcode[ 4 ] = { 5, 5 };
|
||||
int32_t rgi_max_frcode[ 4 ] = { 5, 8 };
|
||||
int32_t rgi_max_pic_width[ 4 ] = { 720, 1920 };
|
||||
int32_t rgi_max_pic_height[ 4 ] = { 608, 1088 };
|
||||
int32_t rgi_fr[ 16 ] = { 100, 24, 24, 25, 30, 30, 50, 60, 60, 100, 100, 100, 100, 100, 100, 100 };
|
||||
int32_t rgi_max_fr[ 4 ] = { 30, 60 };
|
||||
int32_t rgi_max_luma_sample_rate[ 4 ] = { 11059200, 62668800 };
|
||||
int32_t rgi_max_bitrate[ 4 ] = { 50000000, 300000000 };
|
||||
int32_t rgi_max_buffer_size[ 4 ] = { 9437184, 47185920 };
|
||||
|
||||
i_idx = -1;
|
||||
switch( i_level )
|
||||
{
|
||||
case Y262_LEVEL_422MAIN:
|
||||
i_idx = 0;
|
||||
break;
|
||||
case Y262_LEVEL_422HIGH:
|
||||
i_idx = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if( i_idx == -1 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->rgi_fcode[ 0 ][ 0 ] < 1 || ps_y262->rgi_fcode[ 0 ][ 0 ] > rgi_max_hfcode[ i_idx ] ||
|
||||
ps_y262->rgi_fcode[ 1 ][ 0 ] < 1 || ps_y262->rgi_fcode[ 1 ][ 0 ] > rgi_max_hfcode[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "horizontal fcode exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->rgi_fcode[ 0 ][ 1 ] < 1 || ps_y262->rgi_fcode[ 0 ][ 1 ] > rgi_max_vfcode[ i_idx ] ||
|
||||
ps_y262->rgi_fcode[ 1 ][ 1 ] < 1 || ps_y262->rgi_fcode[ 1 ][ 1 ] > rgi_max_vfcode[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "vertical fcode exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->i_sequence_frame_rate_code < 1 || ps_y262->i_sequence_frame_rate_code > rgi_max_frcode[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "frame rate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->i_sequence_width > rgi_max_pic_width[ i_idx ] ||
|
||||
ps_y262->i_sequence_height > rgi_max_pic_height[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "picture size exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
i_luma_sample_rate = ( int32_t ) ( ( ( ( int64_t ) ( ps_y262->i_sequence_width * ps_y262->i_sequence_height ) ) * ps_y262->i_sequence_derived_timescale ) / ps_y262->i_sequence_derived_picture_duration );
|
||||
|
||||
if( i_luma_sample_rate > rgi_max_luma_sample_rate[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "luma sample rate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->s_ratectrl.i_vbvrate > rgi_max_bitrate[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "maximum bitrate exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
if( ps_y262->s_ratectrl.i_vbv_size > rgi_max_buffer_size[ i_idx ] )
|
||||
{
|
||||
if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
|
||||
{
|
||||
ps_y262->s_funcs.pf_error_callback( ps_y262->p_cb_handle, Y262_ERROR_PROFILELEVEL, ( int8_t * ) "video buffer size exceeds level limit" );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
bool_t y262_validate_level( y262_t *ps_y262, int32_t i_profile, int32_t i_level, bool_t b_forderive )
|
||||
{
|
||||
if( i_profile == Y262_PROFILE_SIMPLE ||
|
||||
i_profile == Y262_PROFILE_MAIN )
|
||||
{
|
||||
return y262_validate_level_simple_main_profile( ps_y262, i_level, b_forderive );
|
||||
}
|
||||
else if( i_profile == Y262_PROFILE_HIGH )
|
||||
{
|
||||
return y262_validate_level_high_profile( ps_y262, i_level, b_forderive );
|
||||
}
|
||||
else if( i_profile == Y262_PROFILE_422 )
|
||||
{
|
||||
return y262_validate_level_422_profile( ps_y262, i_level, b_forderive );
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t y262_initialize( void *p_y262, y262_configuration_t *ps_config )
|
||||
{
|
||||
int32_t i_idx, i_mv_range, i_mvs, i_fcode_m1, i_wrap;
|
||||
|
@ -293,19 +513,33 @@ int32_t y262_initialize( void *p_y262, y262_configuration_t *ps_config )
|
|||
}
|
||||
if( ps_config->i_profile != Y262_PROFILE_DERIVE &&
|
||||
ps_config->i_profile != Y262_PROFILE_SIMPLE &&
|
||||
ps_config->i_profile != Y262_PROFILE_MAIN )
|
||||
ps_config->i_profile != Y262_PROFILE_MAIN &&
|
||||
ps_config->i_profile != Y262_PROFILE_HIGH &&
|
||||
ps_config->i_profile != Y262_PROFILE_422 )
|
||||
{
|
||||
return Y262_INIT_ERROR_PROFILE;
|
||||
}
|
||||
if( ps_config->i_level != Y262_LEVEL_DERIVE &&
|
||||
ps_config->i_level != Y262_LEVEL_LOW &&
|
||||
ps_config->i_level != Y262_LEVEL_MAIN &&
|
||||
ps_config->i_level != Y262_LEVEL_HIGH1440 &&
|
||||
ps_config->i_level != Y262_LEVEL_HIGH )
|
||||
if( ps_config->i_level != Y262_LEVEL_DERIVE )
|
||||
{
|
||||
return Y262_INIT_ERROR_LEVEL;
|
||||
if( ps_config->i_profile != Y262_PROFILE_422 )
|
||||
{
|
||||
if( ps_config->i_level != Y262_LEVEL_LOW &&
|
||||
ps_config->i_level != Y262_LEVEL_MAIN &&
|
||||
ps_config->i_level != Y262_LEVEL_HIGH1440 &&
|
||||
ps_config->i_level != Y262_LEVEL_HIGH )
|
||||
{
|
||||
return Y262_INIT_ERROR_LEVEL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ps_config->i_level != Y262_LEVEL_422MAIN &&
|
||||
ps_config->i_level != Y262_LEVEL_422HIGH )
|
||||
{
|
||||
return Y262_INIT_ERROR_LEVEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( ps_config->i_lookahead_pictures < 10 || ps_config->i_lookahead_pictures > 50 )
|
||||
{
|
||||
return Y262_INIT_ERROR_LOOKAHEADPICS;
|
||||
|
@ -672,7 +906,14 @@ int32_t y262_initialize( void *p_y262, y262_configuration_t *ps_config )
|
|||
|
||||
if( ps_config->i_profile == Y262_PROFILE_DERIVE )
|
||||
{
|
||||
ps_y262->i_derived_profile = ps_y262->i_sequence_num_bframes > 0 ? Y262_PROFILE_MAIN : Y262_PROFILE_SIMPLE;
|
||||
if( ps_y262->i_sequence_chroma_format != Y262_CHROMA_FORMAT_420 )
|
||||
{
|
||||
ps_y262->i_derived_profile = Y262_PROFILE_422;
|
||||
}
|
||||
else
|
||||
{
|
||||
ps_y262->i_derived_profile = ps_y262->i_sequence_num_bframes > 0 ? Y262_PROFILE_MAIN : Y262_PROFILE_SIMPLE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -684,6 +925,14 @@ int32_t y262_initialize( void *p_y262, y262_configuration_t *ps_config )
|
|||
}
|
||||
}
|
||||
else if( ps_config->i_profile == Y262_PROFILE_MAIN )
|
||||
{
|
||||
if( ps_y262->i_sequence_chroma_format != Y262_CHROMA_FORMAT_420 )
|
||||
{
|
||||
return Y262_INIT_ERROR_PROFILE_CHROMA_FORMAT;
|
||||
}
|
||||
}
|
||||
else if( ps_config->i_profile == Y262_PROFILE_HIGH ||
|
||||
ps_config->i_profile == Y262_PROFILE_422 )
|
||||
{
|
||||
}
|
||||
else
|
||||
|
@ -695,24 +944,42 @@ int32_t y262_initialize( void *p_y262, y262_configuration_t *ps_config )
|
|||
if( ps_config->i_level == Y262_LEVEL_DERIVE )
|
||||
{
|
||||
int32_t i_check;
|
||||
int32_t rgi_levels[ 4 ] = { Y262_LEVEL_LOW, Y262_LEVEL_MAIN, Y262_LEVEL_HIGH1440, Y262_LEVEL_HIGH };
|
||||
|
||||
for( i_check = 0; i_check < 4; i_check++ )
|
||||
if( ps_y262->i_derived_profile != Y262_PROFILE_422 )
|
||||
{
|
||||
if( y262_validate_level( ps_y262, rgi_levels[ i_check ], i_check < 3 ? TRUE : FALSE ) )
|
||||
int32_t rgi_levels[ 4 ] = { Y262_LEVEL_LOW, Y262_LEVEL_MAIN, Y262_LEVEL_HIGH1440, Y262_LEVEL_HIGH };
|
||||
for( i_check = 0; i_check < 4; i_check++ )
|
||||
{
|
||||
ps_y262->i_derived_level = rgi_levels[ i_check ];
|
||||
break;
|
||||
if( y262_validate_level( ps_y262, ps_y262->i_derived_profile, rgi_levels[ i_check ], i_check < 3 ? TRUE : FALSE ) )
|
||||
{
|
||||
ps_y262->i_derived_level = rgi_levels[ i_check ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i_check == 4 )
|
||||
{
|
||||
return Y262_INIT_ERROR_LEVEL_LIMITS;
|
||||
}
|
||||
}
|
||||
if( i_check == 4 )
|
||||
else /* i_derived_profile == Y262_PROFILE_422 */
|
||||
{
|
||||
return Y262_INIT_ERROR_LEVEL_LIMITS;
|
||||
int32_t rgi_levels[ 4 ] = { Y262_LEVEL_422MAIN, Y262_LEVEL_422HIGH };
|
||||
for( i_check = 0; i_check < 2; i_check++ )
|
||||
{
|
||||
if( y262_validate_level( ps_y262, ps_y262->i_derived_profile, rgi_levels[ i_check ], i_check < 1 ? TRUE : FALSE ) )
|
||||
{
|
||||
ps_y262->i_derived_level = rgi_levels[ i_check ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i_check == 2 )
|
||||
{
|
||||
return Y262_INIT_ERROR_LEVEL_LIMITS;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !y262_validate_level( ps_y262, ps_config->i_level, FALSE ) )
|
||||
if( !y262_validate_level( ps_y262, ps_y262->i_derived_profile, ps_config->i_level, FALSE ) )
|
||||
{
|
||||
return Y262_INIT_ERROR_LEVEL_LIMITS;
|
||||
}
|
||||
|
|
|
@ -113,6 +113,8 @@ typedef struct {
|
|||
#define Y262_PROFILE_DERIVE 256
|
||||
#define Y262_PROFILE_SIMPLE 5
|
||||
#define Y262_PROFILE_MAIN 4
|
||||
#define Y262_PROFILE_HIGH 1
|
||||
#define Y262_PROFILE_422 8
|
||||
int32_t i_profile; /* profile, one of the profile defines */
|
||||
|
||||
#define Y262_LEVEL_DERIVE 256
|
||||
|
@ -120,6 +122,8 @@ typedef struct {
|
|||
#define Y262_LEVEL_MAIN 8
|
||||
#define Y262_LEVEL_HIGH1440 6
|
||||
#define Y262_LEVEL_HIGH 4
|
||||
#define Y262_LEVEL_422MAIN 5
|
||||
#define Y262_LEVEL_422HIGH 2
|
||||
int32_t i_level; /* level, one of the level defines */
|
||||
|
||||
#define Y262_VIDEOFORMAT_PAL 0
|
||||
|
@ -270,6 +274,8 @@ void *y262_create( y262_configuration_t *ps_config );
|
|||
#define Y262_INIT_ERROR_RESOURCE_INTERNAL -28
|
||||
/* invalid y262 context */
|
||||
#define Y262_INIT_ERROR_CONTEXT -29
|
||||
/* invalid chroma format for profile */
|
||||
#define Y262_INIT_ERROR_PROFILE_CHROMA_FORMAT -30
|
||||
|
||||
/*
|
||||
initializes the encoder context p_y262 with the encoding configuration ps_config.
|
||||
|
|
|
@ -374,6 +374,14 @@ int32_t main( int32_t i_argc, char *rgpi8_argv[] )
|
|||
{
|
||||
s_config.i_profile = Y262_PROFILE_MAIN;
|
||||
}
|
||||
else if( strcmp( ( char * ) rgpi8_argv[ i_idx ], "high" ) == 0 )
|
||||
{
|
||||
s_config.i_profile = Y262_PROFILE_HIGH;
|
||||
}
|
||||
else if( strcmp( ( char * ) rgpi8_argv[ i_idx ], "422" ) == 0 )
|
||||
{
|
||||
s_config.i_profile = Y262_PROFILE_422;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( stderr, "unknown profile specified on commandline\n");
|
||||
|
@ -394,10 +402,18 @@ int32_t main( int32_t i_argc, char *rgpi8_argv[] )
|
|||
{
|
||||
s_config.i_level = Y262_LEVEL_HIGH1440;
|
||||
}
|
||||
else if( strcmp( ( char *)rgpi8_argv[ i_idx ], "high" ) == 0 )
|
||||
else if( strcmp( ( char * ) rgpi8_argv[ i_idx ], "high" ) == 0 )
|
||||
{
|
||||
s_config.i_level = Y262_LEVEL_HIGH;
|
||||
}
|
||||
else if( strcmp( ( char * ) rgpi8_argv[ i_idx ], "422main" ) == 0 )
|
||||
{
|
||||
s_config.i_level = Y262_LEVEL_422MAIN;
|
||||
}
|
||||
else if( strcmp( ( char * ) rgpi8_argv[ i_idx ], "422high" ) == 0 )
|
||||
{
|
||||
s_config.i_level = Y262_LEVEL_422HIGH;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( stderr, "unknown level specified on commandline\n" );
|
||||
|
@ -916,6 +932,14 @@ int32_t main( int32_t i_argc, char *rgpi8_argv[] )
|
|||
{
|
||||
fclose( f_in );
|
||||
}
|
||||
if( f_mpass_in )
|
||||
{
|
||||
fclose( f_mpass_in );
|
||||
}
|
||||
if( f_mpass_out )
|
||||
{
|
||||
fclose( f_mpass_out );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue