{(char *)"tag-rotate", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, (void *)NULL},
{(char *)"tag-cdis", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
{(char *)"tag-smta", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
- {(char *)"tag-360", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
- {(char *)"tag-stitched_info", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-spherical", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-stitched", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-stitching-software", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, (void *)NULL},
+ {(char *)"tag-projection-type", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, (void *)NULL},
+ {(char *)"tag-stereo-mode", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, (void *)NULL},
+ {(char *)"tag-source-count", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-init-view-heading", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-init-view-pitch", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-init-view-roll", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-timestamp", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-full-pano-width", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-full-pano-height", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-cropped-area-image-width", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-cropped-area-image-height", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-cropped-area-left", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(char *)"tag-cropped-area-top", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, (void *)0},
+ {(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},
};
static mmf_attrs_construct_info_t g_content_attrs[] = {
mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_CDIS, formatContext->cdis);
mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SMTA, formatContext->smta);
- mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_360, formatContext->is_360);
- mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_STITCHED_INFO, formatContext->stitched_info);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL, formatContext->isSpherical);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_STITCHED, formatContext->isStitched);
+ if (formatContext->stitchingSoftware) mm_attrs_set_string_by_name(hattrs, MM_FILE_TAG_SPHERICAL_STITCHING_SOFTWARE, formatContext->stitchingSoftware);
+ if (formatContext->projectionType) mm_attrs_set_string_by_name(hattrs, MM_FILE_TAG_SPHERICAL_PROJECTION_TYPE, formatContext->projectionType);
+ if (formatContext->stereoMode) mm_attrs_set_string_by_name(hattrs, MM_FILE_TAG_SPHERICAL_STEREO_MODE, formatContext->stereoMode);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_SOURCE_COUNT, formatContext->sourceCount);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_INIT_VIEW_HEADING, formatContext->initViewHeading);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_INIT_VIEW_PITCH, formatContext->initViewPitch);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_INIT_VIEW_ROLL, formatContext->initViewRoll);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_TIMESTAMP, formatContext->timestamp);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_FULL_PANO_WIDTH, formatContext->fullPanoWidth);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_FULL_PANO_HEIGHT, formatContext->fullPanoHeight);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_CROPPED_AREA_IMAGE_WIDTH, formatContext->croppedAreaImageWidth);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_CROPPED_AREA_IMAGE_HEIGHT, formatContext->croppedAreaImageHeight);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_CROPPED_AREA_LEFT, formatContext->croppedAreaLeft);
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_SPHERICAL_CROPPED_AREA_TOP, formatContext->croppedAreaTop);
+
+ mm_attrs_set_int_by_name(hattrs, MM_FILE_TAG_AMBISONIC_TYPE, formatContext->ambisonicType);
+ 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);
if ((formatContext->syncLyricsNum > 0) && (formatContext->syncLyrics))
mm_attrs_set_data_by_name(hattrs, MM_FILE_TAG_SYNCLYRICS, formatContext->syncLyrics, formatContext->syncLyricsNum);
#include <mm_file.h>
#include "mm_file_traverse.h"
+#include "mm_file_debug.h"
#define MM_TIME_CHECK_START \
{ FILE *msg_tmp_fp = fopen("time_check.txt", "a+"); struct timeval start, finish; gettimeofday(&start, NULL);
mmfile_value_t unsynclyrics;
mmfile_value_t synclyrics_size;
mmfile_value_t rotate; /*string */
- mmfile_value_t stitched_info;
+ mmfile_value_t is_spherical;
+ mmfile_value_t is_stitched;
+ mmfile_value_t stitching_software; /*string */
+ mmfile_value_t projection_type; /*string */
+ mmfile_value_t stereo_mode; /*string */
+ mmfile_value_t source_count;
+ mmfile_value_t init_view_heading;
+ mmfile_value_t init_view_pitch;
+ mmfile_value_t init_view_roll;
+ mmfile_value_t timestamp;
+ mmfile_value_t full_pano_width;
+ mmfile_value_t full_pano_height;
+ mmfile_value_t cropped_area_image_width;
+ mmfile_value_t cropped_area_image_height;
+ mmfile_value_t cropped_area_left;
+ mmfile_value_t cropped_area_top;
+ mmfile_value_t ambisonic_type;
+ mmfile_value_t ambisonic_format;
+ mmfile_value_t ambisonic_order;
+
} TagContext_t;
typedef struct _ContentContext {
MM_FILE_TAG_UNSYNCLYRICS, &ctag.unsynclyrics.value.s_val, &ctag.unsynclyrics.len,
MM_FILE_TAG_SYNCLYRICS_NUM, &ctag.synclyrics_size.value.i_val,
MM_FILE_TAG_ROTATE, &ctag.rotate.value.s_val, &ctag.rotate.len,
- MM_FILE_TAG_STITCHED_INFO, &ctag.stitched_info.value.i_val,
+ MM_FILE_TAG_SPHERICAL, &ctag.is_spherical.value.i_val,
+ MM_FILE_TAG_SPHERICAL_STITCHED, &ctag.is_stitched.value.i_val,
+ MM_FILE_TAG_SPHERICAL_STITCHING_SOFTWARE, &ctag.stitching_software.value.s_val, &ctag.stitching_software.len,
+ MM_FILE_TAG_SPHERICAL_PROJECTION_TYPE, &ctag.projection_type.value.s_val, &ctag.projection_type.len,
+ MM_FILE_TAG_SPHERICAL_STEREO_MODE, &ctag.stereo_mode.value.s_val, &ctag.stereo_mode.len,
+ MM_FILE_TAG_SPHERICAL_SOURCE_COUNT, &ctag.source_count.value.i_val,
+ MM_FILE_TAG_SPHERICAL_INIT_VIEW_HEADING, &ctag.init_view_heading.value.i_val,
+ MM_FILE_TAG_SPHERICAL_INIT_VIEW_PITCH, &ctag.init_view_pitch.value.i_val,
+ MM_FILE_TAG_SPHERICAL_INIT_VIEW_ROLL, &ctag.init_view_roll.value.i_val,
+ MM_FILE_TAG_SPHERICAL_TIMESTAMP, &ctag.timestamp.value.i_val,
+ MM_FILE_TAG_SPHERICAL_FULL_PANO_WIDTH, &ctag.full_pano_width.value.i_val,
+ MM_FILE_TAG_SPHERICAL_FULL_PANO_HEIGHT, &ctag.full_pano_height.value.i_val,
+ MM_FILE_TAG_SPHERICAL_CROPPED_AREA_IMAGE_WIDTH, &ctag.cropped_area_image_width.value.i_val,
+ MM_FILE_TAG_SPHERICAL_CROPPED_AREA_IMAGE_HEIGHT, &ctag.cropped_area_image_height.value.i_val,
+ MM_FILE_TAG_SPHERICAL_CROPPED_AREA_LEFT, &ctag.cropped_area_left.value.i_val,
+ MM_FILE_TAG_SPHERICAL_CROPPED_AREA_TOP, &ctag.cropped_area_top.value.i_val,
+ 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,
NULL);
if (ret != FILEINFO_ERROR_NONE && err_attr_name) {
printf("failed to get %s attrs\n", err_attr_name);
printf("# unsynclyrics: [%s]\n", ctag.unsynclyrics.value.s_val);
printf("# synclyrics size: [%d]\n", ctag.synclyrics_size.value.i_val);
printf("# rotate: [%s]\n", ctag.rotate.value.s_val);
- printf("# stitched_info: [%d]\n", ctag.stitched_info.value.i_val);
+ printf("# is_spherical: [%d]\n", ctag.is_spherical.value.i_val);
+ printf("# is_stitched: [%d]\n", ctag.is_stitched.value.i_val);
+
+ if (ctag.is_spherical.value.i_val > 0 && ctag.is_stitched.value.i_val > 0) {
+ printf("# stitching_software: [%s]\n", ctag.stitching_software.value.s_val);
+ printf("# projection_type: [%s]\n", ctag.projection_type.value.s_val);
+ printf("# stereo_mode [%s]\n", ctag.stereo_mode.value.s_val);
+ printf("# source_count: [%d]\n", ctag.source_count.value.i_val);
+ printf("# init_view_heading: [%d]\n", ctag.init_view_heading.value.i_val);
+ printf("# init_view_pitch: [%d]\n", ctag.init_view_pitch.value.i_val);
+ printf("# init_view_roll: [%d]\n", ctag.init_view_roll.value.i_val);
+ printf("# time_stamp: [%d]\n", ctag.timestamp.value.i_val);
+ printf("# full_pano_width: [%d]\n", ctag.full_pano_width.value.i_val);
+ printf("# full_pano_height: [%d]\n", ctag.full_pano_height.value.i_val);
+ printf("# cropped_area_image_width: [%d]\n", ctag.cropped_area_image_width.value.i_val);
+ printf("# cropped_area_image_height: [%d]\n", ctag.cropped_area_image_height.value.i_val);
+ printf("# cropped_area_left: [%d]\n", ctag.cropped_area_left.value.i_val);
+ printf("# cropped_area_top: [%d]\n", ctag.cropped_area_top.value.i_val);
+ }
+
+ printf("# ambisonic_type: [%d]\n", ctag.ambisonic_type.value.i_val);
+
+ if (ctag.ambisonic_type.value.i_val > 0) {
+ printf("# ambisonic_format: [%d]\n", ctag.ambisonic_format.value.i_val);
+ printf("# ambisonic_order: [%d]\n", ctag.ambisonic_order.value.i_val);
+ }
if (ctag.synclyrics_size.value.i_val > 0) {
int idx = 0;
#include <vconf.h>
#include <glib.h>
#include <iniparser.h>
+#include <stdint.h>
#include "mm_file.h"
#include "mm_file_debug.h"
unsigned int value;
} MMFILE_M4A_SMTA_TAGBOX;
+typedef struct _mmfilesa3dbox {
+ uint8_t version;
+ uint8_t ambisonic_type;
+ uint32_t ambisonic_order;
+ uint8_t ambisonic_channel_ordering;
+ uint8_t ambisonic_normalization;
+ uint32_t num_channels;
+ uint32_t channel_map[49]; /* Up to 6th order */
+} __attribute__((aligned(1), packed)) MMFILE_MP4A_SA3D_TAGBOX;
+
#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 GetSA3DInfoFromMP4ATagBox(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;
+ bool is_SA3D_present = false;
+ unsigned int i = 0;
+ MMFILE_MP4A_SA3D_TAGBOX sa3dTag = {0, };
+
+ formatContext->ambisonicType = MMFILE_AMBISONIC_TYPE_UNKNOWN;
+ formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_UNKNOWN;
+ formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_UNKNOWN;
+
+ 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 mp4a box failed\n");
+ goto exception;
+ }
+
+ for (i = 0; i + 3 < basic_header->size; ++i)
+ if (buffer[i] == 'S' && buffer[i + 1] == 'A' && buffer[i + 2] == '3' && buffer[i + 3] == 'D') {
+ debug_warning(DEBUG, "SA3D data found at offset %d bytes\n", i);
+ is_SA3D_present = true;
+ break;
+ }
+
+ if (!is_SA3D_present) {
+ debug_warning(DEBUG, "No SA3D box found");
+ goto exception;
+ }
+
+ mmfile_seek(fp, basic_header->start_offset + i + 4, SEEK_SET);
+
+ readed = mmfile_read(fp, (unsigned char *)&sa3dTag, sizeof(MMFILE_MP4A_SA3D_TAGBOX));
+ if (readed != sizeof(MMFILE_MP4A_SA3D_TAGBOX)) {
+ debug_error(DEBUG, "read SA3D tag header fail\n");
+ goto exception;
+ }
+
+ sa3dTag.ambisonic_order = mmfile_io_be_uint32(sa3dTag.ambisonic_order);
+ sa3dTag.num_channels = mmfile_io_be_uint32(sa3dTag.num_channels);
+ for (i = 0; i < sa3dTag.num_channels; ++i)
+ sa3dTag.channel_map[i] = mmfile_io_be_uint32(sa3dTag.channel_map[i]);
+
+ debug_msg(RELEASE, "sa3dTag.version = %d", sa3dTag.version);
+ debug_msg(RELEASE, "sa3dTag.ambisonic_type = %d", sa3dTag.ambisonic_type);
+ debug_msg(RELEASE, "sa3dTag.ambisonic_order = %d", sa3dTag.ambisonic_order);
+ debug_msg(RELEASE, "sa3dTag.ambisonic_channel_ordering = %d", sa3dTag.ambisonic_channel_ordering);
+ debug_msg(RELEASE, "sa3dTag.ambisonic_normalization = %d", sa3dTag.ambisonic_normalization);
+ debug_msg(RELEASE, "sa3dTag.num_channels = %d", sa3dTag.num_channels);
+ for (i = 0; i < sa3dTag.num_channels; ++i)
+ debug_msg(RELEASE, "sa3dTag.channel_map[%d] = %d", i, sa3dTag.channel_map[i]);
+
+ if (sa3dTag.version != RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
+ debug_error(DEBUG, "SA3D tag box version is unsupported\n");
+ goto exception;
+ } else {
+ if (sa3dTag.ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
+ formatContext->ambisonicType = MMFILE_AMBISONIC_TYPE_PERIPHONIC;
+
+ switch (sa3dTag.ambisonic_order) {
+ case MMFILE_AMBISONIC_ORDER_FOA: {
+ if (sa3dTag.num_channels == 4) {
+ formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_FOA;
+
+ if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
+ (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
+ (sa3dTag.channel_map[0] == 0) &&
+ (sa3dTag.channel_map[1] == 1) &&
+ (sa3dTag.channel_map[2] == 2) &&
+ (sa3dTag.channel_map[3] == 3))
+ formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
+
+ if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
+ (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
+ (sa3dTag.channel_map[0] == 0) &&
+ (sa3dTag.channel_map[1] == 3) &&
+ (sa3dTag.channel_map[2] == 1) &&
+ (sa3dTag.channel_map[3] == 2))
+ formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
+ } else {
+ debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
+ goto exception;
+ }
+
+ break;
+ }
+ case MMFILE_AMBISONIC_ORDER_SOA: {
+ if (sa3dTag.num_channels == 9) {
+ formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_SOA;
+
+ if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
+ (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
+ (sa3dTag.channel_map[0] == 0) &&
+ (sa3dTag.channel_map[1] == 1) &&
+ (sa3dTag.channel_map[2] == 2) &&
+ (sa3dTag.channel_map[3] == 3) &&
+ (sa3dTag.channel_map[4] == 4) &&
+ (sa3dTag.channel_map[5] == 5) &&
+ (sa3dTag.channel_map[6] == 6) &&
+ (sa3dTag.channel_map[7] == 7) &&
+ (sa3dTag.channel_map[8] == 8))
+ formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
+
+ if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
+ (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
+ (sa3dTag.channel_map[0] == 0) &&
+ (sa3dTag.channel_map[1] == 3) &&
+ (sa3dTag.channel_map[2] == 1) &&
+ (sa3dTag.channel_map[3] == 2) &&
+ (sa3dTag.channel_map[4] == 6) &&
+ (sa3dTag.channel_map[5] == 7) &&
+ (sa3dTag.channel_map[6] == 5) &&
+ (sa3dTag.channel_map[7] == 8) &&
+ (sa3dTag.channel_map[4] == 4))
+ formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
+ } else {
+ debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
+ goto exception;
+ }
+
+ break;
+ }
+
+ case MMFILE_AMBISONIC_ORDER_TOA: {
+ if (sa3dTag.num_channels == 16) {
+ formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_TOA;
+
+ if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
+ (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
+ (sa3dTag.channel_map[0] == 0) &&
+ (sa3dTag.channel_map[1] == 1) &&
+ (sa3dTag.channel_map[2] == 2) &&
+ (sa3dTag.channel_map[3] == 3) &&
+ (sa3dTag.channel_map[4] == 4) &&
+ (sa3dTag.channel_map[5] == 5) &&
+ (sa3dTag.channel_map[6] == 6) &&
+ (sa3dTag.channel_map[7] == 7) &&
+ (sa3dTag.channel_map[8] == 8) &&
+ (sa3dTag.channel_map[9] == 9) &&
+ (sa3dTag.channel_map[10] == 10) &&
+ (sa3dTag.channel_map[11] == 11) &&
+ (sa3dTag.channel_map[12] == 12) &&
+ (sa3dTag.channel_map[13] == 13) &&
+ (sa3dTag.channel_map[14] == 14) &&
+ (sa3dTag.channel_map[15] == 15))
+ formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
+
+ if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
+ (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
+ (sa3dTag.channel_map[0] == 0) &&
+ (sa3dTag.channel_map[1] == 3) &&
+ (sa3dTag.channel_map[2] == 1) &&
+ (sa3dTag.channel_map[3] == 2) &&
+ (sa3dTag.channel_map[4] == 6) &&
+ (sa3dTag.channel_map[5] == 7) &&
+ (sa3dTag.channel_map[6] == 5) &&
+ (sa3dTag.channel_map[7] == 8) &&
+ (sa3dTag.channel_map[8] == 4) &&
+ (sa3dTag.channel_map[9] == 12) &&
+ (sa3dTag.channel_map[10] == 13) &&
+ (sa3dTag.channel_map[11] == 11) &&
+ (sa3dTag.channel_map[12] == 14) &&
+ (sa3dTag.channel_map[13] == 10) &&
+ (sa3dTag.channel_map[14] == 15) &&
+ (sa3dTag.channel_map[15] == 9))
+ formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
+ } else {
+ debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
+ goto exception;
+ }
+
+ break;
+ }
+
+ default: {
+ debug_warning(DEBUG, "Ambisonic order or format is not supported: ambix or amb formats up to 3rd order were expected.\n");
+ goto exception;
+ break;
+ }
+ }
+
+ debug_msg(RELEASE, "formatContext->ambisonic_type = %d", formatContext->ambisonicType);
+ debug_msg(RELEASE, "formatContext->ambisonic_order = %d", formatContext->ambisonicOrder);
+ debug_msg(RELEASE, "formatContext->ambisonic_format = %d", formatContext->ambisonicFormat);
+ }
+
+ 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;
return MMFILE_UTIL_FAIL;
}
+int mm_file_get_int_value_from_xml_string(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[value_length_max];
+ int value_length = 0;
+
+ if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
+ debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ value_start = strstr(xml_str, param_name) + strlen(param_name);
+ while ((value_start[0] == ' ') || (value_start[0] == '\t'))
+ value_start++;
+
+ value_end = strchr(value_start, '<');
+ if (!value_end) {
+ debug_error(DEBUG, "error: incorrect XML\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ value_length = value_end - value_start;
+ while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
+ value_length--;
+
+ int i = 0;
+ if (value_start[i] == '+' || value_start[i] == '-')
+ i++;
+ while (i < value_length) {
+ if (value_start[i] < '0' || value_start[i] > '9') {
+ debug_error(DEBUG, "error: incorrect value, integer was expected\n");
+ return MMFILE_UTIL_FAIL;
+ }
+ i++;
+ }
+
+ if (value_length >= value_length_max || value_length < 1) {
+ debug_error(DEBUG, "error: empty XML value or incorrect range\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ 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) {
+ debug_error(DEBUG, "error: no digits were found\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ return MMFILE_UTIL_SUCCESS;
+}
+
+int mm_file_get_string_value_from_xml_string(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;
+
+ if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
+ debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ value_start = strstr(xml_str, param_name) + strlen(param_name);
+ while ((value_start[0] == ' ') || (value_start[0] == '\t'))
+ value_start++;
+
+ value_end = strchr(value_start, '<');
+ if (!value_end) {
+ debug_error(DEBUG, "error: incorrect XML\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ 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) {
+ debug_error(DEBUG, "error: empty XML value or incorrect range\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ *value=(char*)calloc(value_length, sizeof(char));
+ if (*value == NULL) {
+ debug_error(DEBUG, "error: calloc failed\n");
+ return MMFILE_UTIL_FAIL;
+ }
+ strncpy(*value, value_start, value_length);
+
+ return MMFILE_UTIL_SUCCESS;
+}
+
+int mm_file_get_bool_value_from_xml_string(const char* xml_str, const char* param_name, bool* value)
+{
+ char *value_start, *value_end;
+ int value_length = 0;
+
+ if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
+ debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ value_start = strstr(xml_str, param_name) + strlen(param_name);
+ while ((value_start[0] == ' ') || (value_start[0] == '\t'))
+ value_start++;
+
+ value_end = strchr(value_start, '<');
+ if (!value_end) {
+ debug_error(DEBUG, "error: incorrect XML\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ 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) {
+ debug_error(DEBUG, "error: empty XML value or incorrect range\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ *value= strstr(value_start, "true") ? true : false;
+
+ return MMFILE_UTIL_SUCCESS;
+}
+
static int g_junk_counter_limit = 0;
static int GetJunkCounterLimit(void)
{
return data;
}
+static int ParseSpatialVideoMetadataFromXMLString(const char *xmlStr, MMFileFormatContext *formatContext)
+{
+ const char is_spherical_str[] = "<GSpherical:Spherical>";
+ const char is_stitched_str[] = "<GSpherical:Stitched>";
+ const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
+ const char projection_type_str[] = "<GSpherical:ProjectionType>";
+ const char stereo_mode_str[] = "<GSpherical:StereoMode>";
+ const char source_count_str[] = "<GSpherical:SourceCount>";
+ const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
+ const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
+ const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
+ const char timestamp_str[] = "<GSpherical:Timestamp>";
+ const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
+ const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
+ const char cropped_area_image_width_str[] = "<GSpherical:CroppedAreaImageWidthPixels>";
+ const char cropped_area_image_height_str[] = "<GSpherical:CroppedAreaImageHeightPixels>";
+ const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
+ const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
+
+ mm_file_get_bool_value_from_xml_string(xmlStr, is_spherical_str,(bool*)&formatContext->isSpherical);
+ mm_file_get_bool_value_from_xml_string(xmlStr, is_stitched_str, (bool*)&formatContext->isStitched);
+
+ debug_msg(RELEASE, "isSpherical = %d", formatContext->isSpherical);
+ debug_msg(RELEASE, "isStitched = %d", formatContext->isStitched);
+
+ if (formatContext->isSpherical && formatContext->isStitched) {
+ mm_file_get_string_value_from_xml_string(xmlStr, stitching_software_str, &formatContext->stitchingSoftware);
+ mm_file_get_string_value_from_xml_string(xmlStr, projection_type_str, &formatContext->projectionType);
+ mm_file_get_string_value_from_xml_string(xmlStr, stereo_mode_str, &formatContext->stereoMode);
+ mm_file_get_int_value_from_xml_string(xmlStr, source_count_str, &formatContext->sourceCount);
+ mm_file_get_int_value_from_xml_string(xmlStr, init_view_heading_str, &formatContext->initViewHeading);
+ mm_file_get_int_value_from_xml_string(xmlStr, init_view_pitch_str, &formatContext->initViewPitch);
+ mm_file_get_int_value_from_xml_string(xmlStr, init_view_roll_str, &formatContext->initViewRoll);
+ mm_file_get_int_value_from_xml_string(xmlStr, timestamp_str, &formatContext->timestamp);
+ mm_file_get_int_value_from_xml_string(xmlStr, full_pano_width_str, &formatContext->fullPanoWidth);
+ mm_file_get_int_value_from_xml_string(xmlStr, full_pano_height_str, &formatContext->fullPanoHeight);
+ mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_width_str, &formatContext->croppedAreaImageWidth);
+ mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_height_str, &formatContext->croppedAreaImageHeight);
+ mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_left_str, &formatContext->croppedAreaLeft);
+ mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_top_str, &formatContext->croppedAreaTop);
+
+ debug_msg(RELEASE, "stitchingSoftware = %s", formatContext->stitchingSoftware);
+ debug_msg(RELEASE, "projectionType = %s", formatContext->projectionType);
+ debug_msg(RELEASE, "stereoMode = %s", formatContext->stereoMode);
+ debug_msg(RELEASE, "sourceCount %d", formatContext->sourceCount);
+ debug_msg(RELEASE, "initViewHeading = %d", formatContext->initViewHeading);
+ debug_msg(RELEASE, "initViewPitch = %d", formatContext->initViewPitch);
+ debug_msg(RELEASE, "initViewRoll = %d", formatContext->initViewRoll);
+ debug_msg(RELEASE, "timestamp = %d", formatContext->timestamp);
+ debug_msg(RELEASE, "fullPanoWidthPixels = %d", formatContext->fullPanoWidth);
+ debug_msg(RELEASE, "fullPanoHeightPixels = %d", formatContext->fullPanoHeight);
+ debug_msg(RELEASE, "croppedAreaImageWidth = %d", formatContext->croppedAreaImageWidth);
+ debug_msg(RELEASE, "croppedAreaImageHeight = %d", formatContext->croppedAreaImageHeight);
+ debug_msg(RELEASE, "croppedAreaLeft = %d", formatContext->croppedAreaLeft);
+ debug_msg(RELEASE, "croppedAreaTop = %d", formatContext->croppedAreaTop);
+ }
+
+ return MMFILE_UTIL_SUCCESS;
+}
+
#define BIG_CONTENT_BOX_SIZE_LEN 8
EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
{
if(str != NULL) {
memset(str, 0, basic_header.size);
mmfile_read(fp, (unsigned char *)str, basic_header.size);
-
+#if 0
+/* The block is superseded */
if(strstr(str, "<GSpherical:Spherical>true</GSpherical:Spherical>"))
formatContext->is_360 = 1;
else
formatContext->is_360 = 0;
-
+/* Image can be stitched even if it is not spherical */
if(formatContext->is_360 == 1) {
if (strstr(str, "<GSpherical:Stitched>true</GSpherical:Stitched>"))
- formatContext->stitched_info = MMFILE_360_STITCHED;
+ formatContext->stitched = MMFILE_360_STITCHED;
else
- formatContext->stitched_info = MMFILE_360_NON_STITCHED;
+ formatContext->stitched = MMFILE_360_NON_STITCHED;
} else {
- formatContext->stitched_info = MMFILE_360_NONE;
+/* Image can be stitched or non-stitched. Usage of some 3rd value is superfluous */
+ formatContext->stitched = MMFILE_360_NONE;
}
+#endif
+
+ debug_msg(RELEASE, "Extracting tags from UUID XML string %s\n", str);
+
+ ParseSpatialVideoMetadataFromXMLString(str, formatContext);
}
}
ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
break;
}
+ case FOURCC('m', 'd', 'i', 'a'): {
+ debug_msg(RELEASE, "MPEG4: [mdia] SIZE: [%lld]Byte\n", chunk_size);
+ break;
+ }
+ case FOURCC('m', 'i', 'n', 'f'): {
+ debug_msg(RELEASE, "MPEG4: [minf] SIZE: [%lld]Byte\n", chunk_size);
+ break;
+ }
+ case FOURCC('s', 't', 'b', 'l'): {
+ debug_msg(RELEASE, "MPEG4: [stbl] SIZE: [%lld]Byte\n", chunk_size);
+ break;
+ }
+ case FOURCC('s', 't', 's', 'd'): {
+ debug_msg(RELEASE, "MPEG4: [stsd] SIZE: [%lld]Byte\n", chunk_size);
+ break;
+ }
+ case FOURCC('m', 'p', '4', 'a'): {
+ debug_msg(RELEASE, "MPEG4: [mp4a] SIZE: [%lld]Byte\n", chunk_size);
+ GetSA3DInfoFromMP4ATagBox(formatContext, fp, &basic_header);
+ ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
+ 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],