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);
}
}
+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)
{
* 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);
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;