From e12c94065d013986a5f69a14253ee9c439e41301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 10 Jan 2017 18:19:55 +0200 Subject: [PATCH] qtmux: Write tapt atom for MOV files if PAR not 1/1 Needed for QuickTime 7 to properly play files. Also write the clap atom for MOV files always, not only when ProRes is used as a video codec. It's mandatory for MOV. https://bugzilla.gnome.org/show_bug.cgi?id=777100 --- gst/isomp4/atoms.c | 38 +++++++++++++++++++++++++++ gst/isomp4/atoms.h | 11 +++++--- gst/isomp4/fourcc.h | 4 +++ gst/isomp4/gstqtmux.c | 53 ++++++++++++++++++++++++++------------ gst/isomp4/qtdemux_types.c | 1 + 5 files changed, 88 insertions(+), 19 deletions(-) diff --git a/gst/isomp4/atoms.c b/gst/isomp4/atoms.c index 3bc6be9749..ceadb59540 100644 --- a/gst/isomp4/atoms.c +++ b/gst/isomp4/atoms.c @@ -2813,6 +2813,11 @@ atom_trak_copy_data (AtomTRAK * trak, guint8 ** buffer, guint64 * size, if (!atom_tkhd_copy_data (&trak->tkhd, buffer, size, offset)) { return 0; } + if (trak->tapt) { + if (!trak->tapt->copy_data_func (trak->tapt->atom, buffer, size, offset)) { + return 0; + } + } if (trak->edts) { if (!atom_edts_copy_data (trak->edts, buffer, size, offset)) { return 0; @@ -4097,6 +4102,39 @@ build_clap_extension (gint width_n, gint width_d, gint height_n, gint height_d, atom_data_free); } +AtomInfo * +build_tapt_extension (gint clef_width, gint clef_height, gint prof_width, + gint prof_height, gint enof_width, gint enof_height) +{ + AtomData *atom_data = atom_data_new (FOURCC_tapt); + guint8 *data; + + atom_data_alloc_mem (atom_data, 60); + data = atom_data->data; + + GST_WRITE_UINT32_BE (data, 20); + GST_WRITE_UINT32_LE (data + 4, FOURCC_clef); + GST_WRITE_UINT32_BE (data + 8, 0); + GST_WRITE_UINT32_BE (data + 12, clef_width); + GST_WRITE_UINT32_BE (data + 16, clef_height); + + GST_WRITE_UINT32_BE (data + 20, 20); + GST_WRITE_UINT32_LE (data + 24, FOURCC_prof); + GST_WRITE_UINT32_BE (data + 28, 0); + GST_WRITE_UINT32_BE (data + 32, prof_width); + GST_WRITE_UINT32_BE (data + 36, prof_height); + + GST_WRITE_UINT32_BE (data + 40, 20); + GST_WRITE_UINT32_LE (data + 44, FOURCC_enof); + GST_WRITE_UINT32_BE (data + 48, 0); + GST_WRITE_UINT32_BE (data + 52, enof_width); + GST_WRITE_UINT32_BE (data + 56, enof_height); + + + 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) diff --git a/gst/isomp4/atoms.h b/gst/isomp4/atoms.h index 8f2ea1e2de..d38980bd23 100644 --- a/gst/isomp4/atoms.h +++ b/gst/isomp4/atoms.h @@ -113,6 +113,8 @@ void atoms_context_free (AtomsContext *context); /* atom defs and functions */ +typedef struct _AtomInfo AtomInfo; + /* * Used for storing time related values for some atoms. */ @@ -701,6 +703,7 @@ typedef struct _AtomTRAK Atom header; AtomTKHD tkhd; + AtomInfo *tapt; AtomEDTS *edts; AtomMDIA mdia; AtomUDTA udta; @@ -893,13 +896,12 @@ typedef guint64 (*AtomFreeFunc) (Atom *atom); * All we need are the two functions (copying it to an array * for serialization and the memory releasing function). */ -typedef struct _AtomInfo +struct _AtomInfo { Atom *atom; AtomCopyDataFunc copy_data_func; AtomFreeFunc free_func; -} AtomInfo; - +}; guint64 atom_copy_data (Atom *atom, guint8 **buffer, guint64 *size, guint64* offset); @@ -1056,6 +1058,9 @@ AtomInfo * build_jp2x_extension (const GstBuffer * prefix); AtomInfo * build_fiel_extension (GstVideoInterlaceMode mode, GstVideoFieldOrder order); AtomInfo * build_colr_extension (const GstVideoColorimetry *colorimetry, gboolean is_mp4); AtomInfo * build_clap_extension (gint width_n, gint width_d, gint height_n, gint height_d, gint h_off_n, gint h_off_d, gint v_off_n, gint v_off_d); +AtomInfo * build_tapt_extension (gint clef_width, gint clef_height, gint prof_width, gint prof_height, gint enof_width, gint enof_height); + + 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 2b86e5c148..8643ce994f 100644 --- a/gst/isomp4/fourcc.h +++ b/gst/isomp4/fourcc.h @@ -179,6 +179,10 @@ G_BEGIN_DECLS #define FOURCC_pasp GST_MAKE_FOURCC('p','a','s','p') #define FOURCC_colr GST_MAKE_FOURCC('c','o','l','r') #define FOURCC_clap GST_MAKE_FOURCC('c','l','a','p') +#define FOURCC_tapt GST_MAKE_FOURCC('t','a','p','t') +#define FOURCC_clef GST_MAKE_FOURCC('c','l','e','f') +#define FOURCC_prof GST_MAKE_FOURCC('p','r','o','f') +#define FOURCC_enof GST_MAKE_FOURCC('e','n','o','f') #define FOURCC_fiel GST_MAKE_FOURCC('f','i','e','l') #define FOURCC_pcst GST_MAKE_FOURCC('p','c','s','t') #define FOURCC_pgap GST_MAKE_FOURCC('p','g','a','p') diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c index b8fdf17108..f47e424199 100644 --- a/gst/isomp4/gstqtmux.c +++ b/gst/isomp4/gstqtmux.c @@ -4415,6 +4415,43 @@ gst_qt_mux_video_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) ext_atom_list = g_list_append (ext_atom_list, ext_atom); } + + if (qtmux_klass->format == GST_QT_MUX_FORMAT_QT) { + /* The 'clap' extension is also defined for MP4 but inventing values in + * general seems a bit tricky for this one. We only write it for MOV + * then, where it is a requirement. + * The same goes for the 'tapt' extension, just that it is not defined for + * MP4 and only for MOV + * + * NTSC and PAL have special values, otherwise just take width and height + */ + if (width == 720 && (height == 480 || height == 486)) { + ext_atom = build_clap_extension (704, 1, height, 1, 0, 1, 0, 1); + if (ext_atom) + ext_atom_list = g_list_append (ext_atom_list, ext_atom); + + } else if (width == 720 && height == 576) { + ext_atom = build_clap_extension (768 * 54, 59, 576, 1, 0, 1, 0, 1); + if (ext_atom) + ext_atom_list = g_list_append (ext_atom_list, ext_atom); + } else { + ext_atom = build_clap_extension (width, 1, height, 1, 0, 1, 0, 1); + if (ext_atom) + ext_atom_list = g_list_append (ext_atom_list, ext_atom); + } + + if (par_num != par_den) { + gint clef_width = + gst_util_uint64_scale (width, par_num * G_GUINT64_CONSTANT (65536), + par_den); + + ext_atom = + build_tapt_extension (clef_width, height << 16, clef_width, + height << 16, width << 16, height << 16); + qtpad->trak->tapt = ext_atom; + } + } + /* ok, set the pad info accordingly */ qtpad->fourcc = entry.fourcc; qtpad->sync = sync; @@ -4457,22 +4494,6 @@ gst_qt_mux_video_sink_set_caps (GstQTPad * qtpad, GstCaps * caps) strcpy ((gchar *) mp4v->compressor + 1, compressor); mp4v->compressor[0] = strlen (compressor); } - - /* The 'clap' extension is also defined for MP4 but inventing values in - * general seems a bit tricky for this one. We only write it for ProRes - * then, where it is a requirement. - * - * NTSC and PAL have special values, otherwise just take width and height - */ - if (width == 720 && (height == 480 || height == 486)) - ext_atom = build_clap_extension (704, 1, height, 1, 0, 1, 0, 1); - else if (width == 720 && height == 576) - ext_atom = build_clap_extension (768 * 54, 59, 576, 1, 0, 1, 0, 1); - else - ext_atom = build_clap_extension (width, 1, height, 1, 0, 1, 0, 1); - - if (ext_atom) - mp4v->extension_atoms = g_list_append (mp4v->extension_atoms, ext_atom); } gst_object_unref (qtmux); diff --git a/gst/isomp4/qtdemux_types.c b/gst/isomp4/qtdemux_types.c index 8ce37ceb57..15a6184963 100644 --- a/gst/isomp4/qtdemux_types.c +++ b/gst/isomp4/qtdemux_types.c @@ -85,6 +85,7 @@ static const QtNodeType qt_node_types[] = { {FOURCC_jp2h, "jp2h", QT_FLAG_CONTAINER,}, {FOURCC_colr, "colr", 0,}, {FOURCC_clap, "clap", 0,}, + {FOURCC_tapt, "tapt", 0,}, {FOURCC_ihdr, "ihdr", 0,}, {FOURCC_fiel, "fiel", 0,}, {FOURCC_jp2x, "jp2x", 0,},