mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
qtmux: add support for writing vpcC box for VP9
Increases compatibility for VP9 in .mov in at least VLC. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3260>
This commit is contained in:
parent
f77f27f4c9
commit
5bed545113
5 changed files with 118 additions and 3 deletions
|
@ -8328,7 +8328,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 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 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-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 alignment: tu\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n",
|
||||
"direction": "sink",
|
||||
"presence": "request",
|
||||
"type": "GstQTMuxPad"
|
||||
|
|
|
@ -5766,3 +5766,50 @@ build_uuid_xmp_atom (GstBuffer * xmp_data)
|
|||
return build_atom_info_wrapper ((Atom *) uuid, atom_uuid_copy_data,
|
||||
atom_uuid_free);
|
||||
}
|
||||
|
||||
/* https://www.webmproject.org/vp9/mp4/#vp-codec-configuration-box */
|
||||
AtomInfo *
|
||||
build_vpcC_extension (guint8 profile, guint8 level, guint8 bit_depth,
|
||||
guint8 chroma_subsampling, gboolean video_full_range,
|
||||
guint8 colour_primaries, guint8 transfer_characteristics,
|
||||
guint8 matrix_coefficients)
|
||||
{
|
||||
AtomData *atom_data;
|
||||
guint8 *data_block;
|
||||
guint data_block_len;
|
||||
GstByteWriter bw;
|
||||
gboolean hdl = TRUE;
|
||||
guint8 val = 0;
|
||||
|
||||
gst_byte_writer_init (&bw);
|
||||
/* version, always 1 */
|
||||
hdl &= gst_byte_writer_put_uint8 (&bw, 1);
|
||||
/* flags of 24 bits */
|
||||
hdl &= gst_byte_writer_put_uint8 (&bw, 0);
|
||||
hdl &= gst_byte_writer_put_uint8 (&bw, 0);
|
||||
hdl &= gst_byte_writer_put_uint8 (&bw, 0);
|
||||
hdl &= gst_byte_writer_put_uint8 (&bw, profile);
|
||||
hdl &= gst_byte_writer_put_uint8 (&bw, level);
|
||||
val |= (bit_depth & 0xF) << 4;
|
||||
val |= (chroma_subsampling & 0x3) << 1;
|
||||
val |= !(!video_full_range);
|
||||
hdl &= gst_byte_writer_put_uint8 (&bw, val);
|
||||
hdl &= gst_byte_writer_put_uint8 (&bw, colour_primaries);
|
||||
hdl &= gst_byte_writer_put_uint8 (&bw, transfer_characteristics);
|
||||
hdl &= gst_byte_writer_put_uint8 (&bw, matrix_coefficients);
|
||||
/* codec initialization data, currently unused */
|
||||
hdl &= gst_byte_writer_put_uint16_le (&bw, 0);
|
||||
|
||||
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_vpcC, data_block, data_block_len);
|
||||
g_free (data_block);
|
||||
|
||||
return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data,
|
||||
atom_data_free);
|
||||
}
|
||||
|
|
|
@ -1118,6 +1118,10 @@ AtomInfo * build_SMI_atom (const GstBuffer *seqh);
|
|||
AtomInfo * build_ima_adpcm_extension (gint channels, gint rate,
|
||||
gint blocksize);
|
||||
AtomInfo * build_uuid_xmp_atom (GstBuffer * xmp);
|
||||
AtomInfo * build_vpcC_extension (guint8 profile, guint8 level, guint8 bit_depth,
|
||||
guint8 chroma_subsampling, gboolean video_full_range,
|
||||
guint8 colour_primaries, guint8 transfer_characteristics,
|
||||
guint8 matrix_coefficients);
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -6484,7 +6484,66 @@ gst_qt_mux_video_sink_set_caps (GstQTMuxPad * qtpad, GstCaps * caps)
|
|||
} else if (strcmp (mimetype, "video/x-vp8") == 0) {
|
||||
entry.fourcc = FOURCC_vp08;
|
||||
} else if (strcmp (mimetype, "video/x-vp9") == 0) {
|
||||
const char *profile_str, *chroma_format_str, *colorimetry_str;
|
||||
guint bitdepth_luma, bitdepth_chroma;
|
||||
guint8 profile = -1, chroma_format = -1;
|
||||
gboolean video_full_range;
|
||||
GstVideoColorimetry cinfo = { 0, };
|
||||
|
||||
entry.fourcc = FOURCC_vp09;
|
||||
|
||||
profile_str = gst_structure_get_string (structure, "profile");
|
||||
if (g_strcmp0 (profile_str, "0") == 0) {
|
||||
profile = 0;
|
||||
} else if (g_strcmp0 (profile_str, "1") == 0) {
|
||||
profile = 1;
|
||||
} else if (g_strcmp0 (profile_str, "2") == 0) {
|
||||
profile = 2;
|
||||
} else if (g_strcmp0 (profile_str, "3") == 0) {
|
||||
profile = 3;
|
||||
}
|
||||
|
||||
colorimetry_str = gst_structure_get_string (structure, "colorimetry");
|
||||
gst_video_colorimetry_from_string (&cinfo, colorimetry_str);
|
||||
video_full_range = cinfo.range == GST_VIDEO_COLOR_RANGE_0_255;
|
||||
|
||||
chroma_format_str = gst_structure_get_string (structure, "chroma-format");
|
||||
if (g_strcmp0 (chroma_format_str, "4:2:0") == 0) {
|
||||
const char *chroma_site_str;
|
||||
GstVideoChromaSite chroma_site;
|
||||
|
||||
chroma_site_str = gst_structure_get_string (structure, "chroma-site");
|
||||
chroma_site = gst_video_chroma_site_from_string (chroma_site_str);
|
||||
if (chroma_site == GST_VIDEO_CHROMA_SITE_V_COSITED) {
|
||||
chroma_format = 0;
|
||||
} else if (chroma_site == GST_VIDEO_CHROMA_SITE_COSITED) {
|
||||
chroma_format = 1;
|
||||
} else {
|
||||
chroma_format = 1;
|
||||
}
|
||||
} else if (g_strcmp0 (chroma_format_str, "4:2:2") == 0) {
|
||||
chroma_format = 2;
|
||||
} else if (g_strcmp0 (chroma_format_str, "4:4:4") == 0) {
|
||||
chroma_format = 3;
|
||||
}
|
||||
|
||||
gst_structure_get (structure, "bit-depth-luma", G_TYPE_UINT,
|
||||
&bitdepth_luma, "bit-depth-chroma", G_TYPE_UINT, &bitdepth_chroma,
|
||||
NULL);
|
||||
|
||||
if (profile == 0xFF || chroma_format == 0xFF
|
||||
|| bitdepth_luma != bitdepth_chroma || bitdepth_luma == 0) {
|
||||
GST_WARNING_OBJECT (qtmux, "cannot construct vpcC atom from "
|
||||
"incomplete caps");
|
||||
} else {
|
||||
ext_atom = build_vpcC_extension (profile, /* XXX: level */ 10,
|
||||
bitdepth_luma, chroma_format, video_full_range,
|
||||
gst_video_color_primaries_to_iso (cinfo.primaries),
|
||||
gst_video_transfer_function_to_iso (cinfo.transfer),
|
||||
gst_video_color_matrix_to_iso (cinfo.matrix));
|
||||
if (ext_atom)
|
||||
ext_atom_list = g_list_append (ext_atom_list, ext_atom);
|
||||
}
|
||||
} else if (strcmp (mimetype, "video/x-dirac") == 0) {
|
||||
entry.fourcc = FOURCC_drac;
|
||||
} else if (strcmp (mimetype, "video/x-qt-part") == 0) {
|
||||
|
|
|
@ -93,6 +93,12 @@
|
|||
"svqversion = (int) 3, " \
|
||||
COMMON_VIDEO_CAPS
|
||||
|
||||
#define VP9_CAPS \
|
||||
"video/x-vp9, " \
|
||||
"profile = (string) { 0, 1, 2, 3 }, " \
|
||||
"chroma-format = (string) { 4:2:0, 4:2:2, 4:4:4 }, " \
|
||||
COMMON_VIDEO_CAPS
|
||||
|
||||
#define COMMON_AUDIO_CAPS(c, r) \
|
||||
"channels = (int) [ 1, " G_STRINGIFY (c) " ], " \
|
||||
"rate = (int) [ 1, " G_STRINGIFY (r) " ]"
|
||||
|
@ -201,8 +207,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
|
|||
COMMON_VIDEO_CAPS_NO_FRAMERATE "; "
|
||||
"video/x-vp8, "
|
||||
COMMON_VIDEO_CAPS "; "
|
||||
"video/x-vp9, "
|
||||
COMMON_VIDEO_CAPS "; "
|
||||
VP9_CAPS "; "
|
||||
"video/x-dirac, "
|
||||
COMMON_VIDEO_CAPS "; " "video/x-qt-part, " COMMON_VIDEO_CAPS "; "
|
||||
"video/x-av1, " "alignment = (string) \"tu\", "
|
||||
|
|
Loading…
Reference in a new issue