qtmux: support for SVQ3
authorThiago Santos <thiago.sousa.santos@collabora.co.uk>
Thu, 29 Oct 2009 11:36:02 +0000 (08:36 -0300)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Tue, 12 Apr 2011 19:32:13 +0000 (20:32 +0100)
Adds support for muxing SVQ3 content. Usually this format
has decoder info that must be passed in the 'seqh' field
in the caps. It is also good to add the gama atom to make
quicktime not crash.

Fixes #587922

gst/quicktime/atoms.c
gst/quicktime/atoms.h
gst/quicktime/fourcc.h
gst/quicktime/gstqtmux.c
gst/quicktime/gstqtmuxmap.c

index 57b9aa4..5d73ae2 100644 (file)
@@ -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;
+}
index 07efef5..87275d8 100644 (file)
@@ -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);
 
 
 /*
index 9b1fe65..29c12ee 100644 (file)
@@ -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')
index 6b650b2..1838c6c 100644 (file)
@@ -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;
index 6587c45..06171e9 100644 (file)
   "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 "; "