diff --git a/gst/qtmux/atoms.c b/gst/qtmux/atoms.c index 57b9aa483d..5d73ae22a9 100644 --- a/gst/qtmux/atoms.c +++ b/gst/qtmux/atoms.c @@ -3055,7 +3055,7 @@ build_pasp_extension (AtomTRAK * trak, gint par_width, gint par_height) void atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, - VisualSampleEntry * entry, guint32 scale, AtomInfo * ext) + VisualSampleEntry * entry, guint32 scale, GList * ext_atoms_list) { SampleTableEntryMP4V *ste; gint dwidth, dheight; @@ -3087,14 +3087,15 @@ atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, trak->is_video = TRUE; trak->is_h264 = (entry->fourcc == FOURCC_avc1); + ste->version = entry->version; ste->width = entry->width; ste->height = entry->height; ste->depth = entry->depth; ste->color_table_id = entry->color_table_id; ste->frame_count = entry->frame_count; - if (ext) - ste->extension_atoms = g_list_prepend (ste->extension_atoms, ext); + if (ext_atoms_list) + 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)) { @@ -3301,3 +3302,38 @@ build_h263_extension () gst_buffer_unref (buf); return res; } + +AtomInfo * +build_gama_atom (gdouble gamma) +{ + AtomInfo *res; + guint32 gamma_fp; + GstBuffer *buf; + + /* convert to uint32 from fixed point */ + gamma_fp = (guint32) 65536 *gamma; + + buf = gst_buffer_new_and_alloc (4); + GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), gamma_fp); + res = build_codec_data_extension (FOURCC_gama, buf); + gst_buffer_unref (buf); + return res; +} + +AtomInfo * +build_SMI_atom (const GstBuffer * seqh) +{ + AtomInfo *res; + GstBuffer *buf; + + /* the seqh plus its size and fourcc */ + buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (seqh) + 8); + + GST_WRITE_UINT32_LE (GST_BUFFER_DATA (buf), FOURCC_SEQH); + GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + 4, GST_BUFFER_SIZE (seqh)); + memcpy (GST_BUFFER_DATA (buf) + 8, GST_BUFFER_DATA (seqh), + GST_BUFFER_SIZE (seqh)); + res = build_codec_data_extension (FOURCC_SMI_, buf); + gst_buffer_unref (buf); + return res; +} diff --git a/gst/qtmux/atoms.h b/gst/qtmux/atoms.h index 07efef5dc1..87275d897e 100644 --- a/gst/qtmux/atoms.h +++ b/gst/qtmux/atoms.h @@ -628,6 +628,7 @@ void atom_moov_add_trak (AtomMOOV *moov, AtomTRAK *trak); typedef struct { + guint16 version; guint32 fourcc; guint width; guint height; @@ -659,9 +660,10 @@ typedef struct void atom_trak_set_audio_type (AtomTRAK * trak, AtomsContext * context, AudioSampleEntry * entry, guint32 scale, AtomInfo * ext, gint sample_size); + void atom_trak_set_video_type (AtomTRAK * trak, AtomsContext * context, VisualSampleEntry * entry, guint32 rate, - AtomInfo * ext); + GList * ext_atoms_list); AtomInfo * build_codec_data_extension (guint32 fourcc, const GstBuffer * codec_data); AtomInfo * build_mov_aac_extension (AtomTRAK * trak, const GstBuffer * codec_data); @@ -671,6 +673,8 @@ AtomInfo * build_jp2h_extension (AtomTRAK * trak, gint width, gint heig guint32 fourcc); AtomInfo * build_amr_extension (); AtomInfo * build_h263_extension (); +AtomInfo * build_gama_atom (gdouble gamma); +AtomInfo * build_SMI_atom (const GstBuffer *seqh); /* diff --git a/gst/qtmux/fourcc.h b/gst/qtmux/fourcc.h index 9b1fe65a36..29c12eebde 100644 --- a/gst/qtmux/fourcc.h +++ b/gst/qtmux/fourcc.h @@ -170,6 +170,11 @@ G_BEGIN_DECLS #define FOURCC_jpeg GST_MAKE_FOURCC('j','p','e','g') #define FOURCC_mjp2 GST_MAKE_FOURCC('m','j','p','2') #define FOURCC_jp2h GST_MAKE_FOURCC('j','p','2','h') +#define FOURCC_gama GST_MAKE_FOURCC('g','a','m','a') + +/* SVQ3 fourcc */ +#define FOURCC_SEQH GST_MAKE_FOURCC('S','E','Q','H') +#define FOURCC_SMI_ GST_MAKE_FOURCC('S','M','I',' ') /* Xiph fourcc */ #define FOURCC_XiTh GST_MAKE_FOURCC('X','i','T','h') diff --git a/gst/qtmux/gstqtmux.c b/gst/qtmux/gstqtmux.c index 6b650b204a..1838c6c144 100644 --- a/gst/qtmux/gstqtmux.c +++ b/gst/qtmux/gstqtmux.c @@ -1776,6 +1776,7 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) VisualSampleEntry entry = { 0, }; GstQTMuxFormat format; AtomInfo *ext_atom = NULL; + GList *ext_atom_list = NULL; gboolean sync = FALSE; int par_num, par_den; @@ -1859,11 +1860,14 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) break; } } else if (strcmp (mimetype, "video/x-h263") == 0) { + ext_atom = NULL; if (format == GST_QT_MUX_FORMAT_QT) entry.fourcc = FOURCC_h263; else entry.fourcc = FOURCC_s263; ext_atom = build_h263_extension (); + if (ext_atom != NULL) + ext_atom_list = g_list_prepend (ext_atom_list, ext_atom); } else if (strcmp (mimetype, "video/x-divx") == 0 || strcmp (mimetype, "video/mpeg") == 0) { gint version = 0; @@ -1880,6 +1884,8 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) ext_atom = build_esds_extension (qtpad->trak, ESDS_OBJECT_TYPE_MPEG4_P2, ESDS_STREAM_TYPE_VISUAL, codec_data); + if (ext_atom != NULL) + ext_atom_list = g_list_prepend (ext_atom_list, ext_atom); if (!codec_data) GST_WARNING_OBJECT (qtmux, "no codec_data for MPEG4 video; " "output might not play in Apple QuickTime (try global-headers?)"); @@ -1890,6 +1896,42 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) if (!codec_data) GST_WARNING_OBJECT (qtmux, "no codec_data in h264 caps"); ext_atom = build_codec_data_extension (FOURCC_avcC, 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; + const GValue *seqh_value; + gdouble gamma = 0; + + gst_structure_get_int (structure, "svqversion", &version); + if (version == 3) { + entry.fourcc = FOURCC_SVQ3; + entry.version = 3; + entry.depth = 32; + qtpad->is_out_of_order = TRUE; + + seqh_value = gst_structure_get_value (structure, "seqh"); + if (seqh_value) { + seqh = gst_value_get_buffer (seqh_value); + ext_atom = build_SMI_atom (seqh); + if (ext_atom) + ext_atom_list = g_list_prepend (ext_atom_list, ext_atom); + } + + /* we need to add the gamma anyway because quicktime might crash + * when it doesn't find it */ + if (!gst_structure_get_double (structure, "applied-gamma", &gamma)) { + /* it seems that using 0 here makes it ignored */ + gamma = 0.0; + } + ext_atom = build_gama_atom (gamma); + if (ext_atom) + ext_atom_list = g_list_prepend (ext_atom_list, ext_atom); + } else { + GST_WARNING_OBJECT (qtmux, "SVQ version %d not supported. Please file " + "a bug at http://bugzilla.gnome.org", version); + } } else if (strcmp (mimetype, "video/x-dv") == 0) { gint version = 0; gboolean pal = TRUE; @@ -1924,6 +1966,7 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) } else if (strcmp (mimetype, "image/x-j2c") == 0) { guint32 fourcc; + ext_atom = NULL; entry.fourcc = FOURCC_mjp2; sync = FALSE; if (!gst_structure_get_fourcc (structure, "fourcc", &fourcc) || @@ -1932,6 +1975,8 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) GST_DEBUG_OBJECT (qtmux, "missing or invalid fourcc in jp2 caps"); goto refuse_caps; } + if (ext_atom) + ext_atom_list = g_list_prepend (ext_atom_list, ext_atom); } else if (strcmp (mimetype, "video/x-qt-part") == 0) { guint32 fourcc; @@ -1955,7 +2000,7 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps) qtpad->fourcc = entry.fourcc; qtpad->sync = sync; atom_trak_set_video_type (qtpad->trak, qtmux->context, &entry, rate, - ext_atom); + ext_atom_list); gst_object_unref (qtmux); return TRUE; diff --git a/gst/qtmux/gstqtmuxmap.c b/gst/qtmux/gstqtmuxmap.c index 6587c45ab6..06171e9298 100644 --- a/gst/qtmux/gstqtmuxmap.c +++ b/gst/qtmux/gstqtmuxmap.c @@ -73,6 +73,11 @@ "divxversion = (int) 5, "\ COMMON_VIDEO_CAPS +#define SVQ_CAPS \ + "video/x-svq, " \ + "svqversion = (int) 3, " \ + COMMON_VIDEO_CAPS + #define COMMON_AUDIO_CAPS(c, r) \ "channels = (int) [ 1, " G_STRINGIFY (c) " ], " \ "rate = (int) [ 1, " G_STRINGIFY (r) " ]" @@ -141,6 +146,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = { MPEG4V_CAPS "; " H263_CAPS "; " H264_CAPS "; " + SVQ_CAPS "; " "video/x-dv, " "systemstream = (boolean) false, " COMMON_VIDEO_CAPS "; "