From 6d0ee6c7820edba169d41119fa8b4eca1b4c3629 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 10 Jun 2015 14:28:05 +1000 Subject: [PATCH] asfdemux: Add support for stereoscopic video metadata. 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 --- gst/asfdemux/Makefile.am | 1 + gst/asfdemux/gstasfdemux.c | 146 +++++++++++++++++++++++++++++++++++-- gst/asfdemux/gstasfdemux.h | 19 +++++ 3 files changed, 158 insertions(+), 8 deletions(-) mode change 100644 => 100755 gst/asfdemux/gstasfdemux.c mode change 100644 => 100755 gst/asfdemux/gstasfdemux.h diff --git a/gst/asfdemux/Makefile.am b/gst/asfdemux/Makefile.am index a9c3eb64..ede3532a 100644 --- a/gst/asfdemux/Makefile.am +++ b/gst/asfdemux/Makefile.am @@ -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) \ diff --git a/gst/asfdemux/gstasfdemux.c b/gst/asfdemux/gstasfdemux.c old mode 100644 new mode 100755 index ecbec39c..61cd0c42 --- a/gst/asfdemux/gstasfdemux.c +++ b/gst/asfdemux/gstasfdemux.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -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; diff --git a/gst/asfdemux/gstasfdemux.h b/gst/asfdemux/gstasfdemux.h old mode 100644 new mode 100755 index 6ef8c560..daad917a --- a/gst/asfdemux/gstasfdemux.h +++ b/gst/asfdemux/gstasfdemux.h @@ -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 { -- 2.34.1