From f7b719ae91e497ac1816fe6415f760aabb4133bd Mon Sep 17 00:00:00 2001 From: Jakub Adam Date: Mon, 17 Jul 2023 14:48:39 +0800 Subject: [PATCH] av1parse: calculate framerate from AV1 timing info When framerate info isn't provided by upstream elements, try to extract it from AV1 timing info, if present. Part-of: --- .../gst/videoparsers/gstav1parse.c | 66 ++++++++++++++++--- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/subprojects/gst-plugins-bad/gst/videoparsers/gstav1parse.c b/subprojects/gst-plugins-bad/gst/videoparsers/gstav1parse.c index 923bc5d70a..b6ef0543c4 100644 --- a/subprojects/gst-plugins-bad/gst/videoparsers/gstav1parse.c +++ b/subprojects/gst-plugins-bad/gst/videoparsers/gstav1parse.c @@ -110,6 +110,11 @@ struct _GstAV1Parse gchar *colorimetry; GstAV1Profile profile; + gint fps_n; + gint fps_d; + /* incaps framerate overwrites the AV1 time info */ + gboolean has_input_fps; + GstAV1ParseAligment in_align; gboolean detect_annex_b; GstAV1ParseAligment align; @@ -641,7 +646,6 @@ gst_av1_parse_update_src_caps (GstAV1Parse * self, GstCaps * caps) GstStructure *s = NULL; gint width, height; gint par_n = 0, par_d = 0; - gint fps_n = 0, fps_d = 0; const gchar *profile = NULL; if (G_UNLIKELY (!gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (self)))) @@ -685,14 +689,11 @@ gst_av1_parse_update_src_caps (GstAV1Parse * self, GstCaps * caps) } } - if (s && gst_structure_has_field (s, "framerate")) { - gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d); - } - - if (fps_n > 0 && fps_d > 0) { + if (self->fps_n > 0 && self->fps_d > 0) { gst_caps_set_simple (final_caps, "framerate", - GST_TYPE_FRACTION, fps_n, fps_d, NULL); - gst_base_parse_set_frame_rate (GST_BASE_PARSE (self), fps_n, fps_d, 0, 0); + GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL); + gst_base_parse_set_frame_rate (GST_BASE_PARSE (self), + self->fps_n, self->fps_d, 0, 0); } /* When not RGB, the chroma format is needed. */ @@ -878,6 +879,15 @@ gst_av1_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps) if (profile) self->profile = gst_av1_parse_profile_from_string (profile); + if (gst_structure_has_field (str, "framerate")) { + gst_structure_get_fraction (str, "framerate", &self->fps_n, &self->fps_d); + self->has_input_fps = TRUE; + } else { + self->fps_n = 0; + self->fps_d = 1; + self->has_input_fps = FALSE; + } + /* get upstream align from caps */ align = gst_av1_parse_alignment_from_caps (caps); if (align == GST_AV1_PARSE_ALIGN_ERROR) { @@ -1195,6 +1205,34 @@ gst_av1_parse_cache_one_obu (GstAV1Parse * self, GstBuffer * buffer, } } +static void +gst_av1_parse_calculate_framerate (GstAV1TimingInfo * ti, + gint * fps_n, gint * fps_d) +{ + /* To calculate framerate, we use this formula: + * + * time_scale 1 + * fps = ------------------------- x --------------------------------- + * num_units_in_display_tick num_ticks_per_picture_minus_1 + 1 + */ + if (ti->equal_picture_interval) { + gint gcd; + + *fps_n = ti->time_scale; + *fps_d = ti->num_units_in_display_tick * + (ti->num_ticks_per_picture_minus_1 + 1); + + gcd = gst_util_greatest_common_divisor (*fps_n, *fps_d); + if (gcd) { + *fps_n /= gcd; + *fps_d /= gcd; + } + } else { + *fps_n = 0; + *fps_d = 1; + } +} + static GstAV1ParserResult gst_av1_parse_handle_sequence_obu (GstAV1Parse * self, GstAV1OBU * obu) { @@ -1270,6 +1308,18 @@ gst_av1_parse_handle_sequence_obu (GstAV1Parse * self, GstAV1OBU * obu) self->update_caps = TRUE; } + if (!self->has_input_fps) { + gint fps_n, fps_d; + + gst_av1_parse_calculate_framerate (&seq_header.timing_info, &fps_n, &fps_d); + + if (self->fps_n != fps_n || self->fps_d != fps_d) { + self->fps_n = fps_n; + self->fps_d = fps_d; + self->update_caps = TRUE; + } + } + val = (self->parser->state.operating_point_idc >> 8) & 0x0f; for (i = 0; i < (1 << GST_AV1_MAX_SPATIAL_LAYERS); i++) { if (val & (1 << i))