asfdemux: Add support for stereoscopic video metadata.
authorJan Schmidt <jan@centricular.com>
Wed, 10 Jun 2015 04:28:05 +0000 (14:28 +1000)
committerJan Schmidt <jan@centricular.com>
Thu, 11 Jun 2015 01:01:38 +0000 (11:01 +1000)
Add parsing of stereoscopic metadata, and place into the caps to
the decoder.

Fix parsing of Advanced Mutual Exclustion objects.

https://bugzilla.gnome.org/show_bug.cgi?id=711190

Based on a patch by HyeJin Choi <meeshel78@hotmail.com>

gst/asfdemux/Makefile.am
gst/asfdemux/gstasfdemux.c [changed mode: 0644->0755]
gst/asfdemux/gstasfdemux.h [changed mode: 0644->0755]

index a9c3eb6..ede3532 100644 (file)
@@ -3,6 +3,7 @@ plugin_LTLIBRARIES = libgstasf.la
 libgstasf_la_SOURCES = gstasfdemux.c gstasf.c asfheaders.c asfpacket.c gstrtpasfdepay.c gstrtspwms.c
 libgstasf_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
 libgstasf_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+                -lgstvideo-@GST_API_VERSION@ \
                -lgstriff-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ -lgstsdp-@GST_API_VERSION@ \
                -lgstrtp-@GST_API_VERSION@ -lgstaudio-@GST_API_VERSION@ -lgsttag-@GST_API_VERSION@ \
                $(GST_BASE_LIBS) $(GST_LIBS) \
old mode 100644 (file)
new mode 100755 (executable)
index ecbec39..61cd0c4
@@ -38,6 +38,7 @@
 #include <gst/riff/riff-media.h>
 #include <gst/tag/tag.h>
 #include <gst/gst-i18n-plugin.h>
+#include <gst/video/video.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -203,6 +204,10 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
     gst_structure_free (demux->global_metadata);
     demux->global_metadata = NULL;
   }
+  if (demux->mut_ex_streams) {
+    g_slist_free (demux->mut_ex_streams);
+    demux->mut_ex_streams = NULL;
+  }
 
   demux->state = GST_ASF_DEMUX_STATE_HEADER;
   g_free (demux->objpath);
@@ -260,6 +265,8 @@ gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
 
   demux->speed_packets = 1;
 
+  demux->asf_3D_mode = GST_ASF_3D_NONE;
+
   if (chain_reset) {
     GST_LOG_OBJECT (demux, "Restarting");
     gst_segment_init (&demux->segment, GST_FORMAT_TIME);
@@ -2570,6 +2577,81 @@ gst_asf_demux_add_video_stream (GstASFDemux * demux,
     }
   }
 
+  /* For a 3D video, set multiview information into the caps based on
+   * what was detected during object parsing */
+  if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
+    GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
+    GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
+    const gchar *mview_mode_str;
+
+    switch (demux->asf_3D_mode) {
+      case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
+        mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
+        break;
+      case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
+        mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
+        mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+        break;
+      case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
+        mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
+        break;
+      case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
+        mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
+        mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+        break;
+      case GST_ASF_3D_DUAL_STREAM:{
+        gboolean is_right_view = FALSE;
+        /* if Advanced_Mutual_Exclusion object exists, use it
+         * to figure out which is the left view (lower ID) */
+        if (demux->mut_ex_streams != NULL) {
+          guint length;
+          gint i;
+
+          length = g_slist_length (demux->mut_ex_streams);
+
+          for (i = 0; i < length; i++) {
+            gpointer v_s_id;
+
+            v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
+
+            GST_DEBUG_OBJECT (demux,
+                "has Mutual_Exclusion object. stream id in object is %d",
+                GPOINTER_TO_INT (v_s_id));
+
+            if (id > GPOINTER_TO_INT (v_s_id))
+              is_right_view = TRUE;
+          }
+        } else {
+          /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
+           * first video stream encountered has the lower ID */
+          if (demux->num_video_streams > 0) {
+            /* This is not the first video stream, assuming right eye view */
+            is_right_view = TRUE;
+          }
+        }
+        if (is_right_view)
+          mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
+        else
+          mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
+        break;
+      }
+      default:
+        break;
+    }
+
+    GST_INFO_OBJECT (demux,
+        "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
+        (guint) mv_flags);
+
+    mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
+    if (mview_mode_str != NULL) {
+      gst_caps_set_simple (caps,
+          "multiview-mode", G_TYPE_STRING, mview_mode_str,
+          "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
+          GST_FLAG_SET_MASK_EXACT, NULL);
+    }
+  }
+
   if (codec_name) {
     tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
     g_free (codec_name);
@@ -2875,6 +2957,7 @@ gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
 
 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING  0
 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY      1
+#define ASF_DEMUX_DATA_TYPE_BOOL                       2
 #define ASF_DEMUX_DATA_TYPE_DWORD           3
 
 static void
@@ -2943,7 +3026,20 @@ gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
 
   GstTagList *taglist;
   guint16 blockcount, i;
+  gboolean content3D = FALSE;
 
+  struct
+  {
+    const gchar *interleave_name;
+    GstASF3DMode interleaving_type;
+  } stereoscopic_layout_map[] = {
+    {
+    "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
+    "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
+    "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
+    "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
+    "DualStream", GST_ASF_3D_DUAL_STREAM}
+  };
   GST_INFO_OBJECT (demux, "object is an extended content description");
 
   taglist = gst_tag_list_new_empty ();
@@ -3047,6 +3143,26 @@ gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
               GST_DEBUG ("Setting metadata");
               g_value_init (&tag_value, G_TYPE_STRING);
               g_value_set_string (&tag_value, value_utf8);
+              /* If we found a stereoscopic marker, look for StereoscopicLayout
+               * metadata */
+              if (content3D) {
+                guint i;
+                if (strncmp ("StereoscopicLayout", name_utf8,
+                        strlen (name_utf8)) == 0) {
+                  for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
+                    if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
+                            value_utf8)) {
+                      demux->asf_3D_mode =
+                          stereoscopic_layout_map[i].interleaving_type;
+                      GST_INFO ("find interleave type %u", demux->asf_3D_mode);
+                    }
+                  }
+                }
+                GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
+              } else {
+                demux->asf_3D_mode = GST_ASF_3D_NONE;
+                GST_INFO_OBJECT (demux, "None 3d type");
+              }
             }
           } else if (value_utf8 == NULL) {
             GST_WARNING ("Failed to convert string value to UTF8, skipping");
@@ -3083,6 +3199,22 @@ gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
           g_value_set_uint (&tag_value, uint_val);
           break;
         }
