mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-25 11:11:08 +00:00
h264parse: Validate VUI framerate
A few streams contain invalid/wrong framerate in VUI. Do validate it based on the spec and ignore invalid VUI framerate values. Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1753 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4127>
This commit is contained in:
parent
be72fbc334
commit
ad30fb87c2
2 changed files with 107 additions and 0 deletions
|
@ -276,6 +276,7 @@ gst_h264_parse_reset_stream_info (GstH264Parse * h264parse)
|
|||
h264parse->packetized = FALSE;
|
||||
h264parse->push_codec = FALSE;
|
||||
h264parse->first_frame = TRUE;
|
||||
h264parse->ignore_vui_fps = FALSE;
|
||||
|
||||
gst_buffer_replace (&h264parse->codec_data, NULL);
|
||||
gst_buffer_replace (&h264parse->codec_data_in, NULL);
|
||||
|
@ -2039,6 +2040,82 @@ get_level_string (GstH264SPS * sps)
|
|||
}
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_H264_LEVEL_L1 = 10,
|
||||
GST_H264_LEVEL_L1B = 9,
|
||||
GST_H264_LEVEL_L1_1 = 11,
|
||||
GST_H264_LEVEL_L1_2 = 12,
|
||||
GST_H264_LEVEL_L1_3 = 13,
|
||||
GST_H264_LEVEL_L2_0 = 20,
|
||||
GST_H264_LEVEL_L2_1 = 21,
|
||||
GST_H264_LEVEL_L2_2 = 22,
|
||||
GST_H264_LEVEL_L3 = 30,
|
||||
GST_H264_LEVEL_L3_1 = 31,
|
||||
GST_H264_LEVEL_L3_2 = 32,
|
||||
GST_H264_LEVEL_L4 = 40,
|
||||
GST_H264_LEVEL_L4_1 = 41,
|
||||
GST_H264_LEVEL_L4_2 = 42,
|
||||
GST_H264_LEVEL_L5 = 50,
|
||||
GST_H264_LEVEL_L5_1 = 51,
|
||||
GST_H264_LEVEL_L5_2 = 52,
|
||||
GST_H264_LEVEL_L6 = 60,
|
||||
GST_H264_LEVEL_L6_1 = 61,
|
||||
GST_H264_LEVEL_L6_2 = 62,
|
||||
} GstH264Level;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstH264Level level;
|
||||
guint max_sample_per_sec;
|
||||
} GstH264LevelLimit;
|
||||
|
||||
static const GstH264LevelLimit level_limits_map[] = {
|
||||
{GST_H264_LEVEL_L1, 380160},
|
||||
{GST_H264_LEVEL_L1B, 380160},
|
||||
{GST_H264_LEVEL_L1_1, 768000},
|
||||
{GST_H264_LEVEL_L1_2, 1536000},
|
||||
{GST_H264_LEVEL_L1_3, 3041280},
|
||||
{GST_H264_LEVEL_L2_0, 3041280},
|
||||
{GST_H264_LEVEL_L2_1, 5068800},
|
||||
{GST_H264_LEVEL_L2_2, 5184000},
|
||||
{GST_H264_LEVEL_L3, 10368000},
|
||||
{GST_H264_LEVEL_L3_1, 27648000},
|
||||
{GST_H264_LEVEL_L3_2, 55296000},
|
||||
{GST_H264_LEVEL_L4, 62914560},
|
||||
{GST_H264_LEVEL_L4_1, 62914560},
|
||||
{GST_H264_LEVEL_L4_2, 62914560},
|
||||
{GST_H264_LEVEL_L5, 150994994},
|
||||
{GST_H264_LEVEL_L5_1, 251658240},
|
||||
{GST_H264_LEVEL_L5_2, 530841600},
|
||||
{GST_H264_LEVEL_L6, 1069547520},
|
||||
{GST_H264_LEVEL_L6_1, 2139095040},
|
||||
{GST_H264_LEVEL_L6_2, 4278190080},
|
||||
};
|
||||
|
||||
/* A.3.4 Effect of level limits on frame rate (informative) */
|
||||
static guint
|
||||
get_max_samples_per_second (const GstH264SPS * sps)
|
||||
{
|
||||
guint i;
|
||||
guint n_levels = G_N_ELEMENTS (level_limits_map);
|
||||
GstH264Level level = (GstH264Level) sps->level_idc;
|
||||
|
||||
if (level == GST_H264_LEVEL_L1_1 &&
|
||||
(sps->profile_idc == 66 || sps->profile_idc == 77) &&
|
||||
sps->constraint_set3_flag) {
|
||||
/* Level 1b */
|
||||
level = GST_H264_LEVEL_L1B;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_levels; i++) {
|
||||
if (level == level_limits_map[i].level)
|
||||
return level_limits_map[i].max_sample_per_sec;
|
||||
}
|
||||
|
||||
return level_limits_map[n_levels - 1].max_sample_per_sec;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
|
||||
{
|
||||
|
@ -2122,6 +2199,32 @@ gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
|
|||
* it in case we have no info */
|
||||
gst_h264_video_calculate_framerate (sps, h264parse->field_pic_flag,
|
||||
h264parse->sei_pic_struct, &fps_num, &fps_den);
|
||||
|
||||
/* Checks whether given framerate makes sense or not
|
||||
* See also A.3.4 Effect of level limits on frame rate (informative)
|
||||
*/
|
||||
h264parse->ignore_vui_fps = FALSE;
|
||||
if (fps_num > 0 && fps_den > 0 && sps->width > 0 && sps->height > 0 &&
|
||||
sps->vui_parameters_present_flag &&
|
||||
sps->vui_parameters.timing_info_present_flag) {
|
||||
guint luma_samples = sps->width * sps->height;
|
||||
guint max_samples = get_max_samples_per_second (sps);
|
||||
gdouble max_fps, cur_fps;
|
||||
|
||||
cur_fps = (gdouble) fps_num / fps_den;
|
||||
max_fps = (gdouble) max_samples / luma_samples;
|
||||
|
||||
/* XXX: allows up to 2x higher framerate */
|
||||
if (max_fps * 2 < cur_fps) {
|
||||
GST_WARNING_OBJECT (h264parse,
|
||||
"VUI framerate %.1f exceeds allowed maximum %.1f",
|
||||
cur_fps, max_fps);
|
||||
fps_num = 0;
|
||||
fps_den = 1;
|
||||
h264parse->ignore_vui_fps = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (h264parse->fps_num != fps_num
|
||||
|| h264parse->fps_den != fps_den)) {
|
||||
GST_DEBUG_OBJECT (h264parse, "framerate changed %d/%d", fps_num, fps_den);
|
||||
|
@ -2461,6 +2564,9 @@ gst_h264_parse_get_duration (GstH264Parse * h264parse, gboolean frame)
|
|||
if (!sps) {
|
||||
GST_DEBUG_OBJECT (h264parse, "referred SPS invalid");
|
||||
goto fps_duration;
|
||||
} else if (h264parse->ignore_vui_fps) {
|
||||
GST_DEBUG_OBJECT (h264parse, "VUI framerate is not reliable");
|
||||
goto fps_duration;
|
||||
} else if (!sps->vui_parameters_present_flag) {
|
||||
GST_DEBUG_OBJECT (h264parse, "unable to compute duration: VUI not present");
|
||||
goto fps_duration;
|
||||
|
|
|
@ -117,6 +117,7 @@ struct _GstH264Parse
|
|||
guint8 sei_pic_struct;
|
||||
guint8 sei_pic_struct_pres_flag;
|
||||
guint field_pic_flag;
|
||||
gboolean ignore_vui_fps;
|
||||
|
||||
/* cached timestamps */
|
||||
/* (trying to) track upstream dts and interpolate */
|
||||
|
|
Loading…
Reference in a new issue