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:
rwillenbacher 2022-03-09 13:03:15 +01:00
parent df475dedd7
commit ae31172c03
6 changed files with 507 additions and 112 deletions

View file

@ -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_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 = 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.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, 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 ) ) if( ( ps_slice_rc->i_slice_bit_budget + i_extra_bits - i_adjusted_slice_coded_size ) > ( 512 + 9 ) )
{ {
double d_scale; double d_scale;
d_scale = 1.0;
if( i_adjusted_slice_coded_size > 0 && i_adjusted_slice_predicted_size > 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; d_scale = i_adjusted_slice_coded_size / ( double ) i_adjusted_slice_predicted_size;

View file

@ -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 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_dc, i_nz, i_num_active_nodes;
int32_t i_coeff, i_start, i_num_coeff, i_last_coeff, i_idx, i_idx2, i_run, i_level; 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_levels[ 64 ];
int16_t rgi16_coeffs[ 64 ]; int16_t rgi16_coeffs[ 64 ];
int8_t rgi8_idx[ 64 ]; int8_t rgi8_idx[ 64 ];
int16_t rgi16_level[ 64 ]; int16_t rgi16_level[ 64 ];
uint8_t *pui8_qmat; uint8_t *pui8_qmat;
y262_macroblock_t *ps_mb; 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_cost, i_lambda, i_ssd, i_candidate_level, i_dir, i_end;
int32_t i_candidate_level, i_dir, i_end, i_ssd, i_bits, i_cost, i_lambda;
assert( i_stride == 8 );
ps_mb = &ps_slice->s_macroblock; 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; return i_dc;
} }
memset( &ps_y262->trellis.rgi8_path_active, 0, sizeof( ps_y262->trellis.rgi8_path_active ) ); y262_quant8x8_trellis_init( ps_y262, &s_trellis, i_lambda );
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;
for( i_idx = 0; i_idx < i_num_coeff; i_idx++ ) 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_dir = 1;
} }
i_end = i_level + i_dir * 2; 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 ) 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; 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 ] ); 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 ] ) 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++;
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 ); for( ps_node = s_trellis.ps_active_nodes; ps_node; ps_node = ps_next )
i_cost = ps_y262->trellis.rgi_path_cost[ i_idx2 ] + ( ( i_bits * i_lambda ) >> Y262_LAMBDA_BITS ) + i_ssd; {
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( !ps_y262->trellis.rgi8_path_active[ !i_active_toggle ][ i_idx2 + 1 ] || i_cost < ps_y262->trellis.rgi_path_cost[ i_idx2 + 1 ] )
if( i_num_active_nodes > Y262_TRELLIS_MAX_ACTIVE_NODES )
{ {
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_trellis_shrink_trellis( &s_trellis );
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;
}
}
}
}
}
memset( &ps_y262->trellis.rgi8_path_active[ i_active_toggle ][ 0 ], 0, sizeof( int8_t ) * 65 );
i_active_toggle = i_active_toggle^1;
}
i_cost = MAX_COST; i_cost = MAX_COST;
i_idx2 = 0; for( ps_node = s_trellis.ps_active_nodes; ps_node; ps_node = ps_node->ps_next )
for( i_idx = 0; i_idx <= i_num_coeff; i_idx++ )
{ {
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_node->i_cost;
i_cost = ps_y262->trellis.rgi_path_cost[ i_idx ]; 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; pi_coeffs[ ps_best->rgi16_idx[ i_idx ] ] = ps_best->rgi16_level[ i_idx ];
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; return ( ps_best->i16_num_level > 0 );
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 ];
}
return i_idx2 != 0;
} }

View file

@ -768,11 +768,4 @@ typedef struct y262_s {
int32_t i_psyrd_strength; int32_t i_psyrd_strength;
int32_t i_quality_for_speed; 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; } y262_t;

View file

