matroska: Implement basic stereoscopic video support
authorJan Schmidt <jan@centricular.com>
Wed, 10 Jun 2015 14:22:54 +0000 (00:22 +1000)
committerJan Schmidt <jan@centricular.com>
Thu, 11 Jun 2015 02:11:42 +0000 (12:11 +1000)
Implement support for the packed video formats WebM
uses, not all the values that Matroska might use.

In practice, it's really hard to find any samples in the
wild of any.

Supported in both the muxer and demuxer.

gst/matroska/matroska-demux.c
gst/matroska/matroska-ids.c
gst/matroska/matroska-ids.h
gst/matroska/matroska-mux.c

index 0ee13b378397642a0e3f46907d59a5dbadc39bb0..6ad4822ab7c42ff59b3b648e2ac553eb3ad0838f 100644 (file)
@@ -731,12 +731,61 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
               g_free (data);
               break;
             }
+            case GST_MATROSKA_ID_VIDEOSTEREOMODE:
+            {
+              guint64 num;
+
+              if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
+                break;
+
+              GST_DEBUG_OBJECT (demux, "StereoMode: %" G_GUINT64_FORMAT, num);
+
+              switch (num) {
+                case GST_MATROSKA_STEREO_MODE_SBS_RL:
+                  videocontext->multiview_flags =
+                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+                  /* fall through */
+                case GST_MATROSKA_STEREO_MODE_SBS_LR:
+                  videocontext->multiview_mode =
+                      GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
+                  break;
+                case GST_MATROSKA_STEREO_MODE_TB_RL:
+                  videocontext->multiview_flags =
+                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+                  /* fall through */
+                case GST_MATROSKA_STEREO_MODE_TB_LR:
+                  videocontext->multiview_mode =
+                      GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
+                  break;
+                case GST_MATROSKA_STEREO_MODE_CHECKER_RL:
+                  videocontext->multiview_flags =
+                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+                  /* fall through */
+                case GST_MATROSKA_STEREO_MODE_CHECKER_LR:
+                  videocontext->multiview_mode =
+                      GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD;
+                  break;
+                case GST_MATROSKA_STEREO_MODE_FBF_RL:
+                  videocontext->multiview_flags =
+                      GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+                  /* fall through */
+                case GST_MATROSKA_STEREO_MODE_FBF_LR:
+                  videocontext->multiview_mode =
+                      GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
+                  /* FIXME: In frame-by-frame mode, left/right frame buffers are
+                   * laced within one block, and we'll need to apply FIRST_IN_BUNDLE
+                   * accordingly. See http://www.matroska.org/technical/specs/index.html#StereoMode */
+                  GST_FIXME_OBJECT (demux,
+                      "Frame-by-frame stereoscopic mode not fully implemented");
+                  break;
+              }
+              break;
+            }
 
             default:
               GST_WARNING_OBJECT (demux,
                   "Unknown TrackVideo subelement 0x%x - ignoring", id);
               /* fall through */
-            case GST_MATROSKA_ID_VIDEOSTEREOMODE:
             case GST_MATROSKA_ID_VIDEODISPLAYUNIT:
             case GST_MATROSKA_ID_VIDEOPIXELCROPBOTTOM:
             case GST_MATROSKA_ID_VIDEOPIXELCROPTOP:
index 65af1cc4c543f0fb540b74f79434670e2992449a..52e5dc30d1778f1eaff33a22d50b49d2ac536ebd 100644 (file)
@@ -59,6 +59,9 @@ gst_matroska_track_init_video_context (GstMatroskaTrackContext ** p_context)
   video_context->fourcc = 0;
   video_context->default_fps = 0.0;
   video_context->earliest_time = GST_CLOCK_TIME_NONE;
+  video_context->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
+  video_context->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
+
   return TRUE;
 }
 
index 41315a052b76fb7b2fb721e85ad8a5aaa86f5029..661a4a1b0f3323b4117cdf424e67d3e1ace74d0c 100644 (file)
@@ -23,6 +23,7 @@
 #define __GST_MATROSKA_IDS_H__
 
 #include <gst/gst.h>
+#include <gst/video/video-info.h>
 
 #include "ebml-ids.h"
 
