Add Spherical Video Metadata V2 support 42/144642/4
authorMykola Alieksieiev <m.alieksieie@samsung.com>
Thu, 17 Aug 2017 09:32:07 +0000 (12:32 +0300)
committerhj kim <backto.kim@samsung.com>
Wed, 30 Aug 2017 22:38:37 +0000 (22:38 +0000)
Change-Id: I215cce72ac37719c8fbb62da5953e498452ded1f
Signed-off-by: Mykola Alieksieiev <m.alieksieie@samsung.com>
formats/ffmpeg/mm_file_formats.c
include/mm_file.h
include/mm_file_formats.h
mm_file.c
tests/mm_file_test.c
utils/mm_file_util_tag.c

index d5998f7..18282d6 100755 (executable)
@@ -145,6 +145,7 @@ static int _CleanupFrameContext(MMFileFormatContext *formatContext, bool clean_a
                if (formatContext->stereoMode)                  mmfile_free(formatContext->stereoMode);
                if (formatContext->stitchingSoftware)   mmfile_free(formatContext->stitchingSoftware);
                if (formatContext->projectionType)              mmfile_free(formatContext->projectionType);
+               if (formatContext->metadataSourceV2)    mmfile_free(formatContext->metadataSourceV2);
 
                if (clean_all)  /*syncLyrics has to be freed in mm_file_destroy_tag_attrs() except abnormal status */
                        if (formatContext->syncLyrics)                  mm_file_free_synclyrics_list(formatContext->syncLyrics);
index 7afa290..b4686c3 100755 (executable)
@@ -168,7 +168,18 @@ typedef enum {
 #define        MM_FILE_TAG_AMBISONIC_TYPE                      "tag-ambisonic-type"            /**< Ambisonics type in User Data Information*/
 #define        MM_FILE_TAG_AMBISONIC_FORMAT            "tag-ambisonic-format"          /**< Ambisonics format in User Data Information*/
 #define        MM_FILE_TAG_AMBISONIC_ORDER                     "tag-ambisonic-order"           /**< Ambisonics order in User Data Information*/
-
+#define        MM_FILE_TAG_SPHERICAL_V2_STEREO_MODE            "stereo-mode-v2"                                        /**< Stereo frame layout*/
+#define        MM_FILE_TAG_SPHERICAL_V2_METADATA_SOURCE        "metadata-source-v2"                            /**< Tool used to create the Spherical Video Metadata V2*/
+#define        MM_FILE_TAG_SPHERICAL_V2_PROJ_TYPE                      "proj-type-v2"                                          /**< Projection type*/
+#define        MM_FILE_TAG_SPHERICAL_V2_POSE_YAW                       "pose-yaw-degrees-v2"                           /**< Counter-clockwise rotation in degrees around the up vector*/
+#define        MM_FILE_TAG_SPHERICAL_V2_POSE_PITCH                     "pose-pitch-degrees-v2"                         /**< Counter-clockwise rotation in degrees around the right vector post yaw transform*/
+#define        MM_FILE_TAG_SPHERICAL_V2_POSE_ROLL                      "pose-roll-degrees-v2"                          /**< Clockwise-rotation in degrees around the forward vector post yaw and pitch transform*/
+#define        MM_FILE_TAG_SPHERICAL_V2_CBMP_LAYOUT            "cbmp-layout-v2"                                        /**< Layout of cube faces for the Cubemap Projection*/
+#define        MM_FILE_TAG_SPHERICAL_V2_CBMP_PADDING           "cbmp-padding-v2"                                       /**< Number of pixels to pad from the edge of each cube face for the Cubemap Projection*/
+#define        MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_TOP        "equi-projection-bounds-top-v2"         /**< Amount from the top of the frame to crop*/
+#define        MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_BOTTOM     "equi-projection-bounds-bottom-v2"      /**< Amount from the bottom of the frame to crop*/
+#define        MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_LEFT       "equi-projection-bounds-left-v2"        /**< Amount from the left of the frame to crop*/
+#define        MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_RIGHT      "equi-projection-bounds-right-v2"       /**< Amount from the right of the frame to crop*/
 
 /**
   * This function is to create tag attribute from given media file path.<BR>
index 9efc3ab..257ff9b 100755 (executable)
@@ -170,6 +170,18 @@ struct _MMFileFormatContext {
        MMFILE_AMBISONIC_TYPE ambisonicType;
        MMFILE_AMBISONIC_FORMAT ambisonicFormat;
        MMFILE_AMBISONIC_ORDER ambisonicOrder;
+       unsigned stereoModeV2;
+       char *metadataSourceV2;
+       unsigned projTypeV2;
+       unsigned poseYawV2;
+       unsigned posePitchV2;
+       unsigned poseRollV2;
+       unsigned cbmpLayoutV2;
+       unsigned cbmpPaddingV2;
+       unsigned equiBoundsTopV2;
+       unsigned equiBoundsBottomV2;
+       unsigned equiBoundsLeftV2;
+       unsigned equiBoundsRightV2;
 
        /* private data */
        void *privateFormatData;
index 98812e3..4170f4c 100755 (executable)
--- a/mm_file.c
+++ b/mm_file.c
@@ -143,6 +143,18 @@ static mmf_attrs_construct_info_t g_tag_attrs[] = {
        {(char *)"tag-ambisonic-type",                          MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
        {(char *)"tag-ambisonic-format",                        MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
        {(char *)"tag-ambisonic-order",                         MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"stereo-mode-v2",                                              MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"metadata-source-v2",                                  MMF_VALUE_TYPE_STRING,  MM_ATTRS_FLAG_RW, (void *)NULL},
+       {(char *)"proj-type-v2",                                                MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"pose-yaw-degrees-v2",                                 MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"pose-pitch-degrees-v2",                               MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"pose-roll-degrees-v2",                                MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"cbmp-layout-v2",                                              MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"cbmp-padding-v2",                                             MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"equi-projection-bounds-top-v2",               MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"equi-projection-bounds-bottom-v2",    MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"equi-projection-bounds-left-v2",              MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
+       {(char *)"equi-projection-bounds-right-v2",             MMF_VALUE_TYPE_INT,             MM_ATTRS_FLAG_RW, (void *)0},
 };
 
 static mmf_attrs_construct_info_t g_content_attrs[] = {
@@ -346,6 +358,19 @@ _info_set_attr_media(mmf_attrs_t *attrs, MMFileFormatContext *formatContext)
                mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_AMBISONIC_FORMAT, formatContext->ambisonicFormat);
                mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_AMBISONIC_ORDER, formatContext->ambisonicOrder);
 
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_STEREO_MODE, formatContext->stereoModeV2);
+               if (formatContext->metadataSourceV2)    mm_attrs_set_string_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_METADATA_SOURCE, formatContext->metadataSourceV2);
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_PROJ_TYPE, formatContext->projTypeV2);
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_POSE_YAW, formatContext->poseYawV2);
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_POSE_PITCH, formatContext->posePitchV2);
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_POSE_ROLL, formatContext->poseRollV2);
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_CBMP_LAYOUT, formatContext->cbmpLayoutV2);
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_CBMP_PADDING, formatContext->cbmpPaddingV2);
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_TOP, formatContext->equiBoundsTopV2);
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_BOTTOM, formatContext->equiBoundsBottomV2);
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_LEFT, formatContext->equiBoundsLeftV2);
+               mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_RIGHT, formatContext->equiBoundsRightV2);
+
                if ((formatContext->syncLyricsNum > 0) && (formatContext->syncLyrics))
                        mm_attrs_set_data_by_name(hattrs, MM_FILE_TAG_SYNCLYRICS, formatContext->syncLyrics, formatContext->syncLyricsNum);
 
