qtmux: add support for VVC/H.266 video

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8436>
This commit is contained in:
Carlos Bentzen 2025-02-07 18:53:11 +01:00 committed by GStreamer Marge Bot
parent 5feb80193e
commit e2bd8809bf
5 changed files with 66 additions and 6 deletions

View File

@ -8460,7 +8460,7 @@
"type": "GstQTMuxPad"
},
"video_%%u": {
"caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-divx:\n divxversion: 5\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h264:\n stream-format: { (string)avc, (string)avc3 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h265:\n stream-format: { (string)hvc1, (string)hev1 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-mp4-part:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-av1:\n stream-format: obu-stream\n alignment: tu\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp9:\n profile: { (string)0, (string)1, (string)2, (string)3 }\n chroma-format: { (string)4:2:0, (string)4:2:2, (string)4:4:4 }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n",
"caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-divx:\n divxversion: 5\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h264:\n stream-format: { (string)avc, (string)avc3 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h265:\n stream-format: { (string)hvc1, (string)hev1 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h266:\n stream-format: { (string)vvc1, (string)vvi1 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-mp4-part:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-av1:\n stream-format: obu-stream\n alignment: tu\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp9:\n profile: { (string)0, (string)1, (string)2, (string)3 }\n chroma-format: { (string)4:2:0, (string)4:2:2, (string)4:4:4 }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n",
"direction": "sink",
"presence": "request",
"type": "GstQTMuxPad"
@ -8633,7 +8633,7 @@
"type": "GstQTMuxPad"
},
"video_%%u": {
"caps": "video/x-raw:\n format: { RGB, UYVY, v210 }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-divx:\n divxversion: 5\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-prores:\n variant: { (string)standard, (string)lt, (string)hq, (string)proxy, (string)4444, (string)4444xq }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-cineform:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h263:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h264:\n stream-format: { (string)avc, (string)avc3 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h265:\n stream-format: { (string)hvc1, (string)hev1 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-svq:\n svqversion: 3\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-dv:\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nimage/jpeg:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nimage/png:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp8:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp9:\n profile: { (string)0, (string)1, (string)2, (string)3 }\n chroma-format: { (string)4:2:0, (string)4:2:2, (string)4:4:4 }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-dirac:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-qt-part:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-av1:\n stream-format: obu-stream\n alignment: tu\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n",
"caps": "video/x-raw:\n format: { RGB, UYVY, v210 }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-divx:\n divxversion: 5\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-prores:\n variant: { (string)standard, (string)lt, (string)hq, (string)proxy, (string)4444, (string)4444xq }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-cineform:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h263:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h264:\n stream-format: { (string)avc, (string)avc3 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h265:\n stream-format: { (string)hvc1, (string)hev1 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h266:\n stream-format: { (string)vvc1, (string)vvi1 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-svq:\n svqversion: 3\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-dv:\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nimage/jpeg:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nimage/png:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp8:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp9:\n profile: { (string)0, (string)1, (string)2, (string)3 }\n chroma-format: { (string)4:2:0, (string)4:2:2, (string)4:4:4 }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-dirac:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-qt-part:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-av1:\n stream-format: obu-stream\n alignment: tu\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n",
"direction": "sink",
"presence": "request",
"type": "GstQTMuxPad"

View File

@ -5811,3 +5811,32 @@ build_vpcC_extension (guint8 profile, guint8 level, guint8 bit_depth,
return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
atom_data_free);
}
AtomInfo *
build_vvcC_extension (guint8 version, guint32 flags,
const GstBuffer * codec_data)
{
AtomData *atom_data;
GstByteWriter bw;
gboolean hdl = TRUE;
guint8 *data_block;
guint data_block_len;
gst_byte_writer_init (&bw);
hdl &= gst_byte_writer_put_uint8 (&bw, version);
hdl &= gst_byte_writer_put_uint24_be (&bw, flags & 0xFFFFFF);
hdl &= gst_byte_writer_put_buffer (&bw, (GstBuffer *) codec_data, 0, -1);
if (!hdl) {
GST_WARNING ("error creating header");
return NULL;
}
data_block_len = gst_byte_writer_get_size (&bw);
data_block = gst_byte_writer_reset_and_get_data (&bw);
atom_data = atom_data_new_from_data (FOURCC_vvcC, data_block, data_block_len);
g_free (data_block);
return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
atom_data_free);
}