@@ -489,6 +490,16 @@ typedef enum {
   GST_MATROSKA_VIDEOTRACK_INTERLACED = (GST_MATROSKA_TRACK_SHIFT<<0)
 } GstMatroskaVideoTrackFlags;
 
+typedef enum {
+  GST_MATROSKA_STEREO_MODE_SBS_LR      = 0x1,
+  GST_MATROSKA_STEREO_MODE_TB_RL       = 0x2,
+  GST_MATROSKA_STEREO_MODE_TB_LR       = 0x3,
+  GST_MATROSKA_STEREO_MODE_CHECKER_RL  = 0x4,
+  GST_MATROSKA_STEREO_MODE_CHECKER_LR  = 0x5,
+  GST_MATROSKA_STEREO_MODE_SBS_RL      = 0x9,
+  GST_MATROSKA_STEREO_MODE_FBF_LR      = 0xD,
+  GST_MATROSKA_STEREO_MODE_FBF_RL      = 0xE
+} GstMatroskaStereoMode;
 
 typedef struct _GstMatroskaTrackContext GstMatroskaTrackContext;
 
@@ -571,6 +582,9 @@ typedef struct _GstMatroskaTrackVideoContext {
   GstMatroskaAspectRatioMode asr_mode;
   guint32       fourcc;
 
+  GstVideoMultiviewMode multiview_mode;
+  GstVideoMultiviewFlags multiview_flags;
+
   /* QoS */
   GstClockTime  earliest_time;
 
index 0e28ed32143aea37cc23805809056d05620f141b..f555f0df95ce88250ce8d115e9434e3547cae0d8 100644 (file)
@@ -929,7 +929,7 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
   GstMatroskaPad *collect_pad;
   GstStructure *structure;
   const gchar *mimetype;
-  const gchar *interlace_mode;
+  const gchar *interlace_mode, *s;
   const GValue *value = NULL;
   GstBuffer *codec_buf = NULL;
   gint width, height, pixel_width, pixel_height;
@@ -1002,6 +1002,14 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
     videocontext->display_height = 0;
   }
 
+  /* Collect stereoscopic info, if any */
+  if ((s = gst_structure_get_string (structure, "multiview-mode")))
+    videocontext->multiview_mode =
+        gst_video_multiview_mode_from_caps_string (s);
+  gst_structure_get_flagset (structure, "multiview-flags",
+      &videocontext->multiview_flags, NULL);
+
+
 skip_details:
 
   videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
@@ -2432,6 +2440,53 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux,
         gst_ebml_write_binary (ebml, GST_MATROSKA_ID_VIDEOCOLOURSPACE,
             (gpointer) & fcc_le, 4);
       }
+      if (videocontext->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
+        guint64 stereo_mode = 0;
+
+        switch (videocontext->multiview_mode) {
+          case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
+            if (videocontext->multiview_flags &
+                GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
+              stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_RL;
+            else
+              stereo_mode = GST_MATROSKA_STEREO_MODE_SBS_LR;
+            break;
+          case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
+            if (videocontext->multiview_flags &
+                GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
+              stereo_mode = GST_MATROSKA_STEREO_MODE_TB_RL;
+            else
+              stereo_mode = GST_MATROSKA_STEREO_MODE_TB_LR;
+            break;
+          case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
+            if (videocontext->multiview_flags &
+                GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
+              stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_RL;
+            else
+              stereo_mode = GST_MATROSKA_STEREO_MODE_CHECKER_LR;
+            break;
+          case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
+            if (videocontext->multiview_flags &
+                GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST)
+              stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_RL;
+            else
+              stereo_mode = GST_MATROSKA_STEREO_MODE_FBF_LR;
+            /* FIXME: In frame-by-frame mode, left/right frame buffers need to be
+             * laced within one block. See http://www.matroska.org/technical/specs/index.html#StereoMode */
+            GST_FIXME_OBJECT (mux,
+                "Frame-by-frame stereoscopic mode not fully implemented");
+            break;
+          default:
+            GST_WARNING_OBJECT (mux,
+                "Multiview mode %d not supported in Matroska/WebM",
+                videocontext->multiview_mode);
+            break;
+        }
+
+        if (stereo_mode != 0)
+          gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOSTEREOMODE,
+              stereo_mode);
+      }
       gst_ebml_write_master_finish (ebml, master);
 
       break;