+          /* Detect 3D */
+        case ASF_DEMUX_DATA_TYPE_BOOL:{
+          gboolean bool_val = GST_READ_UINT32_LE (value);
+
+          if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
+            if (bool_val) {
+              GST_INFO_OBJECT (demux, "This is 3D contents");
+              content3D = TRUE;
+            } else {
+              GST_INFO_OBJECT (demux, "This is not 3D contenst");
+              content3D = FALSE;
+            }
+          }
+
+          break;
+        }
         default:{
           GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
           break;
@@ -3629,7 +3761,6 @@ gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
 {
   ASFGuid guid;
   guint16 num, i;
-  guint8 *mes;
 
   if (size < 16 + 2 + (2 * 2))
     goto not_enough_data;
@@ -3646,16 +3777,15 @@ gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
     goto not_enough_data;
 
   /* read mutually exclusive stream numbers */
-  mes = g_new (guint8, num + 1);
   for (i = 0; i < num; ++i) {
-    mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
-    GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
-  }
+    guint8 mes;
+    mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
+    GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
 
-  /* add terminator so we can easily get the count or know when to stop */
-  mes[i] = (guint8) - 1;
+    demux->mut_ex_streams =
+        g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
+  }
 
-  demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
 
   return GST_FLOW_OK;
 
old mode 100644 (file)
new mode 100755 (executable)
index 6ef8c56..daad917
@@ -45,6 +45,7 @@ GST_DEBUG_CATEGORY_EXTERN (asfdemux_dbg);
 
 typedef struct _GstASFDemux GstASFDemux;
 typedef struct _GstASFDemuxClass GstASFDemuxClass;
+typedef enum _GstASF3DMode GstASF3DMode;
 
 typedef struct {
   guint32      packet;
@@ -57,6 +58,21 @@ typedef struct {
   guint16                 len;      /* save this so we can skip unknown IDs  */
 } AsfPayloadExtension;
 
+/**
+ * 3D Types for Media play
+ */
+enum _GstASF3DMode
+{
+  GST_ASF_3D_NONE = 0x00,
+
+  //added, interim format - half
+  GST_ASF_3D_SIDE_BY_SIDE_HALF_LR = 0x01,
+  GST_ASF_3D_SIDE_BY_SIDE_HALF_RL = 0x02,
+  GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR = 0x03,
+  GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL = 0x04,
+  GST_ASF_3D_DUAL_STREAM = 0x0D,                  /**< Full format*/
+};
+
 typedef struct
 {
   gboolean        valid;               /* TRUE if structure is valid/filled */
@@ -209,6 +225,9 @@ struct _GstASFDemux {
   AsfSimpleIndexEntry *sidx_entries;     /* packet number for each entry   */
   
   GSList              *other_streams;    /* remember streams that are in header but have unknown type */
+
+  /* parsing 3D */
+  GstASF3DMode asf_3D_mode;
 };
 
 struct _GstASFDemuxClass {