diff --git a/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctions.c b/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctions.c index 334417f0fe..48d5653576 100644 --- a/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctions.c +++ b/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctions.c @@ -6777,6 +6777,154 @@ aa_type_find (GstTypeFind * tf, gpointer private) } } +/*** video/x-av1 ***/ + +static GstStaticCaps av1_caps = + GST_STATIC_CAPS + ("video/x-av1,stream-format={obu-stream, annexb},alignment=none"); + +#define AV1_CAPS gst_static_caps_get(&av1_caps) + +static gboolean +av1_is_valid_obu_type (guint obu_type) +{ + if ((obu_type > 0 && obu_type < 9) || obu_type == 15) + return TRUE; + + return FALSE; +} + +static gboolean +av1_leb128 (const guint8 * data, guint32 * retval, gint * read_bytes) +{ + guint8 leb128_byte = 0; + guint64 value = 0; + gint i; + + *retval = 0; + *read_bytes = 0; + + for (i = 0; i < 8; i++) { + leb128_byte = data[i]; + value |= (((gint) leb128_byte & 0x7f) << (i * 7)); + if (!(leb128_byte & 0x80)) + break; + + if (i == 7 && leb128_byte & 0x80) + return FALSE; + } + + if (i == 8) + return FALSE; + + /* check for bitstream conformance see chapter 4.10.5 */ + if (value < G_MAXUINT32) { + *retval = (guint32) value; + *read_bytes = i + 1; + return TRUE; + } + + return FALSE; +} + +static gboolean +av1_is_valid_obu (const guint8 * data, guint * obu_type, gint * read_bytes) +{ + gboolean obu_forbidden_bit; + gboolean obu_extension_flag; + gboolean obu_has_size_field; + gboolean obu_reserved_1bit; + int offset = 1; + + *obu_type = 0; + *read_bytes = 0; + + /* Detect OBU header */ + obu_forbidden_bit = !!(data[0] & 0x80); + if (obu_forbidden_bit) + return FALSE; + + *obu_type = (data[0] & 0x78) >> 3; + obu_extension_flag = !!(data[0] & 0x4); + obu_has_size_field = !!(data[0] & 0x2); + obu_reserved_1bit = !!(data[0] & 0x1); + + /* if obu_extension_flag is set temporal_id (3 bits) + * spatial_id (2 bits) and extension_header_reserved_3bits (3 bits) + * field are coded in the header so OBU size field is + * 1 byte after */ + if (obu_extension_flag) + offset++; + + *read_bytes += offset; + + if (av1_is_valid_obu_type (*obu_type) && !obu_reserved_1bit) { + if (obu_has_size_field) { + guint32 obu_size; + gint bytes; + + if (!av1_leb128 (data + offset, &obu_size, &bytes)) + return FALSE; + *read_bytes += bytes; + } + + return TRUE; + } + + return FALSE; +} + +static void +av1_type_find (GstTypeFind * tf, gpointer unused) +{ + guint32 temporal_unit_size; + guint32 frame_unit_size; + guint32 obu_length; + const guint8 *data; + guint obu_type; + gint read_bytes; + gint offset = 0; + + data = gst_type_find_peek (tf, 0, 25); + if (!data) + return; + + if (av1_is_valid_obu (data, &obu_type, &read_bytes)) { + gst_type_find_suggest_simple (tf, GST_TYPE_FIND_MINIMUM, "video/x-av1", + "stream-format", G_TYPE_STRING, "obu-stream", + "alignment", G_TYPE_STRING, "none", NULL); + return; + } + + if (!av1_leb128 (data, &temporal_unit_size, &read_bytes)) + return; + offset += read_bytes; + + if (!av1_leb128 (data + offset, &frame_unit_size, &read_bytes)) + return; + offset += read_bytes; + + if (frame_unit_size > temporal_unit_size) + return; + + if (!av1_leb128 (data + offset, &obu_length, &read_bytes)) + return; + offset += read_bytes; + + if (obu_length > frame_unit_size) + return; + + if (!av1_is_valid_obu (data + offset, &obu_type, &read_bytes)) + return; + offset += read_bytes; + + /* The first OBU must be a temporal delimiter */ + if (obu_type == 2) + gst_type_find_suggest_simple (tf, GST_TYPE_FIND_MINIMUM, "video/x-av1", + "stream-format", G_TYPE_STRING, "annexb", + "alignment", G_TYPE_STRING, "none", NULL); +} + /*Type find definition by functions */ GST_TYPE_FIND_REGISTER_DEFINE (musepack, "audio/x-musepack", GST_RANK_PRIMARY, musepack_type_find, "mpc,mpp,mp+", MUSEPACK_CAPS, NULL, NULL); @@ -7042,3 +7190,5 @@ GST_TYPE_FIND_REGISTER_DEFINE (wsaud, "application/x-wsaud", GST_RANK_MARGINAL, wsaud_type_find, "wsaud", WSAUD_CAPS, NULL, NULL); GST_TYPE_FIND_REGISTER_DEFINE (wsvqa, "application/x-wsvqa", GST_RANK_MARGINAL, wsvqa_type_find, "wsvqa", WSVQA_CAPS, NULL, NULL); +GST_TYPE_FIND_REGISTER_DEFINE (av1, "video/x-av1", GST_RANK_MARGINAL, + av1_type_find, "av1", AV1_CAPS, NULL, NULL); diff --git a/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctionsplugin.c b/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctionsplugin.c index 9ff09cc0bf..6db5bf1efe 100644 --- a/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctionsplugin.c +++ b/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctionsplugin.c @@ -214,6 +214,7 @@ plugin_init (GstPlugin * plugin) GST_TYPE_FIND_REGISTER (film_cpk, plugin); GST_TYPE_FIND_REGISTER (gxf, plugin); GST_TYPE_FIND_REGISTER (iff, plugin); + GST_TYPE_FIND_REGISTER (av1, plugin); return TRUE; } diff --git a/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctionsplugin.h b/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctionsplugin.h index b48e872dd2..e9227180f4 100644 --- a/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctionsplugin.h +++ b/subprojects/gst-plugins-base/gst/typefind/gsttypefindfunctionsplugin.h @@ -220,5 +220,6 @@ GST_TYPE_FIND_REGISTER_DECLARE (vmd); GST_TYPE_FIND_REGISTER_DECLARE (wc3movie); GST_TYPE_FIND_REGISTER_DECLARE (wsaud); GST_TYPE_FIND_REGISTER_DECLARE (wsvqa); +GST_TYPE_FIND_REGISTER_DECLARE (av1); #endif //__GST_TYPE_FIND_FUNCTIONS_PLUGIN_H__