From 4566f76461cc1192f9f7dfea44ea1882472c1818 Mon Sep 17 00:00:00 2001 From: Mykola Alieksieiev Date: Thu, 17 Aug 2017 12:32:07 +0300 Subject: [PATCH] Add Spherical Video Metadata V2 support Change-Id: I215cce72ac37719c8fbb62da5953e498452ded1f Signed-off-by: Mykola Alieksieiev --- formats/ffmpeg/mm_file_formats.c | 1 + include/mm_file.h | 13 ++- include/mm_file_formats.h | 12 ++ mm_file.c | 25 ++++ tests/mm_file_test.c | 40 +++++++ utils/mm_file_util_tag.c | 240 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 330 insertions(+), 1 deletion(-) diff --git a/formats/ffmpeg/mm_file_formats.c b/formats/ffmpeg/mm_file_formats.c index d5998f7..18282d6 100755 --- a/formats/ffmpeg/mm_file_formats.c +++ b/formats/ffmpeg/mm_file_formats.c @@ -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); diff --git a/include/mm_file.h b/include/mm_file.h index 7afa290..b4686c3 100755 --- a/include/mm_file.h +++ b/include/mm_file.h @@ -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.
diff --git a/include/mm_file_formats.h b/include/mm_file_formats.h index 9efc3ab..257ff9b 100755 --- a/include/mm_file_formats.h +++ b/include/mm_file_formats.h @@ -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; diff --git a/mm_file.c b/mm_file.c index 98812e3..4170f4c 100755 --- 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); diff --git a/tests/mm_file_test.c b/tests/mm_file_test.c index 0195355..8dc8001 100755 --- a/tests/mm_file_test.c +++ b/tests/mm_file_test.c @@ -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; diff --git a/utils/mm_file_util_tag.c b/utils/mm_file_util_tag.c index 0118779..a650270 100755 --- a/utils/mm_file_util_tag.c +++ b/utils/mm_file_util_tag.c @@ -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], -- 2.7.4