@ -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 i_idx, i_luma_sample_rate;
int32_t rgi_max_hfcode[ 4 ] = { 7, 8, 9, 9 }; int32_t rgi_max_hfcode[ 4 ] = { 7, 8, 9, 9 };
int32_t rgi_max_vfcode[ 4 ] = { 4, 5, 5, 5 }; int32_t rgi_max_vfcode[ 4 ] = { 4, 5, 5, 5 };
int32_t rgi_max_frcode[ 4 ] = { 5, 5, 8, 8 }; 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_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_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_fr[ 4 ] = { 30, 30, 60, 60 };
int32_t rgi_max_luma_sample_rate[ 4 ] = { 3041280, 10368000, 47001600, 62668800 }; int32_t rgi_max_luma_sample_rate[ 4 ] = { 3041280, 10368000, 47001600, 62668800 };
@ -186,8 +186,6 @@ 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 ); 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[ i_idx ] )
{ {
if( !b_forderive && ps_y262->s_funcs.pf_error_callback ) if( !b_forderive && ps_y262->s_funcs.pf_error_callback )
@ -212,14 +210,236 @@ bool_t y262_validate_level( y262_t *ps_y262, int32_t i_level, bool_t b_forderive
} }
return FALSE; 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_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;
}
} }
else 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; 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 y262_initialize( void *p_y262, y262_configuration_t *ps_config )
{ {
int32_t i_idx, i_mv_range, i_mvs, i_fcode_m1, i_wrap; 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 && if( ps_config->i_profile != Y262_PROFILE_DERIVE &&
ps_config->i_profile != Y262_PROFILE_SIMPLE && 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; return Y262_INIT_ERROR_PROFILE;
} }
if( ps_config->i_level != Y262_LEVEL_DERIVE && if( ps_config->i_level != Y262_LEVEL_DERIVE )
ps_config->i_level != Y262_LEVEL_LOW && {
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_MAIN &&
ps_config->i_level != Y262_LEVEL_HIGH1440 && ps_config->i_level != Y262_LEVEL_HIGH1440 &&
ps_config->i_level != Y262_LEVEL_HIGH ) ps_config->i_level != Y262_LEVEL_HIGH )
{ {
return Y262_INIT_ERROR_LEVEL; 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 ) if( ps_config->i_lookahead_pictures < 10 || ps_config->i_lookahead_pictures > 50 )
{ {
return Y262_INIT_ERROR_LOOKAHEADPICS; return Y262_INIT_ERROR_LOOKAHEADPICS;
@ -671,9 +905,16 @@ int32_t y262_initialize( void *p_y262, y262_configuration_t *ps_config )
y262_ratectrl_init( ps_y262 ); y262_ratectrl_init( ps_y262 );
if( ps_config->i_profile == Y262_PROFILE_DERIVE ) if( ps_config->i_profile == Y262_PROFILE_DERIVE )
{
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; ps_y262->i_derived_profile = ps_y262->i_sequence_num_bframes > 0 ? Y262_PROFILE_MAIN : Y262_PROFILE_SIMPLE;
} }
}
else else
{ {
if( ps_config->i_profile == Y262_PROFILE_SIMPLE ) if( ps_config->i_profile == Y262_PROFILE_SIMPLE )
@ -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 ) 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 else
@ -695,11 +944,12 @@ int32_t y262_initialize( void *p_y262, y262_configuration_t *ps_config )
if( ps_config->i_level == Y262_LEVEL_DERIVE ) if( ps_config->i_level == Y262_LEVEL_DERIVE )
{ {
int32_t i_check; int32_t i_check;
if( ps_y262->i_derived_profile != Y262_PROFILE_422 )
{
int32_t rgi_levels[ 4 ] = { Y262_LEVEL_LOW, Y262_LEVEL_MAIN, Y262_LEVEL_HIGH1440, Y262_LEVEL_HIGH }; 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++ ) for( i_check = 0; i_check < 4; i_check++ )
{ {
if( y262_validate_level( ps_y262, rgi_levels[ i_check ], i_check < 3 ? TRUE : FALSE ) ) 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 ]; ps_y262->i_derived_level = rgi_levels[ i_check ];
break; break;
@ -710,9 +960,26 @@ int32_t y262_initialize( void *p_y262, y262_configuration_t *ps_config )
return Y262_INIT_ERROR_LEVEL_LIMITS; return Y262_INIT_ERROR_LEVEL_LIMITS;
} }
} }
else /* i_derived_profile == Y262_PROFILE_422 */
{
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 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; return Y262_INIT_ERROR_LEVEL_LIMITS;
} }

View file

@ -113,6 +113,8 @@ typedef struct {
#define Y262_PROFILE_DERIVE 256 #define Y262_PROFILE_DERIVE 256
#define Y262_PROFILE_SIMPLE 5 #define Y262_PROFILE_SIMPLE 5
#define Y262_PROFILE_MAIN 4 #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 */ int32_t i_profile; /* profile, one of the profile defines */
#define Y262_LEVEL_DERIVE 256 #define Y262_LEVEL_DERIVE 256
@ -120,6 +122,8 @@ typedef struct {
#define Y262_LEVEL_MAIN 8 #define Y262_LEVEL_MAIN 8
#define Y262_LEVEL_HIGH1440 6 #define Y262_LEVEL_HIGH1440 6
#define Y262_LEVEL_HIGH 4 #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 */ int32_t i_level; /* level, one of the level defines */
#define Y262_VIDEOFORMAT_PAL 0 #define Y262_VIDEOFORMAT_PAL 0
@ -270,6 +274,8 @@ void *y262_create( y262_configuration_t *ps_config );
#define Y262_INIT_ERROR_RESOURCE_INTERNAL -28 #define Y262_INIT_ERROR_RESOURCE_INTERNAL -28
/* invalid y262 context */ /* invalid y262 context */
#define Y262_INIT_ERROR_CONTEXT -29 #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. initializes the encoder context p_y262 with the encoding configuration ps_config.

View file

@ -374,6 +374,14 @@ int32_t main( int32_t i_argc, char *rgpi8_argv[] )
{ {
s_config.i_profile = Y262_PROFILE_MAIN; 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 else
{ {
fprintf( stderr, "unknown profile specified on commandline\n"); 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; 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; 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 else
{ {
fprintf( stderr, "unknown level specified on commandline\n" ); 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 ); fclose( f_in );
} }
if( f_mpass_in )
{
fclose( f_mpass_in );
}
if( f_mpass_out )
{
fclose( f_mpass_out );
}
return 0; return 0;
} }