diff --git a/gst/isomp4/atoms.c b/gst/isomp4/atoms.c index f53004ebd8..338bae590f 100644 --- a/gst/isomp4/atoms.c +++ b/gst/isomp4/atoms.c @@ -3915,6 +3915,106 @@ build_pasp_extension (gint par_width, gint par_height) atom_data_free); } +AtomInfo * +build_fiel_extension_prores (const gchar * interlace_mode, gboolean tff) +{ + AtomData *atom_data = atom_data_new (FOURCC_fiel); + guint8 *data; + gint field_order; + gint interlace; + + atom_data_alloc_mem (atom_data, 2); + data = atom_data->data; + + if (!g_strcmp0 (interlace_mode, "progressive")) { + interlace = 1; + field_order = 0; + } else { + interlace = 2; + if (!g_strcmp0 (interlace_mode, "interleaved")) + field_order = tff ? 9 : 14; + else if (!g_strcmp0 (interlace_mode, "mixed")) + field_order = tff ? 1 : 6; + else + g_assert_not_reached (); + } + + GST_WRITE_UINT8 (data, interlace); + GST_WRITE_UINT8 (data + 1, field_order); + + return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data, + atom_data_free); +} + +AtomInfo * +build_colr_extension (GstVideoColorimetry colorimetry) +{ + AtomData *atom_data = atom_data_new (FOURCC_colr); + guint8 *data; + guint16 primaries; + guint16 transfer_function; + guint16 matrix; + + switch (colorimetry.primaries) { + case GST_VIDEO_COLOR_PRIMARIES_BT709: + primaries = 1; + break; + case GST_VIDEO_COLOR_PRIMARIES_BT470BG: + primaries = 5; + break; + case GST_VIDEO_COLOR_PRIMARIES_SMPTE170M: + case GST_VIDEO_COLOR_PRIMARIES_SMPTE240M: + primaries = 6; + break; + case GST_VIDEO_COLOR_PRIMARIES_UNKNOWN: + default: + primaries = 2; + break; + } + + switch (colorimetry.transfer) { + case GST_VIDEO_TRANSFER_BT709: + transfer_function = 1; + break; + case GST_VIDEO_TRANSFER_SMPTE240M: + transfer_function = 7; + break; + case GST_VIDEO_TRANSFER_UNKNOWN: + default: + transfer_function = 2; + break; + } + + switch (colorimetry.matrix) { + case GST_VIDEO_COLOR_MATRIX_BT709: + matrix = 1; + break; + case GST_VIDEO_COLOR_MATRIX_BT601: + matrix = 6; + break; + case GST_VIDEO_COLOR_MATRIX_SMPTE240M: + matrix = 7; + break; + case GST_VIDEO_COLOR_MATRIX_UNKNOWN: + default: + matrix = 2; + break; + } + + atom_data_alloc_mem (atom_data, 10); + data = atom_data->data; + + /* colour specification box */ + GST_WRITE_UINT32_LE (data, FOURCC_nclc); + + GST_WRITE_UINT16_BE (data + 4, primaries); + GST_WRITE_UINT16_BE (data + 6, transfer_function); /* transfer function */ + GST_WRITE_UINT16_BE (data + 8, matrix); + + return build_atom_info_wrapper ((Atom *) atom_data, atom_data_copy_data, + atom_data_free); +} + SampleTableEntryMP4V * atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, VisualSampleEntry * entry, guint32 scale, GList * ext_atoms_list) @@ -3923,11 +4023,8 @@ atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, guint dwidth, dheight; gint par_n = 0, par_d = 0; - if ((entry->par_n != 1 || entry->par_d != 1) && - (entry->par_n != entry->par_d)) { - par_n = entry->par_n; - par_d = entry->par_d; - } + par_n = entry->par_n; + par_d = entry->par_d; dwidth = entry->width; dheight = entry->height; @@ -3960,7 +4057,7 @@ atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, ste->extension_atoms = g_list_concat (ste->extension_atoms, ext_atoms_list); /* QT spec has a pasp extension atom in stsd that can hold PAR */ - if (par_n && (context->flavor == ATOMS_TREE_FLAVOR_MOV)) { + if (context->flavor == ATOMS_TREE_FLAVOR_MOV) { ste->extension_atoms = g_list_append (ste->extension_atoms, build_pasp_extension (par_n, par_d)); } diff --git a/gst/isomp4/atoms.h b/gst/isomp4/atoms.h index 283d9cfe2f..ba829e2a26 100644 --- a/gst/isomp4/atoms.h +++ b/gst/isomp4/atoms.h @@ -1044,6 +1044,8 @@ AtomInfo * build_jp2h_extension (gint width, gint height, const gchar * AtomInfo * build_jp2x_extension (const GstBuffer * prefix); AtomInfo * build_fiel_extension (gint fields); +AtomInfo * build_fiel_extension_prores (const gchar * interlace_mode, gboolean tff); +AtomInfo * build_colr_extension (GstVideoColorimetry colorimetry); AtomInfo * build_ac3_extension (guint8 fscod, guint8 bsid, guint8 bsmod, guint8 acmod, guint8 lfe_on, guint8 bitrate_code); diff --git a/gst/isomp4/fourcc.h b/gst/isomp4/fourcc.h index 9e7408b95f..d7d9e8d833 100644 --- a/gst/isomp4/fourcc.h +++ b/gst/isomp4/fourcc.h @@ -169,6 +169,7 @@ G_BEGIN_DECLS #define FOURCC_mp4s GST_MAKE_FOURCC('m','p','4','s') #define FOURCC_mp4v GST_MAKE_FOURCC('m','p','4','v') #define FOURCC_name GST_MAKE_FOURCC('n','a','m','e') +#define FOURCC_nclc GST_MAKE_FOURCC('n','c','l','c') #define FOURCC_opus GST_MAKE_FOURCC('O','p','u','s') #define FOURCC_dops GST_MAKE_FOURCC('d','O','p','s') #define FOURCC_pasp GST_MAKE_FOURCC('p','a','s','p') diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c index 0847d4e18d..42e9533a6b 100644 --- a/gst/isomp4/gstqtmux.c +++ b/gst/isomp4/gstqtmux.c @@ -4246,8 +4246,14 @@ gst_qt_mux_video_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) entry.fourcc = fourcc; } else if (strcmp (mimetype, "video/x-prores") == 0) { const gchar *variant; + const gchar *colorimetry_str; + const gchar *interlace_mode; + gboolean tff = TRUE; + GstVideoColorimetry colorimetry; variant = gst_structure_get_string (structure, "variant"); + colorimetry_str = gst_structure_get_string (structure, "colorimetry"); + interlace_mode = gst_structure_get_string (structure, "interlace-mode"); if (!variant || !g_strcmp0 (variant, "standard")) entry.fourcc = FOURCC_apcn; else if (!g_strcmp0 (variant, "lt")) @@ -4256,6 +4262,29 @@ gst_qt_mux_video_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) entry.fourcc = FOURCC_apch; else if (!g_strcmp0 (variant, "proxy")) entry.fourcc = FOURCC_apco; + if (!g_strcmp0 (interlace_mode, "interleaved") || + !g_strcmp0 (interlace_mode, "mixed")) { + /* Assume top-fields-first if unspecified */ + gst_structure_get_boolean (structure, "top-field-first", &tff); + } + + if (gst_video_colorimetry_from_string (&colorimetry, colorimetry_str)) { + ext_atom = build_colr_extension (colorimetry); + if (ext_atom) + ext_atom_list = g_list_append (ext_atom_list, ext_atom); + } + + ext_atom = build_fiel_extension_prores (interlace_mode, tff); + if (ext_atom) + ext_atom_list = g_list_append (ext_atom_list, ext_atom); + + if (colorimetry_str == NULL) { + /* TODO: Maybe implement better heuristics */ + GST_WARNING_OBJECT (qtmux, + "Colorimetry information not found in caps. The resulting file's " + "color information might be wrong"); + colorimetry_str = height < 720 ? "bt601" : "bt709"; + } } if (!entry.fourcc) @@ -4267,6 +4296,12 @@ gst_qt_mux_video_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) qtpad->trak_ste = (SampleTableEntry *) atom_trak_set_video_type (qtpad->trak, qtmux->context, &entry, rate, ext_atom_list); + if (strcmp (mimetype, "video/x-prores") == 0) { + SampleTableEntryMP4V *mp4v = (SampleTableEntryMP4V *) qtpad->trak_ste; + mp4v->spatial_quality = 0x3FF; + mp4v->temporal_quality = 0; + mp4v->vendor = FOURCC_appl; + } gst_object_unref (qtmux); return TRUE;