Commit 9d5db450 authored by François Cartegnie's avatar François Cartegnie 🤞
Browse files

packetizer: h264: decode and compute POC

parent fde0b7b7
......@@ -118,5 +118,250 @@ bool h264_decode_slice( const uint8_t *p_buffer, size_t i_buffer,
p_slice->i_delta_pic_order_cnt1 = bs_read_se( &s );
}
if( p_pps->i_redundant_pic_present_flag )
bs_read_ue( &s ); /* redudant_pic_count */
unsigned num_ref_idx_l01_active_minus1[2] = {0 , 0};
if( i_slice_type == 1 || i_slice_type == 6 ) /* B slices */
bs_read1( &s ); /* direct_spatial_mv_pred_flag */
if( i_slice_type == 0 || i_slice_type == 5 ||
i_slice_type == 3 || i_slice_type == 8 ||
i_slice_type == 1 || i_slice_type == 6 ) /* P SP B slices */
{
if( bs_read1( &s ) ) /* num_ref_idx_active_override_flag */
{
num_ref_idx_l01_active_minus1[0] = bs_read_ue( &s );
if( i_slice_type == 1 || i_slice_type == 6 ) /* B slices */
num_ref_idx_l01_active_minus1[1] = bs_read_ue( &s );
}
}
/* BELOW, Further processing up to assert MMCO 5 presence for POC */
if( p_slice->i_nal_type == 5 || p_slice->i_nal_ref_idc == 0 )
{
/* Early END, don't waste parsing below */
p_slice->has_mmco5 = false;
return true;
}
/* ref_pic_list_[mvc_]modification() */
const bool b_mvc = (p_slice->i_nal_type == 20 || p_slice->i_nal_type == 21 );
unsigned i = 0;
if( i_slice_type % 5 != 2 && i_slice_type % 5 != 4 )
i++;
if( i_slice_type % 5 == 1 )
i++;
for( ; i>0; i-- )
{
if( bs_read1( &s ) ) /* ref_pic_list_modification_flag_l{0,1} */
{
uint32_t mod;
do
{
mod = bs_read_ue( &s );
if( mod < 3 || ( b_mvc && (mod == 4 || mod == 5) ) )
bs_read_ue( &s ); /* abs_diff_pic_num_minus1, long_term_pic_num, abs_diff_view_idx_min1 */
}
while( mod != 3 && bs_remain( &s ) );
}
}
/* pred_weight_table() */
if( ( p_pps->weighted_pred_flag && ( i_slice_type == 0 || i_slice_type == 5 || /* P, SP */
i_slice_type == 3 || i_slice_type == 8 ) ) ||
( p_pps->weighted_bipred_idc == 1 && ( i_slice_type == 1 || i_slice_type == 6 ) /* B */ ) )
{
bs_read_ue( &s ); /* luma_log2_weight_denom */
if( !p_sps->b_separate_colour_planes_flag ) /* ChromaArrayType != 0 */
bs_read_ue( &s ); /* chroma_log2_weight_denom */
const unsigned i_num_layers = ( i_slice_type % 5 == 1 ) ? 2 : 1;
for( unsigned j=0; j < i_num_layers; j++ )
{
for( unsigned i=0; i<=num_ref_idx_l01_active_minus1[j]; i++ )
{
if( bs_read1( &s ) ) /* luma_weight_l{0,1}_flag */
{
bs_read_se( &s );
bs_read_se( &s );
}
if( !p_sps->b_separate_colour_planes_flag ) /* ChromaArrayType != 0 */
{
if( bs_read1( &s ) ) /* chroma_weight_l{0,1}_flag */
{
bs_read_se( &s );
bs_read_se( &s );
bs_read_se( &s );
bs_read_se( &s );
}
}
}
}
}
/* dec_ref_pic_marking() */
if( p_slice->i_nal_type != 5 ) /* IdrFlag */
{
if( bs_read1( &s ) ) /* adaptive_ref_pic_marking_mode_flag */
{
uint32_t mmco;
do
{
mmco = bs_read_ue( &s );
if( mmco == 1 || mmco == 3 )
bs_read_ue( &s ); /* diff_pics_minus1 */
if( mmco == 2 )
bs_read_ue( &s ); /* long_term_pic_num */
if( mmco == 3 || mmco == 6 )
bs_read_ue( &s ); /* long_term_frame_idx */
if( mmco == 4 )
bs_read_ue( &s ); /* max_long_term_frame_idx_plus1 */
if( mmco == 5 )
{
p_slice->has_mmco5 = true;
break; /* Early END */
}
}
while( mmco > 0 );
}
}
/* If you need to store anything else than MMCO presence above, care of "Early END" cases */
return true;
}
void h264_compute_poc( const h264_sequence_parameter_set_t *p_sps,
const h264_slice_t *p_slice, poc_context_t *p_ctx,
int *p_PictureOrderCount, int *p_tFOC, int *p_bFOC )
{
*p_tFOC = *p_bFOC = 0;
if( p_sps->i_pic_order_cnt_type == 0 )
{
unsigned maxPocLSB = 1U << (p_sps->i_log2_max_pic_order_cnt_lsb + 4);
/* POC reference */
if( p_slice->i_nal_type == H264_NAL_SLICE_IDR )
{
p_ctx->prevPicOrderCnt.lsb = 0;
p_ctx->prevPicOrderCnt.msb = 0;
}
else if( p_ctx->prevRefPictureHasMMCO5 )
{
p_ctx->prevPicOrderCnt.msb = 0;
if( !p_ctx->prevRefPictureIsBottomField )
p_ctx->prevPicOrderCnt.lsb = p_ctx->prevRefPictureTFOC;
else
p_ctx->prevPicOrderCnt.lsb = 0;
}
/* 8.2.1.1 */
int pocMSB = p_ctx->prevPicOrderCnt.msb;
int64_t orderDiff = p_slice->i_pic_order_cnt_lsb - p_ctx->prevPicOrderCnt.lsb;
if( orderDiff < 0 && -orderDiff >= maxPocLSB / 2 )
pocMSB += maxPocLSB;
else if( orderDiff > maxPocLSB / 2 )
pocMSB -= maxPocLSB;
*p_tFOC = *p_bFOC = pocMSB + p_slice->i_pic_order_cnt_lsb;
if( p_slice->i_field_pic_flag )
*p_bFOC += p_slice->i_delta_pic_order_cnt_bottom;
/* Save from ref picture */
if( p_slice->i_nal_ref_idc /* Is reference */ )
{
p_ctx->prevRefPictureIsBottomField = (p_slice->i_field_pic_flag &&
p_slice->i_bottom_field_flag);
p_ctx->prevRefPictureHasMMCO5 = p_slice->has_mmco5;
p_ctx->prevRefPictureTFOC = *p_tFOC;
p_ctx->prevPicOrderCnt.lsb = p_slice->i_pic_order_cnt_lsb;
p_ctx->prevPicOrderCnt.msb = pocMSB;
}
}
else
{
unsigned maxFrameNum = 1 << (p_sps->i_log2_max_frame_num + 4);
unsigned frameNumOffset;
unsigned expectedPicOrderCnt = 0;
if( p_slice->i_nal_type == H264_NAL_SLICE_IDR )
frameNumOffset = 0;
else if( p_ctx->prevFrameNum > (unsigned) p_slice->i_frame_num )
frameNumOffset = p_ctx->prevFrameNumOffset + maxFrameNum;
else
frameNumOffset = p_ctx->prevFrameNumOffset;
if( p_sps->i_pic_order_cnt_type == 1 )
{
unsigned absFrameNum;
if( p_sps->i_num_ref_frames_in_pic_order_cnt_cycle > 0 )
absFrameNum = frameNumOffset + p_slice->i_frame_num;
else
absFrameNum = 0;
if( p_slice->i_nal_ref_idc == 0 && absFrameNum > 0 )
absFrameNum--;
if( absFrameNum > 0 )
{
int32_t expectedDeltaPerPicOrderCntCycle = 0;
for( int i=0; i<p_sps->i_num_ref_frames_in_pic_order_cnt_cycle; i++ )
expectedDeltaPerPicOrderCntCycle += p_sps->offset_for_ref_frame[i];
unsigned picOrderCntCycleCnt = 0;
unsigned frameNumInPicOrderCntCycle = 0;
if( p_sps->i_num_ref_frames_in_pic_order_cnt_cycle )
{
picOrderCntCycleCnt = ( absFrameNum - 1 ) / p_sps->i_num_ref_frames_in_pic_order_cnt_cycle;
frameNumInPicOrderCntCycle = ( absFrameNum - 1 ) % p_sps->i_num_ref_frames_in_pic_order_cnt_cycle;
}
expectedPicOrderCnt = picOrderCntCycleCnt * expectedDeltaPerPicOrderCntCycle;
for( unsigned i=0; i <= frameNumInPicOrderCntCycle; i++ )
expectedPicOrderCnt = expectedPicOrderCnt + p_sps->offset_for_ref_frame[i];
}
if( p_slice->i_nal_ref_idc == 0 )
expectedPicOrderCnt = expectedPicOrderCnt + p_sps->offset_for_non_ref_pic;
*p_tFOC = expectedPicOrderCnt + p_slice->i_delta_pic_order_cnt0;
if( !p_slice->i_field_pic_flag )
*p_bFOC = *p_tFOC + p_sps->offset_for_top_to_bottom_field + p_slice->i_delta_pic_order_cnt1;
else if( p_slice->i_bottom_field_flag )
*p_bFOC = expectedPicOrderCnt + p_sps->offset_for_top_to_bottom_field + p_slice->i_delta_pic_order_cnt0;
}
else if( p_sps->i_pic_order_cnt_type == 2 )
{
unsigned tempPicOrderCnt;
if( p_slice->i_nal_type == H264_NAL_SLICE_IDR )
tempPicOrderCnt = 0;
else if( p_slice->i_nal_ref_idc == 0 )
tempPicOrderCnt = 2 * ( frameNumOffset + p_slice->i_frame_num ) - 1;
else
tempPicOrderCnt = 2 * ( frameNumOffset + p_slice->i_frame_num );
*p_bFOC = *p_tFOC = tempPicOrderCnt;
}
p_ctx->prevFrameNum = p_slice->i_frame_num;
if( p_slice->has_mmco5 )
p_ctx->prevFrameNumOffset = 0;
else
p_ctx->prevFrameNumOffset = frameNumOffset;
}
/* 8.2.1 (8-1) */
if( !p_slice->i_field_pic_flag ) /* progressive or contains both fields */
*p_PictureOrderCount = __MIN( *p_bFOC, *p_tFOC );
else /* split top or bottom field */
if ( p_slice->i_bottom_field_flag )
*p_PictureOrderCount = *p_bFOC;
else
*p_PictureOrderCount = *p_tFOC;
}
......@@ -41,6 +41,7 @@ typedef struct
int i_delta_pic_order_cnt0;
int i_delta_pic_order_cnt1;
bool has_mmco5;
} h264_slice_t;
static inline void h264_slice_init( h264_slice_t *p_slice )
......@@ -58,6 +59,7 @@ static inline void h264_slice_init( h264_slice_t *p_slice )
p_slice->i_delta_pic_order_cnt_bottom = -1;
p_slice->i_delta_pic_order_cnt0 = 0;
p_slice->i_delta_pic_order_cnt1 = 0;
p_slice->has_mmco5 = false;
}
bool h264_decode_slice( const uint8_t *p_buffer, size_t i_buffer,
......@@ -66,4 +68,31 @@ bool h264_decode_slice( const uint8_t *p_buffer, size_t i_buffer,
const h264_picture_parameter_set_t ** ),
void *, h264_slice_t *p_slice );
typedef struct
{
struct
{
int lsb;
int msb;
} prevPicOrderCnt;
unsigned prevFrameNum;
unsigned prevFrameNumOffset;
int prevRefPictureTFOC;
bool prevRefPictureIsBottomField;
bool prevRefPictureHasMMCO5;
} poc_context_t;
static inline void h264_poc_context_init( poc_context_t *p_ctx )
{
p_ctx->prevPicOrderCnt.lsb = 0;
p_ctx->prevPicOrderCnt.msb = 0;
p_ctx->prevFrameNum = 0;
p_ctx->prevFrameNumOffset = 0;
p_ctx->prevRefPictureIsBottomField = false;
p_ctx->prevRefPictureHasMMCO5 = false;
}
void h264_compute_poc( const h264_sequence_parameter_set_t *p_sps,
const h264_slice_t *p_slice, poc_context_t *p_ctx,
int *p_PictureOrderCount, int *p_tFOC, int *p_bFOC );
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment