qtmux: Add support for muxing svmi atom for stereoscopic video information

https://bugzilla.gnome.org/show_bug.cgi?id=793120
diff --git a/gst/isomp4/atoms.c b/gst/isomp4/atoms.c
index eb90b79..4ca6927 100644
--- a/gst/isomp4/atoms.c
+++ b/gst/isomp4/atoms.c
@@ -729,6 +729,33 @@
 }
 
 static void
+atom_svmi_init (AtomSVMI * svmi)
+{
+  guint8 flags[3] = { 0, 0, 0 };
+
+  atom_full_init (&svmi->header, FOURCC_svmi, 0, 0, 0, flags);
+  svmi->stereoscopic_composition_type = 0x00;
+  svmi->is_left_first = FALSE;
+}
+
+AtomSVMI *
+atom_svmi_new (guint8 stereoscopic_composition_type, gboolean is_left_first)
+{
+  AtomSVMI *svmi = g_new0 (AtomSVMI, 1);
+
+  atom_svmi_init (svmi);
+  svmi->stereoscopic_composition_type = stereoscopic_composition_type;
+  svmi->is_left_first = is_left_first;
+  return svmi;
+}
+
+static void
+atom_svmi_free (AtomSVMI * svmi)
+{
+  g_free (svmi);
+}
+
+static void
 atom_stts_init (AtomSTTS * stts)
 {
   guint8 flags[3] = { 0, 0, 0 };
@@ -822,6 +849,7 @@
   atom_stsz_init (&stbl->stsz);
   atom_stsc_init (&stbl->stsc);
   stbl->ctts = NULL;
+  stbl->svmi = NULL;
 
   atom_co64_init (&stbl->stco64);
 }
@@ -838,6 +866,9 @@
   if (stbl->ctts) {
     atom_ctts_free (stbl->ctts);
   }
+  if (stbl->svmi) {
+    atom_svmi_free (stbl->svmi);
+  }
   atom_stco64_clear (&stbl->stco64);
 }
 
@@ -2293,6 +2324,25 @@
 }
 
 guint64
+atom_svmi_copy_data (AtomSVMI * svmi, guint8 ** buffer, guint64 * size,
+    guint64 * offset)
+{
+  guint64 original_offset = *offset;
+
+  if (!atom_full_copy_data (&svmi->header, buffer, size, offset)) {
+    return 0;
+  }
+
+  prop_copy_uint8 (svmi->stereoscopic_composition_type, buffer, size, offset);
+  prop_copy_uint8 (svmi->is_left_first ? 1 : 0, buffer, size, offset);
+  /* stereo-mono change count */
+  prop_copy_uint32 (0, buffer, size, offset);
+
+  atom_write_size (buffer, size, offset, original_offset);
+  return *offset - original_offset;
+}
+
+guint64
 atom_stco64_copy_data (AtomSTCO64 * stco64, guint8 ** buffer, guint64 * size,
     guint64 * offset)
 {
@@ -2454,6 +2504,11 @@
       return 0;
     }
   }
+  if (stbl->svmi) {
+    if (!atom_svmi_copy_data (stbl->svmi, buffer, size, offset)) {
+      return 0;
+    }
+  }
   if (!atom_stco64_copy_data (&stbl->stco64, buffer, size, offset)) {
     return 0;
   }
diff --git a/gst/isomp4/atoms.h b/gst/isomp4/atoms.h
index f73cb9f..27d2494 100644
--- a/gst/isomp4/atoms.h
+++ b/gst/isomp4/atoms.h
@@ -563,6 +563,14 @@
   gboolean do_pts;
 } AtomCTTS;
 
+typedef struct _AtomSVMI
+{
+  AtomFull header;
+
+  guint8 stereoscopic_composition_type;
+  gboolean is_left_first;
+} AtomSVMI;
+
 typedef struct _AtomSTBL
 {
   Atom header;
@@ -574,6 +582,8 @@
   AtomSTSZ stsz;
   /* NULL if not present */
   AtomCTTS *ctts;
+  /* NULL if not present */
+  AtomSVMI *svmi;
 
   AtomSTCO64 stco64;
 } AtomSTBL;
@@ -960,6 +970,9 @@
                                         guint64 *size, guint64* offset);
 guint64    atom_ctts_copy_data         (AtomCTTS *atom, guint8 **buffer,
                                         guint64 *size, guint64* offset);
+guint64    atom_svmi_copy_data         (AtomSVMI *atom, guint8 **buffer,
+                                        guint64 *size, guint64* offset);
+AtomSVMI * atom_svmi_new (guint8 stereoscopic_composition_type, gboolean is_left_first);
 guint64    atom_stco64_copy_data       (AtomSTCO64 *atom, guint8 **buffer,
                                         guint64 *size, guint64* offset);
 AtomMOOF*  atom_moof_new               (AtomsContext *context, guint32 sequence_number);
diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c
index 09357be..74e177c 100644
--- a/gst/isomp4/gstqtmux.c
+++ b/gst/isomp4/gstqtmux.c
@@ -5189,6 +5189,7 @@
   GList *ext_atom_list = NULL;
   gboolean sync = FALSE;
   int par_num, par_den;
+  const gchar *multiview_mode;
 
   /* does not go well to renegotiate stream mid-way, unless
    * the old caps are a subset of the new one (this means upstream
@@ -5258,6 +5259,36 @@
   GST_DEBUG_OBJECT (qtmux, "Rate of video track selected: %" G_GUINT32_FORMAT,
       rate);
 
+  multiview_mode = gst_structure_get_string (structure, "multiview-mode");
+  if (multiview_mode && !qtpad->trak->mdia.minf.stbl.svmi) {
+    GstVideoMultiviewMode mode;
+    GstVideoMultiviewFlags flags = 0;
+
+    mode = gst_video_multiview_mode_from_caps_string (multiview_mode);
+    gst_structure_get_flagset (structure, "multiview-flags", &flags, NULL);
+    switch (mode) {
+      case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
+        qtpad->trak->mdia.minf.stbl.svmi =
+            atom_svmi_new (0,
+            flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST);
+        break;
+      case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED:
+        qtpad->trak->mdia.minf.stbl.svmi =
+            atom_svmi_new (1,
+            flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST);
+        break;
+      case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
+        qtpad->trak->mdia.minf.stbl.svmi =
+            atom_svmi_new (2,
+            flags & GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST);
+        break;
+      default:
+        GST_DEBUG_OBJECT (qtmux, "Unsupported multiview-mode %s",
+            multiview_mode);
+        break;
+    }
+  }
+
   /* set common properties */
   entry.width = width;
   entry.height = height;