{(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[] = {
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);
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;
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);
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;
#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;
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
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;
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],