codecparsers: Defering computation of pps and sps fields

While possible defer computataion of pps and sps fields until
slice parsing since it may happens that bitstreams don't encoded
them in expected order.
A example weird ordered bitstreams is VPSSPSPPS_A_MainConcept_1
conformance test.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2575>
This commit is contained in:
Benjamin Gaignard 2022-05-16 15:25:36 +02:00 committed by Nicolas Dufresne
parent 316b182a86
commit 5ae05bb42a
2 changed files with 173 additions and 61 deletions

View file

@ -597,10 +597,12 @@ gst_h265_parse_vui_parameters (GstH265SPS * sps, NalReader * nr)
READ_UE_MAX (nr, vui->log2_max_mv_length_vertical, 15); READ_UE_MAX (nr, vui->log2_max_mv_length_vertical, 15);
} }
vui->parsed = TRUE;
return TRUE; return TRUE;
error: error:
GST_WARNING ("error parsing \"VUI Parameters\""); GST_WARNING ("error parsing \"VUI Parameters\"");
vui->parsed = FALSE;
return FALSE; return FALSE;
} }
@ -1998,12 +2000,9 @@ gst_h265_parse_sps (GstH265Parser * parser, GstH265NalUnit * nalu,
GstH265SPS * sps, gboolean parse_vui_params) GstH265SPS * sps, gboolean parse_vui_params)
{ {
NalReader nr; NalReader nr;
GstH265VPS *vps;
guint8 vps_id;
guint i; guint i;
guint subwc[] = { 1, 2, 2, 1, 1 }; guint subwc[] = { 1, 2, 2, 1, 1 };
guint subhc[] = { 1, 2, 1, 1, 1 }; guint subhc[] = { 1, 2, 1, 1, 1 };
GstH265VUIParams *vui = NULL;
GST_DEBUG ("parsing SPS"); GST_DEBUG ("parsing SPS");
@ -2012,13 +2011,7 @@ gst_h265_parse_sps (GstH265Parser * parser, GstH265NalUnit * nalu,
memset (sps, 0, sizeof (*sps)); memset (sps, 0, sizeof (*sps));
READ_UINT8 (&nr, vps_id, 4); READ_UINT8 (&nr, sps->vps_id, 4);
vps = gst_h265_parser_get_vps (parser, vps_id);
if (!vps) {
GST_DEBUG ("couldn't find associated video parameter set with id: %d",
vps_id);
}
sps->vps = vps;
READ_UINT8 (&nr, sps->max_sub_layers_minus1, 3); READ_UINT8 (&nr, sps->max_sub_layers_minus1, 3);
READ_UINT8 (&nr, sps->temporal_id_nesting_flag, 1); READ_UINT8 (&nr, sps->temporal_id_nesting_flag, 1);
@ -2119,11 +2112,9 @@ gst_h265_parse_sps (GstH265Parser * parser, GstH265NalUnit * nalu,
READ_UINT8 (&nr, sps->strong_intra_smoothing_enabled_flag, 1); READ_UINT8 (&nr, sps->strong_intra_smoothing_enabled_flag, 1);
READ_UINT8 (&nr, sps->vui_parameters_present_flag, 1); READ_UINT8 (&nr, sps->vui_parameters_present_flag, 1);
if (sps->vui_parameters_present_flag && parse_vui_params) { if (sps->vui_parameters_present_flag && parse_vui_params)
if (!gst_h265_parse_vui_parameters (sps, &nr)) if (!gst_h265_parse_vui_parameters (sps, &nr))
goto error; goto error;
vui = &sps->vui_params;
}
READ_UINT8 (&nr, sps->sps_extension_flag, 1); READ_UINT8 (&nr, sps->sps_extension_flag, 1);
@ -2241,24 +2232,6 @@ done:
sps->fps_num = 0; sps->fps_num = 0;
sps->fps_den = 1; sps->fps_den = 1;
if (vui && vui->timing_info_present_flag) {
/* derive framerate for progressive stream if the pic_struct
* syntax element is not present in picture timing SEI messages */
/* Fixme: handle other cases also */
if (parse_vui_params && vui->timing_info_present_flag
&& !vui->field_seq_flag && !vui->frame_field_info_present_flag) {
sps->fps_num = vui->time_scale;
sps->fps_den = vui->num_units_in_tick;
GST_LOG ("framerate %d/%d in VUI", sps->fps_num, sps->fps_den);
}
} else if (vps && vps->timing_info_present_flag) {
sps->fps_num = vps->time_scale;
sps->fps_den = vps->num_units_in_tick;
GST_LOG ("framerate %d/%d in VPS", sps->fps_num, sps->fps_den);
} else {
GST_LOG ("No VUI, unknown framerate");
}
sps->valid = TRUE; sps->valid = TRUE;
return GST_H265_PARSER_OK; return GST_H265_PARSER_OK;
@ -2283,11 +2256,8 @@ GstH265ParserResult
gst_h265_parse_pps (GstH265Parser * parser, GstH265NalUnit * nalu, gst_h265_parse_pps (GstH265Parser * parser, GstH265NalUnit * nalu,
GstH265PPS * pps) GstH265PPS * pps)
{ {
guint32 MaxBitDepthY, MaxBitDepthC;
NalReader nr; NalReader nr;
GstH265SPS *sps;
gint sps_id;
gint qp_bd_offset;
guint32 CtbSizeY, MinCbLog2SizeY, CtbLog2SizeY, MaxBitDepthY, MaxBitDepthC;
guint8 i; guint8 i;
GST_DEBUG ("parsing PPS"); GST_DEBUG ("parsing PPS");
@ -2298,24 +2268,7 @@ gst_h265_parse_pps (GstH265Parser * parser, GstH265NalUnit * nalu,
memset (pps, 0, sizeof (*pps)); memset (pps, 0, sizeof (*pps));
READ_UE_MAX (&nr, pps->id, GST_H265_MAX_PPS_COUNT - 1); READ_UE_MAX (&nr, pps->id, GST_H265_MAX_PPS_COUNT - 1);
READ_UE_MAX (&nr, sps_id, GST_H265_MAX_SPS_COUNT - 1); READ_UE_MAX (&nr, pps->sps_id, GST_H265_MAX_SPS_COUNT - 1);
sps = gst_h265_parser_get_sps (parser, sps_id);
if (!sps) {
GST_WARNING ("couldn't find associated sequence parameter set with id: %d",
sps_id);
return GST_H265_PARSER_BROKEN_LINK;
}
pps->sps = sps;
qp_bd_offset = 6 * sps->bit_depth_luma_minus8;
MinCbLog2SizeY = sps->log2_min_luma_coding_block_size_minus3 + 3;
CtbLog2SizeY = MinCbLog2SizeY + sps->log2_diff_max_min_luma_coding_block_size;
CtbSizeY = 1 << CtbLog2SizeY;
pps->PicHeightInCtbsY =
ceil ((gdouble) sps->pic_height_in_luma_samples / (gdouble) CtbSizeY);
pps->PicWidthInCtbsY =
ceil ((gdouble) sps->pic_width_in_luma_samples / (gdouble) CtbSizeY);
/* set default values for fields that might not be present in the bitstream /* set default values for fields that might not be present in the bitstream
and have valid defaults */ and have valid defaults */
@ -2330,15 +2283,21 @@ gst_h265_parse_pps (GstH265Parser * parser, GstH265NalUnit * nalu,
READ_UE_MAX (&nr, pps->num_ref_idx_l0_default_active_minus1, 14); READ_UE_MAX (&nr, pps->num_ref_idx_l0_default_active_minus1, 14);
READ_UE_MAX (&nr, pps->num_ref_idx_l1_default_active_minus1, 14); READ_UE_MAX (&nr, pps->num_ref_idx_l1_default_active_minus1, 14);
READ_SE_ALLOWED (&nr, pps->init_qp_minus26, -(26 + qp_bd_offset), 25);
/* The value of init_qp_minus26 shall be in the range of
* ( 26 + QpBdOffsetY ) to +25, inclusive.
* QpBdOffsetY = 6 * bit_depth_luma_minus8 (7-5)
* and bit_depth_luma_minus8 shall be in the range of 0 to 8, inclusive.
* so the minimum possible value of init_qp_minus26 is -(26 + 6*8) */
READ_SE_ALLOWED (&nr, pps->init_qp_minus26, -(26 + 6 * 8), 25);
READ_UINT8 (&nr, pps->constrained_intra_pred_flag, 1); READ_UINT8 (&nr, pps->constrained_intra_pred_flag, 1);
READ_UINT8 (&nr, pps->transform_skip_enabled_flag, 1); READ_UINT8 (&nr, pps->transform_skip_enabled_flag, 1);
READ_UINT8 (&nr, pps->cu_qp_delta_enabled_flag, 1); READ_UINT8 (&nr, pps->cu_qp_delta_enabled_flag, 1);
if (pps->cu_qp_delta_enabled_flag) if (pps->cu_qp_delta_enabled_flag) {
READ_UE_MAX (&nr, pps->diff_cu_qp_delta_depth, READ_UE_MAX (&nr, pps->diff_cu_qp_delta_depth, 6);
sps->log2_diff_max_min_luma_coding_block_size); }
READ_SE_ALLOWED (&nr, pps->cb_qp_offset, -12, 12); READ_SE_ALLOWED (&nr, pps->cb_qp_offset, -12, 12);
READ_SE_ALLOWED (&nr, pps->cr_qp_offset, -12, 12); READ_SE_ALLOWED (&nr, pps->cr_qp_offset, -12, 12);
@ -2351,6 +2310,26 @@ gst_h265_parse_pps (GstH265Parser * parser, GstH265NalUnit * nalu,
READ_UINT8 (&nr, pps->entropy_coding_sync_enabled_flag, 1); READ_UINT8 (&nr, pps->entropy_coding_sync_enabled_flag, 1);
if (pps->tiles_enabled_flag) { if (pps->tiles_enabled_flag) {
GstH265SPS *sps;
guint32 CtbSizeY, MinCbLog2SizeY, CtbLog2SizeY;
sps = gst_h265_parser_get_sps (parser, pps->sps_id);
if (!sps) {
GST_WARNING
("couldn't find associated sequence parameter set with id: %d",
pps->sps_id);
return GST_H265_PARSER_BROKEN_LINK;
}
MinCbLog2SizeY = sps->log2_min_luma_coding_block_size_minus3 + 3;
CtbLog2SizeY =
MinCbLog2SizeY + sps->log2_diff_max_min_luma_coding_block_size;
CtbSizeY = 1 << CtbLog2SizeY;
pps->PicHeightInCtbsY =
ceil ((gdouble) sps->pic_height_in_luma_samples / (gdouble) CtbSizeY);
pps->PicWidthInCtbsY =
ceil ((gdouble) sps->pic_width_in_luma_samples / (gdouble) CtbSizeY);
READ_UE_ALLOWED (&nr, READ_UE_ALLOWED (&nr,
pps->num_tile_columns_minus1, 0, pps->PicWidthInCtbsY - 1); pps->num_tile_columns_minus1, 0, pps->PicWidthInCtbsY - 1);
READ_UE_ALLOWED (&nr, READ_UE_ALLOWED (&nr,
@ -2421,10 +2400,6 @@ gst_h265_parse_pps (GstH265Parser * parser, GstH265NalUnit * nalu,
if (pps->scaling_list_data_present_flag) if (pps->scaling_list_data_present_flag)
if (!gst_h265_parser_parse_scaling_lists (&nr, &pps->scaling_list, FALSE)) if (!gst_h265_parser_parse_scaling_lists (&nr, &pps->scaling_list, FALSE))
goto error; goto error;
if (sps->scaling_list_enabled_flag && !sps->scaling_list_data_present_flag
&& !pps->scaling_list_data_present_flag)
if (!gst_h265_parser_parse_scaling_lists (&nr, &pps->scaling_list, TRUE))
goto error;
READ_UINT8 (&nr, pps->lists_modification_present_flag, 1); READ_UINT8 (&nr, pps->lists_modification_present_flag, 1);
READ_UE_MAX (&nr, pps->log2_parallel_merge_level_minus2, 4); READ_UE_MAX (&nr, pps->log2_parallel_merge_level_minus2, 4);
@ -2440,6 +2415,16 @@ gst_h265_parse_pps (GstH265Parser * parser, GstH265NalUnit * nalu,
} }
if (pps->pps_range_extension_flag) { if (pps->pps_range_extension_flag) {
GstH265SPS *sps;
sps = gst_h265_parser_get_sps (parser, pps->sps_id);
if (!sps) {
GST_WARNING
("couldn't find associated sequence parameter set with id: %d",
pps->sps_id);
return GST_H265_PARSER_BROKEN_LINK;
}
if (pps->transform_skip_enabled_flag) if (pps->transform_skip_enabled_flag)
READ_UE (&nr, READ_UE (&nr,
pps->pps_extension_params.log2_max_transform_skip_block_size_minus2); pps->pps_extension_params.log2_max_transform_skip_block_size_minus2);
@ -2484,6 +2469,16 @@ gst_h265_parse_pps (GstH265Parser * parser, GstH265NalUnit * nalu,
} }
if (pps->pps_scc_extension_flag) { if (pps->pps_scc_extension_flag) {
GstH265SPS *sps;
sps = gst_h265_parser_get_sps (parser, pps->sps_id);
if (!sps) {
GST_WARNING
("couldn't find associated sequence parameter set with id: %d",
pps->sps_id);
return GST_H265_PARSER_BROKEN_LINK;
}
READ_UINT8 (&nr, READ_UINT8 (&nr,
pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag, 1); pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag, 1);
READ_UINT8 (&nr, READ_UINT8 (&nr,
@ -2587,6 +2582,90 @@ gst_h265_parser_parse_pps (GstH265Parser * parser,
return res; return res;
} }
static GstH265ParserResult
gst_h265_parser_fill_sps (GstH265Parser * parser, GstH265SPS * sps)
{
GstH265VPS *vps;
GstH265VUIParams *vui = &sps->vui_params;
GstH265ParserResult ret = GST_H265_PARSER_OK;
vps = gst_h265_parser_get_vps (parser, sps->vps_id);
if (!vps) {
GST_DEBUG ("couldn't find associated video parameter set with id: %d",
sps->vps_id);
return GST_H265_PARSER_BROKEN_LINK;
}
sps->vps = vps;
if (vui && vui->timing_info_present_flag) {
/* derive framerate for progressive stream if the pic_struct
* syntax element is not present in picture timing SEI messages */
/* Fixme: handle other cases also */
if (vui->parsed && vui->timing_info_present_flag
&& !vui->field_seq_flag && !vui->frame_field_info_present_flag) {
sps->fps_num = vui->time_scale;
sps->fps_den = vui->num_units_in_tick;
GST_LOG ("framerate %d/%d in VUI", sps->fps_num, sps->fps_den);
}
} else if (vps && vps->timing_info_present_flag) {
sps->fps_num = vps->time_scale;
sps->fps_den = vps->num_units_in_tick;
GST_LOG ("framerate %d/%d in VPS", sps->fps_num, sps->fps_den);
} else {
GST_LOG ("No VUI, unknown framerate");
}
return ret;
}
static GstH265ParserResult
gst_h265_parser_fill_pps (GstH265Parser * parser, GstH265PPS * pps)
{
GstH265SPS *sps;
gint qp_bd_offset;
guint32 CtbSizeY, MinCbLog2SizeY, CtbLog2SizeY;
GstH265ParserResult ret = GST_H265_PARSER_OK;
sps = gst_h265_parser_get_sps (parser, pps->sps_id);
if (!sps) {
GST_WARNING ("couldn't find associated sequence parameter set with id: %d",
pps->sps_id);
return GST_H265_PARSER_BROKEN_LINK;
}
ret = gst_h265_parser_fill_sps (parser, sps);
if (ret != GST_H265_PARSER_OK) {
GST_WARNING ("couldn't fill sps id: %d", pps->sps_id);
return ret;
}
pps->sps = sps;
qp_bd_offset = 6 * sps->bit_depth_luma_minus8;
MinCbLog2SizeY = sps->log2_min_luma_coding_block_size_minus3 + 3;
CtbLog2SizeY = MinCbLog2SizeY + sps->log2_diff_max_min_luma_coding_block_size;
CtbSizeY = 1 << CtbLog2SizeY;
pps->PicHeightInCtbsY =
ceil ((gdouble) sps->pic_height_in_luma_samples / (gdouble) CtbSizeY);
pps->PicWidthInCtbsY =
ceil ((gdouble) sps->pic_width_in_luma_samples / (gdouble) CtbSizeY);
if (pps->init_qp_minus26 < -(26 + qp_bd_offset))
return GST_H265_PARSER_BROKEN_LINK;
if (sps->scaling_list_enabled_flag && !sps->scaling_list_data_present_flag
&& !pps->scaling_list_data_present_flag)
if (!gst_h265_parser_parse_scaling_lists (NULL, &pps->scaling_list, TRUE))
return GST_H265_PARSER_BROKEN_LINK;
if (pps->cu_qp_delta_enabled_flag)
if (pps->diff_cu_qp_delta_depth >
sps->log2_diff_max_min_luma_coding_block_size)
return GST_H265_PARSER_BROKEN_LINK;
return ret;
}
/** /**
* gst_h265_parser_parse_slice_hdr: * gst_h265_parser_parse_slice_hdr:
* @parser: a #GstH265Parser * @parser: a #GstH265Parser
@ -2612,6 +2691,7 @@ gst_h265_parser_parse_slice_hdr (GstH265Parser * parser,
guint32 UsedByCurrPicLt[16]; guint32 UsedByCurrPicLt[16];
guint32 PicSizeInCtbsY; guint32 PicSizeInCtbsY;
gint NumPocTotalCurr = 0; gint NumPocTotalCurr = 0;
GstH265ParserResult err;
memset (slice, 0, sizeof (*slice)); memset (slice, 0, sizeof (*slice));
@ -2638,6 +2718,12 @@ gst_h265_parser_parse_slice_hdr (GstH265Parser * parser,
return GST_H265_PARSER_BROKEN_LINK; return GST_H265_PARSER_BROKEN_LINK;
} }
err = gst_h265_parser_fill_pps (parser, pps);
if (err != GST_H265_PARSER_OK) {
GST_WARNING ("couldn't fill pps id: %d", pps_id);
return err;
}
slice->pps = pps; slice->pps = pps;
sps = pps->sps; sps = pps->sps;
if (!sps) { if (!sps) {

View file

@ -788,6 +788,7 @@ struct _GstH265ShortTermRefPicSet
/** /**
* GstH265VUIParams: * GstH265VUIParams:
* @parsed: %TRUE indicate that VUI parameters have been parsed (Since: 1.22)
* @aspect_ratio_info_present_flag: %TRUE specifies that aspect_ratio_idc is present. * @aspect_ratio_info_present_flag: %TRUE specifies that aspect_ratio_idc is present.
* %FALSE specifies that aspect_ratio_idc is not present * %FALSE specifies that aspect_ratio_idc is not present
* @aspect_ratio_idc specifies the value of the sample aspect ratio of the luma samples * @aspect_ratio_idc specifies the value of the sample aspect ratio of the luma samples
@ -856,6 +857,14 @@ struct _GstH265ShortTermRefPicSet
*/ */
struct _GstH265VUIParams struct _GstH265VUIParams
{ {
/**
* _GstH265VUIParams.parsed:
*
* %TRUE indicate that VUI parameters have been parsed.
*
* Since: 1.22
*/
gboolean parsed;
guint8 aspect_ratio_info_present_flag; guint8 aspect_ratio_info_present_flag;
guint8 aspect_ratio_idc; guint8 aspect_ratio_idc;
/* if aspect_ratio_idc == 255 */ /* if aspect_ratio_idc == 255 */
@ -1102,6 +1111,14 @@ struct _GstH265SPS
{ {
guint8 id; guint8 id;
/**
* _GstH265SPS.vps_id:
*
* The ID of the VPS. This is used to store the ID until the VPS is
* parsed in case its placed after the SPS.
* Since: 1.22
*/
guint8 vps_id;
GstH265VPS *vps; GstH265VPS *vps;
guint8 max_sub_layers_minus1; guint8 max_sub_layers_minus1;
@ -1201,6 +1218,15 @@ struct _GstH265PPS
{ {
guint id; guint id;
/**
* _GstH265PPS.sps_id:
*
* The ID of the SPS. This is used to store the ID until the SPS is
* parsed in case its placed after the PPS.
*
* Since: 1.22
*/
guint sps_id;
GstH265SPS *sps; GstH265SPS *sps;
guint8 dependent_slice_segments_enabled_flag; guint8 dependent_slice_segments_enabled_flag;