index 0195355..8dc8001 100755 (executable)
@@ -100,6 +100,18 @@ typedef struct _TagContext {
        mmfile_value_t ambisonic_type;
        mmfile_value_t ambisonic_format;
        mmfile_value_t ambisonic_order;
+       mmfile_value_t stereo_mode_v2;
+       mmfile_value_t proj_type_v2;
+       mmfile_value_t metadata_source_v2;      /*string */
+       mmfile_value_t pose_yaw_degrees_v2;
+       mmfile_value_t pose_pitch_degrees_v2;
+       mmfile_value_t pose_roll_degrees_v2;
+       mmfile_value_t cbmp_layout_v2;
+       mmfile_value_t cbmp_padding_v2;
+       mmfile_value_t equi_projection_bounds_top_v2;
+       mmfile_value_t equi_projection_bounds_bottom_v2;
+       mmfile_value_t equi_projection_bounds_left_v2;
+       mmfile_value_t equi_projection_bounds_right_v2;
 
 } TagContext_t;
 
@@ -390,6 +402,18 @@ static int mmfile_get_file_infomation(void *data, void *user_data, bool file_tes
                                                MM_FILE_TAG_AMBISONIC_TYPE, &ctag.ambisonic_type.value.i_val,
                                                MM_FILE_TAG_AMBISONIC_FORMAT, &ctag.ambisonic_format.value.i_val,
                                                MM_FILE_TAG_AMBISONIC_ORDER, &ctag.ambisonic_order.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_STEREO_MODE, &ctag.stereo_mode_v2.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_METADATA_SOURCE, &ctag.metadata_source_v2.value.s_val, &ctag.metadata_source_v2.len,
+                                               MM_FILE_TAG_SPHERICAL_V2_PROJ_TYPE, &ctag.proj_type_v2.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_POSE_YAW, &ctag.pose_yaw_degrees_v2.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_POSE_PITCH, &ctag.pose_pitch_degrees_v2.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_POSE_ROLL, &ctag.pose_roll_degrees_v2.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_CBMP_LAYOUT, &ctag.cbmp_layout_v2.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_CBMP_PADDING, &ctag.cbmp_padding_v2.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_TOP, &ctag.equi_projection_bounds_top_v2.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_BOTTOM, &ctag.equi_projection_bounds_bottom_v2.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_LEFT, &ctag.equi_projection_bounds_left_v2.value.i_val,
+                                               MM_FILE_TAG_SPHERICAL_V2_EQUI_BOUNDS_RIGHT, &ctag.equi_projection_bounds_right_v2.value.i_val,
                                                NULL);
                if (ret != FILEINFO_ERROR_NONE &&  err_attr_name) {
                        printf("failed to get %s attrs\n", err_attr_name);
@@ -458,6 +482,22 @@ static int mmfile_get_file_infomation(void *data, void *user_data, bool file_tes
                        printf("# ambisonic_order: [%d]\n", ctag.ambisonic_order.value.i_val);
                }
 
+               printf("# stereo_mode_v2: [%d]\n", ctag.stereo_mode_v2.value.i_val);
+
+               if (ctag.proj_type_v2.value.i_val >= 0) {
+                       printf("# proj_type_v2: [%d]\n", ctag.proj_type_v2.value.i_val);
+                       printf("# metadata_source_v2: [%s]\n", ctag.metadata_source_v2.value.s_val);
+                       printf("# pose_yaw_degrees_v2: [%d]\n", ctag.pose_yaw_degrees_v2.value.i_val);
+                       printf("# pose_pitch_degrees_v2: [%d]\n", ctag.pose_pitch_degrees_v2.value.i_val);
+                       printf("# pose_roll_degrees_v2: [%d]\n", ctag.pose_roll_degrees_v2.value.i_val);
+                       printf("# cbmp_layout_v2: [%d]\n", ctag.cbmp_layout_v2.value.i_val);
+                       printf("# cbmp_padding_v2: [%d]\n", ctag.cbmp_padding_v2.value.i_val);
+                       printf("# equi_projection_bounds_top_v2: [%d]\n", ctag.equi_projection_bounds_top_v2.value.i_val);
+                       printf("# equi_projection_bounds_bottom_v2: [%d]\n", ctag.equi_projection_bounds_bottom_v2.value.i_val);
+                       printf("# equi_projection_bounds_left_v2: [%d]\n", ctag.equi_projection_bounds_left_v2.value.i_val);
+                       printf("# equi_projection_bounds_right_v2: [%d]\n", ctag.equi_projection_bounds_right_v2.value.i_val);
+               }
+
                if (ctag.synclyrics_size.value.i_val > 0) {
                        int idx = 0;
                        unsigned long time_info = 0;
index 0118779..a650270 100755 (executable)
@@ -33,6 +33,8 @@
 #include "mm_file_utils.h"
 
 #define ENABLE_ITUNES_META             /*All itunes metadata extracted by ffmpeg. see mov_read_udta_string() but Some cover art not support. */
+#define INVALID_UINT_VALUE     0xFFFFFFFF
+#define INVALID_UINT8_VALUE    0xFF
 
 typedef struct _mmfilemp4basicboxheader {
        unsigned int size;
@@ -140,6 +142,14 @@ typedef struct _mmfilesa3dbox {
        uint32_t channel_map[49]; /* Up to 6th order */
 } __attribute__((aligned(1), packed)) MMFILE_MP4A_SA3D_TAGBOX;
 
+typedef enum {
+       PROJECTION_TYPE_RECT = 0, /* Rectangular, Google's RFC value */
+       PROJECTION_TYPE_EQUI = 1, /* Equirectangular, Google's RFC value */
+       PROJECTION_TYPE_CBMP = 2, /* Cubemap, Google's RFC value */
+       PROJECTION_TYPE_MESH = 3, /* Mesh, Google's RFC value, unsupported */
+       PROJECTION_TYPE_UNKNOWN = INVALID_UINT_VALUE,
+} SPHERICAL_VIDEO2_PROJECTION_TYPE;
+
 #define MMFILE_MP4_BASIC_BOX_HEADER_LEN 8
 #define MMFILE_MP4_MOVIE_HEADER_BOX_LEN 96
 #define MMFILE_MP4_HDLR_BOX_LEN         24
@@ -976,6 +986,231 @@ exception:
        return MMFILE_UTIL_FAIL;
 }
 
+static int ParseSt3dData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset)
+{
+       uint8_t stereo_mode = INVALID_UINT8_VALUE;
+       unsigned int readed = 0;
+
+       mmfile_seek(fp, start_offset, SEEK_SET);
+
+       readed = mmfile_read(fp, (unsigned char *)&stereo_mode, sizeof(uint8_t));
+       if (readed != sizeof(uint8_t)) {
+               debug_error(DEBUG, "read st3d tag header fail\n");
+               return MMFILE_UTIL_FAIL;
+       }
+
+       formatContext->stereoModeV2 = stereo_mode;
+
+       return MMFILE_UTIL_SUCCESS;
+}
+
+static int ParseSvhdData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset, unsigned int box_size)
+{
+       unsigned int readed = 0;
+
+       formatContext->metadataSourceV2 = (char *)calloc(1, box_size);
+       if (!formatContext->metadataSourceV2) {
+               debug_error(DEBUG, "Calloc failed");
+               return MMFILE_UTIL_FAIL;
+       }
+
+       mmfile_seek(fp, start_offset, SEEK_SET);
+       readed = mmfile_read(fp, (unsigned char *)formatContext->metadataSourceV2, box_size);
+       if (readed != box_size) {
+               debug_error(DEBUG, "read svhd tag header fail\n");
+               if (formatContext->metadataSourceV2)
+                       free(formatContext->metadataSourceV2);
+               return MMFILE_UTIL_FAIL;
+       }
+
+       return MMFILE_UTIL_SUCCESS;
+}
+
+static int ParseProjData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset)
+{
+       unsigned int readed = 0;
+       typedef struct proj_box_data_s {
+               uint32_t proj_type;
+               uint8_t version;
+               uint8_t flags[3];
+       } __attribute__((aligned(1), packed)) proj_box_data;
+
+       typedef struct prhd_box_data_s {
+               uint32_t projection_pose_yaw;
+               uint32_t projection_pose_pitch;
+               uint32_t projection_pose_roll;
+       } prhd_box_data;
+
+       typedef struct equi_box_data_s {
+               uint32_t projection_bounds_top;
+               uint32_t projection_bounds_bottom;
+               uint32_t projection_bounds_left;
+               uint32_t projection_bounds_right;
+       } equi_box_data;
+
+       typedef struct cbmp_box_data_s {
+               uint32_t layout;
+               uint32_t padding;
+       } cbmp_box_data;
+
+
+       proj_box_data proj_data;
+       proj_data.proj_type = INVALID_UINT_VALUE;
+
+       prhd_box_data prhd_data;
+       prhd_data.projection_pose_yaw = INVALID_UINT_VALUE;
+       prhd_data.projection_pose_pitch = INVALID_UINT_VALUE;
+       prhd_data.projection_pose_roll = INVALID_UINT_VALUE;
+
+       equi_box_data equi_data;
+       equi_data.projection_bounds_top = INVALID_UINT_VALUE;
+       equi_data.projection_bounds_bottom = INVALID_UINT_VALUE;
+       equi_data.projection_bounds_left = INVALID_UINT_VALUE;
+       equi_data.projection_bounds_right = INVALID_UINT_VALUE;
+
+       cbmp_box_data cbmp_data;
+       cbmp_data.layout = INVALID_UINT_VALUE;
+       cbmp_data.padding = INVALID_UINT_VALUE;
+
+       mmfile_seek(fp, start_offset, SEEK_SET);
+
+       readed = mmfile_read(fp, (unsigned char *)&proj_data, sizeof(proj_box_data));
+       if (readed != sizeof(proj_box_data)) {
+               debug_error(DEBUG, "read of proj box failed\n");
+               return MMFILE_UTIL_FAIL;
+       }
+
+       formatContext->projTypeV2 = mmfile_io_be_uint32(proj_data.proj_type);
+
+       debug_error(DEBUG, "formatContext->projTypeV2 = %d\n", formatContext->projTypeV2);
+       debug_error(DEBUG, "proj_data.version = %d\n", proj_data.version);
+       debug_error(DEBUG, "proj_data.flags = %d\n", ((uint32_t)proj_data.flags[0] << 16) +
+                       ((uint32_t)proj_data.flags[1] << 8) + (uint32_t)proj_data.flags[2]);
+
+       mmfile_seek(fp, sizeof(proj_box_data), SEEK_CUR);
+       readed = mmfile_read(fp, (unsigned char *)&prhd_data, sizeof(prhd_box_data));
+       if (readed != sizeof(prhd_box_data)) {
+               debug_error(DEBUG, "read of prhd box failed\n");
+               return MMFILE_UTIL_FAIL;
+       }
+
+       formatContext->poseYawV2 = mmfile_io_be_uint32(prhd_data.projection_pose_yaw);
+       formatContext->posePitchV2 = mmfile_io_be_uint32(prhd_data.projection_pose_pitch);
+       formatContext->poseRollV2 = mmfile_io_be_uint32(prhd_data.projection_pose_roll);
+
+       debug_error(DEBUG, "formatContext->poseYawV2 = %d\n", formatContext->poseYawV2);
+       debug_error(DEBUG, "formatContext->posePitchV2 = %d\n", formatContext->posePitchV2);
+       debug_error(DEBUG, "formatContext->poseRollV2 = %d\n", formatContext->poseRollV2);
+
+       if (formatContext->projTypeV2 == PROJECTION_TYPE_EQUI) {
+               debug_msg(RELEASE, "Projection type is Equirectangular");
+               mmfile_seek(fp, 8, SEEK_CUR); /* 8 = 4 (for size) + 4 (fourcc) */
+               readed = mmfile_read(fp, (unsigned char *)&equi_data, sizeof(equi_box_data));
+               if (readed != sizeof(equi_box_data)) {
+                       debug_error(DEBUG, "read of equi box failed\n");
+                       return MMFILE_UTIL_FAIL;
+               }
+
+               formatContext->equiBoundsTopV2 = mmfile_io_be_uint32(equi_data.projection_bounds_top);
+               formatContext->equiBoundsBottomV2 = mmfile_io_be_uint32(equi_data.projection_bounds_bottom);
+               formatContext->equiBoundsLeftV2 = mmfile_io_be_uint32(equi_data.projection_bounds_left);
+               formatContext->equiBoundsRightV2 = mmfile_io_be_uint32(equi_data.projection_bounds_right);
+
+               debug_error(DEBUG, "formatContext->equiBoundsTopV2 = %d\n", formatContext->equiBoundsTopV2);
+               debug_error(DEBUG, "formatContext->equiBoundsBottomV2 = %d\n", formatContext->equiBoundsBottomV2);
+               debug_error(DEBUG, "formatContext->equiBoundsLeftV2 = %d\n", formatContext->equiBoundsLeftV2);
+               debug_error(DEBUG, "formatContext->equiBoundsRightV2 = %d\n", formatContext->equiBoundsRightV2);
+
+       } else if (formatContext->projTypeV2 == PROJECTION_TYPE_CBMP) {
+               debug_msg(RELEASE, "Projection type is Cubemap");
+               mmfile_seek(fp, 8, SEEK_CUR); /* 8 = 4 (for size) + 4 (fourcc) */
+               readed = mmfile_read(fp, (unsigned char *)&cbmp_data, sizeof(cbmp_box_data));
+               if (readed != sizeof(cbmp_box_data)) {
+                       debug_error(DEBUG, "read of cbmp box failed\n");
+                       return MMFILE_UTIL_FAIL;
+               }
+
+               formatContext->cbmpLayoutV2 = mmfile_io_be_uint32(cbmp_data.layout);
+               formatContext->cbmpPaddingV2 = mmfile_io_be_uint32(cbmp_data.padding);
+
+               debug_error(DEBUG, "formatContext->cbmpLayoutV2 = %d\n", formatContext->cbmpLayoutV2);
+               debug_error(DEBUG, "formatContext->cbmpPaddingV2 = %d\n", formatContext->cbmpPaddingV2);
+
+       } else {
+               debug_msg(RELEASE, "Projection type is %d (unknown)", proj_data.proj_type);
+               return MMFILE_UTIL_FAIL;
+       }
+
+       return MMFILE_UTIL_SUCCESS;
+}
+
+static int GetVideoV2MetadataFromAvc1TagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
+{
+       if (!formatContext || !fp || !basic_header) {
+               debug_error(DEBUG, "invalid param\n");
+               return MMFILE_UTIL_FAIL;
+       }
+
+       unsigned char *buffer;
+       int readed = 0;
+       unsigned int i = 0;
+
+       formatContext->stereoModeV2 = INVALID_UINT_VALUE;
+       formatContext->metadataSourceV2 = NULL;
+       formatContext->projTypeV2 = INVALID_UINT_VALUE;
+       formatContext->poseYawV2 = INVALID_UINT_VALUE;
+       formatContext->posePitchV2 = INVALID_UINT_VALUE;
+       formatContext->poseRollV2 = INVALID_UINT_VALUE;
+       formatContext->cbmpLayoutV2 = INVALID_UINT_VALUE;
+       formatContext->cbmpPaddingV2 = INVALID_UINT_VALUE;
+       formatContext->equiBoundsTopV2 = INVALID_UINT_VALUE;
+       formatContext->equiBoundsBottomV2 = INVALID_UINT_VALUE;
+       formatContext->equiBoundsLeftV2 = INVALID_UINT_VALUE;
+       formatContext->equiBoundsRightV2 = INVALID_UINT_VALUE;
+
+       mmfile_seek(fp, basic_header->start_offset, SEEK_SET);
+
+       buffer = calloc(basic_header->size + 1, sizeof(unsigned char));
+       if (!buffer) {
+               debug_error(DEBUG, "calloc failed ");
+               goto exception;
+       }
+
+       readed = mmfile_read(fp, buffer, basic_header->size);
+       if (readed != (int)basic_header->size) {
+               debug_error(DEBUG, "read st3d box failed\n");
+               goto exception;
+       }
+
+       for (i = 0; i + 3 < basic_header->size; ++i) {
+               if ((buffer[i] == 's' && buffer[i + 1] == 't' && buffer[i + 2] == '3' && buffer[i + 3] == 'd') && (formatContext->stereoModeV2 == INVALID_UINT_VALUE)) {
+                       debug_warning(DEBUG, "st3d data found at offset %0x\n", basic_header->start_offset + i);
+                       ParseSt3dData(formatContext, fp, basic_header->start_offset + i + 4);
+                       debug_msg(RELEASE, "formatContext->stereoModeV2 = %d", formatContext->stereoModeV2);
+               }
+               if (buffer[i] == 's' && buffer[i + 1] == 'v' && buffer[i + 2] == '3' && buffer[i + 3] == 'd') {
+                       debug_warning(DEBUG, "sv3d data found at offset %0x\n", basic_header->start_offset + i);
+                       formatContext->isSpherical = true;
+               }
+               if (buffer[i] == 's' && buffer[i + 1] == 'v' && buffer[i + 2] == 'h' && buffer[i + 3] == 'd') {
+                       debug_warning(DEBUG, "svhd data found at offset %0x\n", basic_header->start_offset + i);
+                       ParseSvhdData(formatContext, fp, basic_header->start_offset + i + 4, mmfile_io_be_uint32(*((uint32_t*)(buffer - 4 + i))));
+                       debug_msg(RELEASE, "formatContext->metadataSourceV2 = %s (length = %d)", formatContext->metadataSourceV2, strlen(formatContext->metadataSourceV2));
+               }
+               if (buffer[i] == 'p' && buffer[i + 1] == 'r' && buffer[i + 2] == 'o' && buffer[i + 3] == 'j') {
+                       debug_warning(DEBUG, "proj data found at offset %0x\n", basic_header->start_offset + i);
+                       ParseProjData(formatContext, fp, basic_header->start_offset + i + 4);
+               }
+       }
+
+       return MMFILE_UTIL_SUCCESS;
+
+exception:
+       mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
+
+       return MMFILE_UTIL_FAIL;
+}
+
 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
 {
        unsigned int value = 0;
@@ -1892,6 +2127,11 @@ EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
                                        ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
                                        break;
                                }
+                       case FOURCC('a', 'v', 'c', '1'): {
+                                       debug_msg(RELEASE, "MPEG4: [avc1] SIZE: [%lld]Byte (offset: %0x)\n", chunk_size, basic_header.start_offset);
+                                       GetVideoV2MetadataFromAvc1TagBox(formatContext, fp, &basic_header);
+                                       break;
+                               }
                        default: {
                                        debug_msg(RELEASE, "4CC: Not Support [%c%c%c%c]. So skip it. Size [%lld Byte]\n",
                                                                ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],