View File

@ -1122,6 +1122,7 @@ AtomInfo * build_vpcC_extension (guint8 profile, guint8 level, guint8 b
guint8 chroma_subsampling, gboolean video_full_range,
guint8 colour_primaries, guint8 transfer_characteristics,
guint8 matrix_coefficients);
AtomInfo * build_vvcC_extension (guint8 version, guint32 flags, const GstBuffer* codec_data);
/*

View File

@ -5820,7 +5820,8 @@ check_field (const GstIdStr * fieldname, const GValue * value,
}
if (g_strcmp0 (name, "video/x-h264") == 0 ||
g_strcmp0 (name, "video/x-h265") == 0) {
g_strcmp0 (name, "video/x-h265") == 0 ||
g_strcmp0 (name, "video/x-h266") == 0) {
/* We support muxing multiple codec_data structures, and the new SPS
* will contain updated tier / level / profiles, which means we do
* not need to fail renegotiation when those change.
@ -6468,6 +6469,28 @@ gst_qt_mux_video_sink_set_caps (GstQTMuxPad * qtpad, GstCaps * caps)
if (ext_atom != NULL)
ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
} else if (strcmp (mimetype, "video/x-h266") == 0) {
const gchar *format;
if (!codec_data) {
GST_WARNING_OBJECT (qtmux, "no codec_data in h266 caps");
goto refuse_caps;
}
format = gst_structure_get_string (structure, "stream-format");
if (strcmp (format, "vvc1") == 0)
entry.fourcc = FOURCC_vvc1;
else if (strcmp (format, "vvi1") == 0)
entry.fourcc = FOURCC_vvi1;
ext_atom = build_btrt_extension (0, qtpad->avg_bitrate, qtpad->max_bitrate);
if (ext_atom != NULL)
ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
ext_atom = build_vvcC_extension (0, 0, codec_data);
if (ext_atom != NULL)
ext_atom_list = g_list_prepend (ext_atom_list, ext_atom);
} else if (strcmp (mimetype, "video/x-svq") == 0) {
gint version = 0;
const GstBuffer *seqh = NULL;

View File

@ -70,6 +70,12 @@
"alignment = (string) au, " \
COMMON_VIDEO_CAPS
#define H266_CAPS \
"video/x-h266, " \
"stream-format = (string) { vvc1, vvi1 }, " \
"alignment = (string) au, " \
COMMON_VIDEO_CAPS
#define MPEG4V_CAPS \
"video/mpeg, " \
"mpegversion = (int) 4, "\
@ -197,6 +203,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
H263_CAPS "; "
H264_CAPS "; "
H265_CAPS "; "
H266_CAPS "; "
SVQ_CAPS "; "
"video/x-dv, "
"systemstream = (boolean) false, "
@ -229,9 +236,9 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
"MP4",
"GstMP4Mux",
GST_STATIC_CAPS ("video/quicktime, variant = (string) iso"),
GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS ";" H265_CAPS ";"
"video/x-mp4-part," COMMON_VIDEO_CAPS "; "
"video/x-av1, " "stream-format = (string) \"obu-stream\", "
GST_STATIC_CAPS (MPEG4V_CAPS "; " H264_CAPS ";" H265_CAPS ";" H266_CAPS
";" "video/x-mp4-part," COMMON_VIDEO_CAPS "; " "video/x-av1, "
"stream-format = (string) \"obu-stream\", "
"alignment = (string) \"tu\", " COMMON_VIDEO_CAPS "; " VP9_CAPS
"; "),
GST_STATIC_CAPS (MP123_CAPS "; " AAC_CAPS " ; " AC3_CAPS " ; " ALAC_CAPS