X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=subprojects%2Fgst-plugins-good%2Fgst%2Fisomp4%2Fqtdemux.c;h=ce45048d53337850de8bf00b1df78b2a20e19290;hb=44999c0bad391fde9faf1d9e322cdd8cc9c38b08;hp=b74f4ef150892544e62a8b202a429be0fb9bb4bd;hpb=f0b045a69bb0b36515b84e3b64df9dc30c8f1e1a;p=platform%2Fupstream%2Fgstreamer.git diff --git a/subprojects/gst-plugins-good/gst/isomp4/qtdemux.c b/subprojects/gst-plugins-good/gst/isomp4/qtdemux.c index b74f4ef..ce45048 100644 --- a/subprojects/gst-plugins-good/gst/isomp4/qtdemux.c +++ b/subprojects/gst-plugins-good/gst/isomp4/qtdemux.c @@ -79,7 +79,7 @@ #include #ifdef HAVE_ZLIB -# include +#include #endif /* max. size considered 'sane' for non-mdat atoms */ @@ -115,6 +115,34 @@ GST_DEBUG_CATEGORY (qtdemux_debug); typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo; typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo; +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION +typedef struct _QtDemuxSphericalMetadata QtDemuxSphericalMetadata; + +struct _QtDemuxSphericalMetadata +{ + gboolean is_spherical; + gboolean is_stitched; + char *stitching_software; + char *projection_type; + char *stereo_mode; + int source_count; + int init_view_heading; + int init_view_pitch; + int init_view_roll; + int timestamp; + int full_pano_width_pixels; + int full_pano_height_pixels; + int cropped_area_image_width; + int cropped_area_image_height; + int cropped_area_left; + int cropped_area_top; + QTDEMUX_AMBISONIC_TYPE ambisonic_type; + QTDEMUX_AMBISONIC_FORMAT ambisonic_format; + QTDEMUX_AMBISONIC_ORDER ambisonic_order; +}; + +#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */ + /* Macros for converting to/from timescale */ #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale)) #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND)) @@ -384,6 +412,10 @@ static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux, static void qtdemux_gst_structure_free (GstStructure * gststructure); static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard); +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION +static void gst_tag_register_spherical_tags (void); +#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */ + static void gst_qtdemux_class_init (GstQTDemuxClass * klass) { @@ -407,6 +439,10 @@ gst_qtdemux_class_init (GstQTDemuxClass * klass) gst_tag_register_musicbrainz_tags (); +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION + gst_tag_register_spherical_tags (); +#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */ + gst_element_class_add_static_pad_template (gstelement_class, &gst_qtdemux_sink_template); gst_element_class_add_static_pad_template (gstelement_class, @@ -447,6 +483,33 @@ gst_qtdemux_init (GstQTDemux * qtdemux) qtdemux->old_streams = g_ptr_array_new_with_free_func ((GDestroyNotify) gst_qtdemux_stream_unref); +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION + qtdemux->spherical_metadata = (QtDemuxSphericalMetadata *) + malloc (sizeof (QtDemuxSphericalMetadata)); + + if (qtdemux->spherical_metadata) { + qtdemux->spherical_metadata->is_spherical = FALSE; + qtdemux->spherical_metadata->is_stitched = FALSE; + qtdemux->spherical_metadata->stitching_software = NULL; + qtdemux->spherical_metadata->projection_type = NULL; + qtdemux->spherical_metadata->stereo_mode = NULL; + qtdemux->spherical_metadata->source_count = 0; + qtdemux->spherical_metadata->init_view_heading = 0; + qtdemux->spherical_metadata->init_view_pitch = 0; + qtdemux->spherical_metadata->init_view_roll = 0; + qtdemux->spherical_metadata->timestamp = 0; + qtdemux->spherical_metadata->full_pano_width_pixels = 0; + qtdemux->spherical_metadata->full_pano_height_pixels = 0; + qtdemux->spherical_metadata->cropped_area_image_width = 0; + qtdemux->spherical_metadata->cropped_area_image_height = 0; + qtdemux->spherical_metadata->cropped_area_left = 0; + qtdemux->spherical_metadata->cropped_area_top = 0; + qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_UNKNOWN; + qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_UNKNOWN; + qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_UNKNOWN; + } +#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */ + GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE); gst_qtdemux_reset (qtdemux, TRUE); @@ -467,6 +530,20 @@ gst_qtdemux_dispose (GObject * object) { GstQTDemux *qtdemux = GST_QTDEMUX (object); +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION + if (qtdemux->spherical_metadata) { + if (qtdemux->spherical_metadata->stitching_software) + free(qtdemux->spherical_metadata->stitching_software); + if (qtdemux->spherical_metadata->projection_type) + free(qtdemux->spherical_metadata->projection_type); + if (qtdemux->spherical_metadata->stereo_mode) + free(qtdemux->spherical_metadata->stereo_mode); + + free(qtdemux->spherical_metadata); + qtdemux->spherical_metadata = NULL; + } +#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */ + if (qtdemux->adapter) { g_object_unref (G_OBJECT (qtdemux->adapter)); qtdemux->adapter = NULL; @@ -791,6 +868,12 @@ gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream) stream->stream_tags); gst_pad_push_event (stream->pad, gst_event_new_tag (gst_tag_list_ref (stream->stream_tags))); +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION + /* post message qtdemux tag (for early recive application) */ + gst_element_post_message (GST_ELEMENT_CAST (qtdemux), + gst_message_new_tag (GST_OBJECT_CAST (qtdemux), + gst_tag_list_copy (stream->stream_tags))); +#endif } if (G_UNLIKELY (stream->send_global_tags)) { @@ -2683,6 +2766,475 @@ qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length) } } +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION +static void +_get_int_value_from_xml_string (GstQTDemux * qtdemux, + const char *xml_str, const char *param_name, int *value) +{ + char *value_start, *value_end, *endptr; + const short value_length_max = 12; + char init_view_ret[12]; + int value_length = 0; + int i = 0; + + value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL; + + if (!value_start) { + GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n", + param_name); + return; + } + + value_start += strlen (param_name); + while ((value_start[0] == ' ') || (value_start[0] == '\t')) + value_start++; + + value_end = strchr (value_start, '<'); + if (!value_end) { + GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n"); + return; + } + + value_length = value_end - value_start; + while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') + || (value_start[value_length - 1] == '\t'))) + value_length--; + + if (value_start[i] == '+' || value_start[i] == '-') + i++; + while (i < value_length) { + if (value_start[i] < '0' || value_start[i] > '9') { + GST_ERROR_OBJECT (qtdemux, + "error: incorrect value, integer was expected\n"); + return; + } + i++; + } + + if (value_length >= value_length_max || value_length < 1) { + GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n"); + return; + } + + strncpy (init_view_ret, value_start, value_length_max); + init_view_ret[value_length] = '\0'; + + *value = strtol (init_view_ret, &endptr, 10); + if (endptr == init_view_ret) { + GST_ERROR_OBJECT (qtdemux, "error: no digits were found\n"); + return; + } + + return; +} + +static void +_get_string_value_from_xml_string (GstQTDemux * qtdemux, + const char *xml_str, const char *param_name, char **value) +{ + char *value_start, *value_end; + const short value_length_max = 256; + int value_length = 0; + + value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL; + + if (!value_start) { + GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n", + param_name); + return; + } + + value_start += strlen (param_name); + while ((value_start[0] == ' ') || (value_start[0] == '\t')) + value_start++; + + value_end = strchr (value_start, '<'); + if (!value_end) { + GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n"); + return; + } + + value_length = value_end - value_start; + while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') + || (value_start[value_length - 1] == '\t'))) + value_length--; + + if (value_length >= value_length_max || value_length < 1) { + GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n"); + return; + } + + *value = strndup(value_start, value_length); + + return; +} + +static void +_get_bool_value_from_xml_string (GstQTDemux * qtdemux, + const char *xml_str, const char *param_name, gboolean * value) +{ + char *value_start, *value_end; + int value_length = 0; + + value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL; + + if (!value_start) { + GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n", + param_name); + return; + } + + value_start += strlen (param_name); + while ((value_start[0] == ' ') || (value_start[0] == '\t')) + value_start++; + + value_end = strchr (value_start, '<'); + if (!value_end) { + GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n"); + return; + } + + value_length = value_end - value_start; + while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') + || (value_start[value_length - 1] == '\t'))) + value_length--; + + if (value_length < 1) { + GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n"); + return; + } + + *value = g_strstr_len(value_start, value_length, "true") ? TRUE : FALSE; + + return; +} + +static void +_parse_spatial_video_metadata_from_xml_string (GstQTDemux * qtdemux, const char *xmlStr) +{ + const char is_spherical_str[] = ""; + const char is_stitched_str[] = ""; + const char stitching_software_str[] = ""; + const char projection_type_str[] = ""; + const char stereo_mode_str[] = ""; + const char source_count_str[] = ""; + const char init_view_heading_str[] = ""; + const char init_view_pitch_str[] = ""; + const char init_view_roll_str[] = ""; + const char timestamp_str[] = ""; + const char full_pano_width_str[] = ""; + const char full_pano_height_str[] = ""; + const char cropped_area_image_width_str[] = + ""; + const char cropped_area_image_height_str[] = + ""; + const char cropped_area_left_str[] = ""; + const char cropped_area_top_str[] = ""; + + QtDemuxSphericalMetadata * spherical_metadata = qtdemux->spherical_metadata; + + _get_bool_value_from_xml_string (qtdemux, xmlStr, is_spherical_str, + (gboolean *) & spherical_metadata->is_spherical); + _get_bool_value_from_xml_string (qtdemux, xmlStr, is_stitched_str, + (gboolean *) & spherical_metadata->is_stitched); + + if (spherical_metadata->is_spherical && spherical_metadata->is_stitched) { + _get_string_value_from_xml_string (qtdemux, xmlStr, + stitching_software_str, &spherical_metadata->stitching_software); + _get_string_value_from_xml_string (qtdemux, xmlStr, + projection_type_str, &spherical_metadata->projection_type); + _get_string_value_from_xml_string (qtdemux, xmlStr, stereo_mode_str, + &spherical_metadata->stereo_mode); + _get_int_value_from_xml_string (qtdemux, xmlStr, source_count_str, + &spherical_metadata->source_count); + _get_int_value_from_xml_string (qtdemux, xmlStr, + init_view_heading_str, &spherical_metadata->init_view_heading); + _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_pitch_str, + &spherical_metadata->init_view_pitch); + _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_roll_str, + &spherical_metadata->init_view_roll); + _get_int_value_from_xml_string (qtdemux, xmlStr, timestamp_str, + &spherical_metadata->timestamp); + _get_int_value_from_xml_string (qtdemux, xmlStr, full_pano_width_str, + &spherical_metadata->full_pano_width_pixels); + _get_int_value_from_xml_string (qtdemux, xmlStr, + full_pano_height_str, &spherical_metadata->full_pano_height_pixels); + _get_int_value_from_xml_string (qtdemux, xmlStr, + cropped_area_image_width_str, + &spherical_metadata->cropped_area_image_width); + _get_int_value_from_xml_string (qtdemux, xmlStr, + cropped_area_image_height_str, + &spherical_metadata->cropped_area_image_height); + _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_left_str, + &spherical_metadata->cropped_area_left); + _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_top_str, + &spherical_metadata->cropped_area_top); + } + + return; +} + +static void +gst_tag_register_spherical_tags (void) { + gst_tag_register ("is_spherical", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-spherical"), + _("Flag indicating if the video is a spherical video"), + NULL); + gst_tag_register ("is_stitched", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-stitched"), + _("Flag indicating if the video is stitched"), + NULL); + gst_tag_register ("stitching_software", GST_TAG_FLAG_META, + G_TYPE_STRING, + _("tag-stitching-software"), + _("Software used to stitch the spherical video"), + NULL); + gst_tag_register ("projection_type", GST_TAG_FLAG_META, + G_TYPE_STRING, + _("tag-projection-type"), + _("Projection type used in the video frames"), + NULL); + gst_tag_register ("stereo_mode", GST_TAG_FLAG_META, + G_TYPE_STRING, + _("tag-stereo-mode"), + _("Description of stereoscopic 3D layout"), + NULL); + gst_tag_register ("source_count", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-source-count"), + _("Number of cameras used to create the spherical video"), + NULL); + gst_tag_register ("init_view_heading", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-init-view-heading"), + _("The heading angle of the initial view in degrees"), + NULL); + gst_tag_register ("init_view_pitch", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-init-view-pitch"), + _("The pitch angle of the initial view in degrees"), + NULL); + gst_tag_register ("init_view_roll", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-init-view-roll"), + _("The roll angle of the initial view in degrees"), + NULL); + gst_tag_register ("timestamp", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-timestamp"), + _("Epoch timestamp of when the first frame in the video was recorded"), + NULL); + gst_tag_register ("full_pano_width_pixels", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-full-pano-width"), + _("Width of the encoded video frame in pixels"), + NULL); + gst_tag_register ("full_pano_height_pixels", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-full-pano-height"), + _("Height of the encoded video frame in pixels"), + NULL); + gst_tag_register ("cropped_area_image_width", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-cropped-area-image-width"), + _("Width of the video frame to display (e.g. cropping)"), + NULL); + gst_tag_register ("cropped_area_image_height", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-cropped-area-image-height"), + _("Height of the video frame to display (e.g. cropping)"), + NULL); + gst_tag_register ("cropped_area_left", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-cropped-area-left"), + _("Column where the left edge of the image was cropped from the" + " full sized panorama"), + NULL); + gst_tag_register ("cropped_area_top", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-cropped-area-top"), + _("Row where the top edge of the image was cropped from the" + " full sized panorama"), + NULL); + gst_tag_register ("ambisonic_type", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-ambisonic-type"), + _("Specifies the type of ambisonic audio represented"), + NULL); + gst_tag_register ("ambisonic_format", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-ambisonic-format"), + _("Specifies the ambisonic audio format"), + NULL); + gst_tag_register ("ambisonic_order", GST_TAG_FLAG_META, + G_TYPE_INT, + _("tag-ambisonic-order"), + _("Specifies the ambisonic audio channel order"), + NULL); + + return; +} + +static void +_send_spherical_metadata_msg_to_bus (GstQTDemux * qtdemux) +{ + GstTagList *taglist; + QtDemuxSphericalMetadata *spherical_metadata = qtdemux->spherical_metadata; + + GST_DEBUG_OBJECT (qtdemux, "is_spherical = %d", + spherical_metadata->is_spherical); + GST_DEBUG_OBJECT (qtdemux, "is_stitched = %d", + spherical_metadata->is_stitched); + GST_DEBUG_OBJECT (qtdemux, "stitching_software = %s", + spherical_metadata->stitching_software); + GST_DEBUG_OBJECT (qtdemux, "projection_type = %s", + spherical_metadata->projection_type); + GST_DEBUG_OBJECT (qtdemux, "stereo_mode = %s", + spherical_metadata->stereo_mode); + GST_DEBUG_OBJECT (qtdemux, "source_count %d", + spherical_metadata->source_count); + GST_DEBUG_OBJECT (qtdemux, "init_view_heading = %d", + spherical_metadata->init_view_heading); + GST_DEBUG_OBJECT (qtdemux, "init_view_pitch = %d", + spherical_metadata->init_view_pitch); + GST_DEBUG_OBJECT (qtdemux, "init_view_roll = %d", + spherical_metadata->init_view_roll); + GST_DEBUG_OBJECT (qtdemux, "timestamp = %d", spherical_metadata->timestamp); + GST_DEBUG_OBJECT (qtdemux, "full_pano_width_pixels = %d", + spherical_metadata->full_pano_width_pixels); + GST_DEBUG_OBJECT (qtdemux, "full_pano_height_pixels = %d", + spherical_metadata->full_pano_height_pixels); + GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_width = %d", + spherical_metadata->cropped_area_image_width); + GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_height = %d", + spherical_metadata->cropped_area_image_height); + GST_DEBUG_OBJECT (qtdemux, "cropped_area_left = %d", + spherical_metadata->cropped_area_left); + GST_DEBUG_OBJECT (qtdemux, "cropped_area_top = %d", + spherical_metadata->cropped_area_top); + GST_DEBUG_OBJECT (qtdemux, "ambisonic_type = %d", + spherical_metadata->ambisonic_type); + GST_DEBUG_OBJECT (qtdemux, "ambisonic_order = %d", + spherical_metadata->ambisonic_order); + GST_DEBUG_OBJECT (qtdemux, "ambisonic_format = %d", + spherical_metadata->ambisonic_format); + + taglist = gst_tag_list_new_empty (); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, + "is_spherical", spherical_metadata->is_spherical, + "is_stitched", spherical_metadata->is_stitched, + "source_count", spherical_metadata->source_count, + "init_view_heading", spherical_metadata->init_view_heading, + "init_view_pitch", spherical_metadata->init_view_pitch, + "init_view_roll", spherical_metadata->init_view_roll, + "timestamp", spherical_metadata->timestamp, + "full_pano_width_pixels", spherical_metadata->full_pano_width_pixels, + "full_pano_height_pixels", spherical_metadata->full_pano_height_pixels, + "cropped_area_image_width", spherical_metadata->cropped_area_image_width, + "cropped_area_image_height", spherical_metadata->cropped_area_image_height, + "cropped_area_left", spherical_metadata->cropped_area_left, + "cropped_area_top", spherical_metadata->cropped_area_top, + "ambisonic_type", spherical_metadata->ambisonic_type, + "ambisonic_format", spherical_metadata->ambisonic_format, + "ambisonic_order", spherical_metadata->ambisonic_order, + NULL); + + if (spherical_metadata->stitching_software) + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, + "stitching_software", spherical_metadata->stitching_software, + NULL); + if (spherical_metadata->projection_type) + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, + "projection_type", spherical_metadata->projection_type, + NULL); + if (spherical_metadata->stereo_mode) + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, + "stereo_mode", spherical_metadata->stereo_mode, + NULL); + + gst_element_post_message (GST_ELEMENT_CAST (qtdemux), + gst_message_new_tag (GST_OBJECT_CAST (qtdemux), + gst_tag_list_copy (taglist))); + + gst_tag_list_unref(taglist); + + return; +} + +static void +qtdemux_parse_SA3D (GstQTDemux * qtdemux, const guint8 * buffer, gint length) +{ + guint offset = 0; + + guint8 version = 0; + guint8 ambisonic_type = 0; + guint32 ambisonic_order = 0; + guint8 ambisonic_channel_ordering = 0; + guint8 ambisonic_normalization = 0; + guint32 num_channels = 0; + guint32 channel_map[49] = { 0 }; /* Up to 6th order */ + + int i; + + GST_DEBUG_OBJECT (qtdemux, "qtdemux_parse_SA3D"); + + qtdemux->header_size += length; + offset = (QT_UINT32 (buffer) == 0) ? 16 : 8; + + if (length <= offset + 16) { + GST_DEBUG_OBJECT (qtdemux, "SA3D atom is too short, skipping"); + return; + } + + version = QT_UINT8 (buffer + offset); + ambisonic_type = QT_UINT8 (buffer + offset + 1); + ambisonic_order = QT_UINT32 (buffer + offset + 2); + ambisonic_channel_ordering = QT_UINT8 (buffer + offset + 6); + ambisonic_normalization = QT_UINT8 (buffer + offset + 7); + num_channels = QT_UINT32 (buffer + offset + 8); + for (i = 0; i < num_channels; ++i) + channel_map[i] = QT_UINT32 (buffer + offset + 12 + i * 4); + + GST_DEBUG_OBJECT (qtdemux, "version: %d", version); + GST_DEBUG_OBJECT (qtdemux, "ambisonic_type: %d", ambisonic_type); + GST_DEBUG_OBJECT (qtdemux, "ambisonic_order: %d", ambisonic_order); + GST_DEBUG_OBJECT (qtdemux, "ambisonic_channel_ordering: %d", + ambisonic_channel_ordering); + GST_DEBUG_OBJECT (qtdemux, "ambisonic_normalization: %d", + ambisonic_normalization); + GST_DEBUG_OBJECT (qtdemux, "num_channels: %d", num_channels); + for (i = 0; i < num_channels; ++i) + GST_DEBUG_OBJECT (qtdemux, "channel_map: %d", channel_map[i]); + + if (version == RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) { + if (ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC) + qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_PERIPHONIC; + + if (ambisonic_order == RFC_AMBISONIC_ORDER_FOA) { + if (num_channels == 4) { + qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_FOA; + + if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) + && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) + && (channel_map[0] == 0) && (channel_map[1] == 1) + && (channel_map[2] == 2) && (channel_map[3] == 3)) + qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMBIX; + + if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) + && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) + && (channel_map[0] == 0) && (channel_map[1] == 3) + && (channel_map[2] == 1) && (channel_map[3] == 2)) + qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMB; + } + } + } + + return; +} +#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */ + static void qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux, QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, @@ -2931,6 +3483,13 @@ qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length) 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4 }; +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION + static const guint8 spherical_uuid[] = { + 0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93, + 0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd + }; +#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */ + guint offset; /* counts as header data */ @@ -2943,6 +3502,21 @@ qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length) return; } +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION + if (memcmp (buffer + offset, spherical_uuid, 16) == 0) { + const char *contents; + + GST_DEBUG_OBJECT (qtdemux, "spherical uuid was found"); + contents = (char *) (buffer + offset + 16); + GST_DEBUG_OBJECT (qtdemux, "contents: %s\n", contents); + + if (qtdemux->spherical_metadata) + _parse_spatial_video_metadata_from_xml_string (qtdemux, contents); + + return; + } +#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */ + if (memcmp (buffer + offset, xmp_uuid, 16) == 0) { GstBuffer *buf; GstTagList *taglist; @@ -4654,6 +5228,10 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) beach: if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) { /* digested all data, show what we have */ +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION + if (qtdemux->spherical_metadata) + _send_spherical_metadata_msg_to_bus (qtdemux); +#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */ qtdemux_prepare_streams (qtdemux); QTDEMUX_EXPOSE_LOCK (qtdemux); ret = qtdemux_expose_streams (qtdemux); @@ -8259,6 +8837,13 @@ qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer, qtdemux_parse_container (qtdemux, node, buffer + 36, end); break; } +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION + case FOURCC_SA3D: + { + qtdemux_parse_SA3D (qtdemux, buffer, end - buffer); + break; + } +#endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */ default: if (!strcmp (type->name, "unknown")) GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4); @@ -8601,9 +9186,16 @@ gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream) GST_TIME_FORMAT, duration, first_duration, n_samples - 1, GST_TIME_ARGS (avg_duration)); +#ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION + gst_video_guess_framerate (avg_duration, + &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d); + if (CUR_STREAM (stream)->fps_d == 0) + fps_available = FALSE; +#else fps_available = gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d); +#endif GST_DEBUG_OBJECT (qtdemux, "Calculating framerate, timescale %u gave fps_n %d fps_d %d", @@ -10864,6 +11456,22 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) stream = _create_stream (qtdemux, track_id); stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags); +#ifdef TIZEN_FEATURE_QTDEMUX_DURATION + if (!gst_byte_reader_skip (&tkhd, 4)) + goto corrupt_file; + + if (tkhd_version == 1) { + if (!gst_byte_reader_get_uint64_be (&tkhd, &stream->tkhd_duration)) + goto corrupt_file; + } else { + guint32 dur = 0; + if (!gst_byte_reader_get_uint32_be (&tkhd, &dur)) + goto corrupt_file; + stream->tkhd_duration = dur; + } + GST_INFO_OBJECT (qtdemux, "tkhd duration: %" G_GUINT64_FORMAT, + stream->tkhd_duration); +#endif /* need defaults for fragments */ qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy); @@ -10988,7 +11596,11 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) guint32 matrix[9]; /* version 1 uses some 64-bit ints */ +#ifdef TIZEN_FEATURE_QTDEMUX_DURATION + if (!gst_byte_reader_skip (&tkhd, 16)) +#else if (!gst_byte_reader_skip (&tkhd, 20 + value_size)) +#endif goto corrupt_file; if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd")) @@ -13260,6 +13872,9 @@ static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux) { GstFlowReturn ret = GST_FLOW_OK; +#ifdef TIZEN_FEATURE_QTDEMUX_DURATION + guint64 tkhd_max_duration = 0; +#endif gint i; GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux)); @@ -13281,6 +13896,10 @@ qtdemux_prepare_streams (GstQTDemux * qtdemux) } else { /* discard any stray moof */ qtdemux->moof_offset = 0; +#ifdef TIZEN_FEATURE_QTDEMUX_DURATION + if (tkhd_max_duration < stream->tkhd_duration) + tkhd_max_duration = stream->tkhd_duration; +#endif } /* prepare braking */ @@ -13312,6 +13931,15 @@ qtdemux_prepare_streams (GstQTDemux * qtdemux) } } +#ifdef TIZEN_FEATURE_QTDEMUX_DURATION + if (!qtdemux->fragmented && (qtdemux->duration > tkhd_max_duration)) { + GST_INFO_OBJECT (qtdemux, + "Update duration: %" G_GUINT64_FORMAT " -> %" G_GUINT64_FORMAT, + qtdemux->duration, tkhd_max_duration); + qtdemux->duration = tkhd_max_duration; + } +#endif + return ret; }