42844c6e7ddb5bf8fea4801b3197871003143e64
[platform/core/multimedia/libmm-fileinfo.git] / utils / mm_file_util_tag.c
1 /*
2  * libmm-fileinfo
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Haejeong Kim <backto.kim@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <vconf.h>
27 #include <glib.h>
28 #include <stdint.h>
29
30 #include "mm_file.h"
31 #include "mm_file_debug.h"
32 #include "mm_file_utils.h"
33
34 #define ENABLE_ITUNES_META              /*All itunes metadata extracted by ffmpeg. see mov_read_udta_string() but Some cover art not support. */
35 #define INVALID_UINT_VALUE      0xFFFFFFFF
36 #define INVALID_UINT8_VALUE     0xFF
37
38 #define ID3TAG_V110_TRACK_NUM_DIGIT     5
39
40 typedef struct _mmfilemp4basicboxheader {
41         unsigned int size;
42         unsigned int type;
43         long long start_offset; /*huge file*/
44 } MMFILE_MP4_BASIC_BOX_HEADER;
45
46 typedef struct _mmfilemp4ftpybox {
47         unsigned int major_brand;
48         unsigned short major_version;
49         unsigned short minor_version;
50         unsigned int *compatiable_brands;
51 } MMFILE_MP4_FTYPBOX;
52
53 typedef enum {
54         eMMFILE_3GP_TAG_TITLE = 0x01,
55         eMMFILE_3GP_TAG_CAPTION = 0x02,
56         eMMFILE_3GP_TAG_COPYRIGHT = 0x03,
57         eMMFILE_3GP_TAG_PERFORMER = 0x04,
58         eMMFILE_3GP_TAG_AUTHOR = 0x05,
59         eMMFILE_3GP_TAG_GENRE = 0x06,
60 } eMMFILE_3GP_TEXT_TAG;
61
62 typedef struct _mmfile3gptagtextbox {
63         unsigned char version;
64         unsigned char flag[3];
65         unsigned char language[2];
66         unsigned char *text;
67 } MMFILE_3GP_TEXT_TAGBOX;
68
69 typedef struct _mmfile3gptagyearbox {
70         unsigned char version;
71         unsigned char flag[3];
72         unsigned short year;
73 } MMFILE_3GP_YEAR_TAGBOX;
74
75 typedef struct _mmfile3gptagalbumbox {
76         unsigned char version;
77         unsigned char flag[3];
78         unsigned char language[2];
79         unsigned char *albumtile;
80         unsigned char trackNumber;
81 } MMFILE_3GP_ALBUM_TAGBOX;
82
83 typedef struct _mmfile3gpratingbox {
84         unsigned char version;
85         unsigned char flag[3];
86         unsigned int  ratingEntity;
87         unsigned int  ratingCriteria;
88         unsigned char language[2];
89         unsigned char *ratingInfo;
90 } MMFILE_3GP_RATING_TAGBOX;
91
92 typedef struct _mmfile3gpclsfbox {
93         unsigned char version;
94         unsigned char flag[3];
95         unsigned int  classificationEntity;
96         unsigned int  classificationTable;
97         unsigned char language[2];
98         unsigned char *classificationInfo;
99 } MMFILE_3GP_CLASSIFICATION_TAGBOX;
100
101 typedef struct _mmfile3gphdlrbox {
102         unsigned int  version;
103         unsigned int  pre_defined;
104         unsigned int  handler_type;
105         unsigned int  reserved[3];
106         unsigned char *boxname;
107 } MMFILE_3GP_HANDLER_BOX;
108
109 typedef struct _mmfileidv2box {
110         unsigned char version;
111         unsigned char flag[3];
112         unsigned char language[2];
113         unsigned char *id3v2Data;
114 } MMFILE_3GP_ID3V2_BOX;
115
116 typedef struct _mmfilelocibox {
117         unsigned char version;
118         unsigned char flag[3];
119         unsigned char language[2];
120         unsigned char *name;
121         unsigned char role;
122         float         longitude;
123         float         latitude;
124         float         altitude;
125         unsigned char *astronomical_body;
126         unsigned char *additional_notes;
127 } MMFILE_3GP_LOCATION_TAGBOX;
128
129 typedef struct _mmfilesmtabox {
130         unsigned int tmp;
131         unsigned int length;
132         unsigned char saut[4];
133         unsigned int value;
134 } MMFILE_M4A_SMTA_TAGBOX;
135
136 typedef struct _mmfilesa3dbox {
137         uint8_t version;
138         uint8_t ambisonic_type;
139         uint32_t ambisonic_order;
140         uint8_t ambisonic_channel_ordering;
141         uint8_t ambisonic_normalization;
142         uint32_t num_channels;
143         uint32_t channel_map[49]; /* Up to 6th order */
144 } __attribute__((aligned(1), packed)) MMFILE_MP4A_SA3D_TAGBOX;
145
146 typedef struct _mmfile_proj_v2_box {
147         uint16_t proj_box_id;
148         uint8_t proj_box_size;
149         uint16_t proj_type_box_id;
150         uint8_t proj_type_box_size;
151         uint8_t proj_type_box_value; /* only equi (=1) or cubemap (=2) currently */
152         uint16_t proj_priv_box_id;
153         uint8_t proj_priv_box_size;
154 } __attribute__((aligned(1), packed)) MMFILE_WEBM_PROJ_V2_BOX;
155
156 typedef struct _mmfile_equi_proj_v2_box {
157         unsigned char proj_priv_box_name[4]; /* "equi" */
158         uint32_t equi_projection_bounds_top;
159         uint32_t equi_projection_bounds_bottom;
160         uint32_t equi_projection_bounds_left;
161         uint32_t equi_projection_bounds_right;
162 } __attribute__((aligned(1), packed)) MMFILE_WEBM_EQUI_PROJ_V2_BOX;
163
164 typedef struct _mmfile_cbmp_proj_v2_box {
165         unsigned char proj_priv_box_name[4]; /* "cbmp" */
166         uint32_t cbmp_projection_layout;
167         uint32_t cbmp_projection_padding;
168 } __attribute__((aligned(1), packed)) MMFILE_WEBM_CBMP_PROJ_V2_BOX;
169
170 typedef struct _mmfile_pose_element_v2_box {
171         uint16_t pose_yaw_element_id;
172         uint8_t pose_yaw_element_size;
173         float pose_yaw_element_value;
174         uint16_t pose_pitch_element_id;
175         uint8_t pose_pitch_element_size;
176         float  pose_pitch_element_value;
177         uint16_t pose_roll_element_id;
178         uint8_t pose_roll_element_size;
179         float  pose_roll_element_value;
180 } __attribute__((aligned(1), packed)) MMFILE_WEBM_POSE_ELEMENT_V2_BOX;
181
182
183 typedef enum {
184         PROJECTION_TYPE_RECT = 0, /* Rectangular, Google's RFC value */
185         PROJECTION_TYPE_EQUI = 1, /* Equirectangular, Google's RFC value */
186         PROJECTION_TYPE_CBMP = 2, /* Cubemap, Google's RFC value */
187         PROJECTION_TYPE_MESH = 3, /* Mesh, Google's RFC value, unsupported */
188         PROJECTION_TYPE_UNKNOWN = INVALID_UINT_VALUE,
189 } SPHERICAL_VIDEO2_PROJECTION_TYPE;
190
191 enum spherical_video_metadata_elements_ids_le {
192         PROJ_BOX_ID           = 0x7076,
193         PROJ_TYPE_BOX_ID      = 0x7176,
194         PROJ_PRIV_BOX_ID      = 0x7276,
195         POSE_YAW_ELEMENT_ID   = 0x7376,
196         POSE_PITCH_ELEMENT_ID = 0x7476,
197         POSE_ROLL_ELEMENT_ID  = 0x7576
198 };
199
200 #define MMFILE_MP4_BASIC_BOX_HEADER_LEN 8
201 #define MMFILE_MP4_MOVIE_HEADER_BOX_LEN 96
202 #define MMFILE_MP4_HDLR_BOX_LEN         24
203 #define MMFILE_MP4_STSZ_BOX_LEN         20
204 #define MMFILE_MP4_MP4VBOX_LEN          80
205 #define MMFILE_MP4_MP4ABOX_LEN          28
206 #define MMFILE_3GP_TEXT_TAGBOX_LEN      6
207 #define MMFILE_3GP_YEAR_TAGBOX_LEN      6
208 #define MMFILE_3GP_ALBUM_TAGBOX_LEN     6
209 #define MMFILE_3GP_RATING_TAGBOX_LEN    14
210 #define MMFILE_3GP_CLASS_TAGBOX_LEN     14
211 #define MMFILE_3GP_HANDLER_BOX_LEN      24
212 #define MMFILE_3GP_ID3V2_BOX_LEN        6
213 #define MMFILE_SYNC_LYRIC_INFO_MIN_LEN        5
214
215
216 #define FOURCC(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
217
218 #define GENRE_COUNT     149
219
220 static const char * const MpegAudio_Genre[GENRE_COUNT] = {"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal",
221                                                                                                 "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial",
222                                                                                                 "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
223                                                                                                 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
224                                                                                                 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
225                                                                                                 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
226                                                                                                 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
227                                                                                                 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
228                                                                                                 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
229                                                                                                 "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic",
230                                                                                                 "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove",
231                                                                                                 "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
232                                                                                                 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore",
233                                                                                                 "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian", "Heavy Metal", "Black Metal", "Crossover",
234                                                                                                 "Contemporary", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "Synthpop", "Unknown"
235                                                                                                 };
236
237 static unsigned char gTagJPEGHeader[] = {0xff, 0xd8, 0xff };
238 static unsigned char gTagPNGHeader[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
239
240 typedef struct _mmfileid3taginfo {
241         char name[4];
242         unsigned int int_name;
243         AvID3TagList tag;
244 } MMFILE_ID3TAG_INFO;
245
246 #define ID3TAG_NUM_V22  16
247 #define ID3TAG_NUM_V23  21
248
249 static MMFILE_ID3TAG_INFO tag_info_v22[ID3TAG_NUM_V22] = {
250         {"TT2", 21170, AV_ID3TAG_TITLE},
251         {"TP1", 21041, AV_ID3TAG_ARTIST},
252         {"TP2", 21042, AV_ID3TAG_ALBUM_ARTIST},
253         {"TP3", 21043, AV_ID3TAG_CONDUCTOR},
254         {"TAL", 20588, AV_ID3TAG_ALBUM},
255         {"TYE", 21349, AV_ID3TAG_YEAR},
256         {"COM", 3629, AV_ID3TAG_COMMENT},
257         {"TCO", 20655, AV_ID3TAG_GENRE},
258         {"TRK", 21131, AV_ID3TAG_TRACKNUM},
259         {"PIC", 16739, AV_ID3TAG_PICTURE},
260         {"TCR", 20658, AV_ID3TAG_COPYRIGHT},
261         {"TCM", 20653, AV_ID3TAG_COMPOSER},
262         {"TRD", 21124, AV_ID3TAG_RECDATE},
263 };
264
265 static MMFILE_ID3TAG_INFO tag_info_v23[ID3TAG_NUM_V23] = {
266         {"TIT2", 665266, AV_ID3TAG_TITLE},
267         {"TPE1", 671953, AV_ID3TAG_ARTIST},
268         {"TPE2", 671954, AV_ID3TAG_ALBUM_ARTIST},
269         {"TPE3", 671955, AV_ID3TAG_CONDUCTOR},
270         {"TALB", 656834, AV_ID3TAG_ALBUM},
271         {"TYER", 681202, AV_ID3TAG_YEAR},
272         {"COMM", 114157, AV_ID3TAG_COMMENT},
273         {"TCON", 658990, AV_ID3TAG_GENRE},
274         {"TRCK", 673963, AV_ID3TAG_TRACKNUM},
275         {"APIC", 49507, AV_ID3TAG_PICTURE},
276         {"TCOP", 658992, AV_ID3TAG_COPYRIGHT},
277         {"TCOM", 658989, AV_ID3TAG_COMPOSER},
278         {"TRDA", 660097, AV_ID3TAG_RECDATE},                    /*Recdate for 2.3*/
279         {"USLT", 708052, AV_ID3TAG_UNSYNCLYRICS},
280         {"SYLT", 648660, AV_ID3TAG_SYNCLYRICS},
281         {"TIT1", 665265, AV_ID3TAG_CONTENT_GROUP},      /*Content Group for 2.4*/
282         {"TDRC", 660099, AV_ID3TAG_RECDATE},                    /*Recdate for 2.4*/
283 };
284
285 static int g_junk_counter_limit = 0;
286
287 static int GetStringFromTextTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header, eMMFILE_3GP_TEXT_TAG eTag)
288 {
289         int ret = MMFILE_UTIL_FAIL;    /*fail*/
290         MMFILE_3GP_TEXT_TAGBOX texttag = {0, };
291         int readed = 0;
292         int textBytes = 0;
293         char *temp_text = NULL;
294
295         if (!formatContext || !fp || !basic_header) {
296                 debug_error(DEBUG, "invalid param");
297                 return MMFILE_UTIL_FAIL;
298         }
299
300         textBytes = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_TEXT_TAGBOX_LEN;
301
302         readed = mmfile_read(fp, (unsigned char *)&texttag, MMFILE_3GP_TEXT_TAGBOX_LEN);
303         if (readed != MMFILE_3GP_TEXT_TAGBOX_LEN) {
304                 debug_error(DEBUG, "read text tag header fail");
305                 ret = MMFILE_UTIL_FAIL;
306                 goto exception;
307         }
308
309         if (textBytes <= 1) { /* there exist only 00(null) */
310                 debug_error(DEBUG, "Text is NULL");
311                 goto exception;
312         }
313
314         texttag.text = g_malloc0(textBytes);
315
316         readed = mmfile_read(fp, (unsigned char *)texttag.text, textBytes);
317         if (readed != textBytes) {
318                 debug_error(DEBUG, "read text fail");
319                 ret = MMFILE_UTIL_FAIL;
320                 goto exception;
321         }
322
323         /* check BOM char */
324         if ((texttag.text[0] == 0xFE) && (texttag.text[1] == 0xFF)) {
325                 /* this char is UTF-16 */
326                 temp_text = mmfile_convert_to_utf8((const char *)&texttag.text[2], readed - 2, MMFILE_CODESET_UTF16);
327         } else {
328                 temp_text = g_strdup((const char *)texttag.text);
329         }
330
331         switch (eTag) {
332                 case eMMFILE_3GP_TAG_TITLE: {
333                                 if (!formatContext->title) {
334                                         formatContext->title = g_strdup(temp_text);
335                                 }
336                                 break;
337                         }
338                 case eMMFILE_3GP_TAG_CAPTION: {
339                                 if (!formatContext->description) {
340                                         formatContext->description = g_strdup(temp_text);
341                                 }
342                                 break;
343                         }
344                 case eMMFILE_3GP_TAG_COPYRIGHT: {
345                                 if (!formatContext->copyright) {
346                                         formatContext->copyright = g_strdup(temp_text);
347                                 }
348                                 break;
349                         }
350                 case eMMFILE_3GP_TAG_PERFORMER: {
351                                 if (!formatContext->artist) {
352                                         formatContext->artist = g_strdup(temp_text);
353                                 }
354                                 break;
355                         }
356                 case eMMFILE_3GP_TAG_AUTHOR: {
357                                 if (!formatContext->author) {
358                                         formatContext->author = g_strdup(temp_text);
359                                 }
360                                 break;
361                         }
362                 case eMMFILE_3GP_TAG_GENRE: {
363                                 if (!formatContext->genre) {
364                                         formatContext->genre = g_strdup(temp_text);
365                                 }
366                                 break;
367                         }
368                 default: {
369                                 debug_warning(DEBUG, "Not supported Text Tag type[%d]", eTag);
370                                 break;
371                         }
372         }
373
374         mmfile_free(texttag.text);
375         texttag.text = NULL;
376         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
377
378         mmfile_free(temp_text);
379
380         return MMFILE_UTIL_SUCCESS;
381
382 exception:
383         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
384         mmfile_free(texttag.text);
385
386         return ret;
387 }
388
389 static int GetYearFromYearTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
390 {
391 #define MAX_YEAR_BUFFER 10
392         int readed = 0;
393         MMFILE_3GP_YEAR_TAGBOX yearbox = {0, };
394         char temp_year[MAX_YEAR_BUFFER] = {0, };
395
396         if (!formatContext || !fp || !basic_header) {
397                 debug_error(DEBUG, "invalid param");
398                 return MMFILE_UTIL_FAIL;
399         }
400
401         readed = mmfile_read(fp, (unsigned char *)&yearbox, MMFILE_3GP_YEAR_TAGBOX_LEN);
402         if (readed != MMFILE_3GP_YEAR_TAGBOX_LEN) {
403                 debug_error(DEBUG, "read yeartag header fail");
404                 goto exception;
405         }
406
407         if (!formatContext->year) {
408                 yearbox.year = mmfile_io_be_int16(yearbox.year);
409                 snprintf(temp_year, MAX_YEAR_BUFFER, "%d", yearbox.year);
410                 temp_year[MAX_YEAR_BUFFER - 1] = '\0';
411                 formatContext->year = g_strdup((const char *)temp_year);
412         }
413
414         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
415         return MMFILE_UTIL_SUCCESS;
416
417 exception:
418         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
419
420         return MMFILE_UTIL_FAIL;
421 }
422
423 static int GetAlbumFromAlbumTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
424 {
425         int albumTitleLen = 0;
426         char *temp_text = NULL;
427         int readed = 0;
428         int trackFlags = 0;
429         MMFILE_3GP_ALBUM_TAGBOX albumbox = {0, };
430
431         if (!formatContext || !fp || !basic_header) {
432                 debug_error(DEBUG, "invalid param");
433                 return MMFILE_UTIL_FAIL;
434         }
435
436         readed = mmfile_read(fp, (unsigned char *)&albumbox, MMFILE_3GP_ALBUM_TAGBOX_LEN);
437         if (readed != MMFILE_3GP_ALBUM_TAGBOX_LEN) {
438                 debug_error(DEBUG, "read albumtag header fail");
439                 goto exception;
440         }
441
442         albumTitleLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ALBUM_TAGBOX_LEN - 1; /* 1: track number */
443         if (albumTitleLen > 1) { /* there exist only 00(null) */
444                 debug_msg(RELEASE, "albumTitleLen=%d", albumTitleLen);
445
446                 albumbox.albumtile = g_malloc0(albumTitleLen + 1);  /* 1: for null char */
447
448                 readed = mmfile_read(fp, (unsigned char *)albumbox.albumtile, albumTitleLen);
449                 if (readed != albumTitleLen) {
450                         debug_error(DEBUG, "read album title fail");
451                         goto exception;
452                 }
453
454                 if (albumbox.albumtile[albumTitleLen - 1] == '\0') { /* there exist track number */
455                         trackFlags = 1;
456                 } else {
457                         trackFlags = 0;
458                         readed = mmfile_read(fp, (unsigned char *)&(albumbox.albumtile[albumTitleLen]), 1);
459                         if (readed != 1) {
460                                 debug_error(DEBUG, "read album title fail");
461                                 goto exception;
462                         }
463                         albumbox.albumtile[albumTitleLen] = '\0';
464                 }
465
466                 /* check BOM char */
467                 if ((albumbox.albumtile[0] == 0xFE) && (albumbox.albumtile[1] == 0xFF)) {
468                         /* this char is UTF-16 */
469                         temp_text = mmfile_convert_to_utf8((const char *)&albumbox.albumtile[2], readed - 2, MMFILE_CODESET_UTF16);
470                 } else {
471                         temp_text = g_strdup((const char *)albumbox.albumtile);
472                 }
473
474                 if (!formatContext->album)
475                         formatContext->album = temp_text;
476                 else
477                         mmfile_free(temp_text);
478
479                 debug_msg(RELEASE, "formatContext->album=%s, strlen=%zu", formatContext->album, strlen(formatContext->album));
480         }
481
482         if (trackFlags) {
483                 readed = mmfile_read(fp, (unsigned char *)&albumbox.trackNumber, 1);
484                 if (readed != 1) {
485                         debug_error(DEBUG, "read track number fail");
486                         goto exception;
487                 }
488
489                 if (formatContext->tagTrackNum == 0) {
490                         char tracknum[10] = {0, };
491                         snprintf(tracknum, 10, "%d", albumbox.trackNumber);
492                         tracknum[9] = '\0';
493                         formatContext->tagTrackNum = g_strdup((const char *)tracknum);
494                 }
495         }
496
497         mmfile_free(albumbox.albumtile);
498         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
499
500         return MMFILE_UTIL_SUCCESS;
501
502 exception:
503         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
504         mmfile_free(albumbox.albumtile);
505
506         return MMFILE_UTIL_FAIL;
507 }
508
509 static int GetRatingFromRatingTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
510 {
511         int readed = 0;
512         int  ratinginfoLen = 0;
513         char *temp_text = NULL;
514
515         MMFILE_3GP_RATING_TAGBOX ratingTag = {0, };
516
517         if (!formatContext || !fp || !basic_header) {
518                 debug_error(DEBUG, "invalid param");
519                 return MMFILE_UTIL_FAIL;
520         }
521
522         readed = mmfile_read(fp, (unsigned char *)&ratingTag, MMFILE_3GP_RATING_TAGBOX_LEN);
523         if (readed != MMFILE_3GP_RATING_TAGBOX_LEN) {
524                 debug_error(DEBUG, "read rating tag header fail");
525                 goto exception;
526         }
527
528         ratinginfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_RATING_TAGBOX_LEN;
529
530         if (ratinginfoLen == 1) {
531                 debug_error(DEBUG, "Rating Text is NULL");
532                 goto exception;
533         }
534
535         ratingTag.ratingInfo = g_malloc0(ratinginfoLen);
536
537         readed = mmfile_read(fp, (unsigned char *)ratingTag.ratingInfo, ratinginfoLen);
538         if (readed != ratinginfoLen) {
539                 debug_error(DEBUG, "read rating info string fail");
540                 goto exception;
541         }
542
543         /* check BOM char */
544         if ((ratingTag.ratingInfo[0] == 0xFE) && (ratingTag.ratingInfo[1] == 0xFF)) {
545                 /* this char is UTF-16 */
546                 temp_text = mmfile_convert_to_utf8((const char *)&ratingTag.ratingInfo[2], readed - 2, MMFILE_CODESET_UTF16);
547         } else {
548                 temp_text = g_strdup((const char *)ratingTag.ratingInfo);
549         }
550
551         if (!formatContext->rating) {
552                 formatContext->rating = temp_text;
553         } else {
554                 mmfile_free(temp_text);
555         }
556
557         mmfile_free(ratingTag.ratingInfo);
558         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
559
560         return MMFILE_UTIL_SUCCESS;
561
562 exception:
563         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
564         mmfile_free(ratingTag.ratingInfo);
565
566         return MMFILE_UTIL_FAIL;
567 }
568
569
570 static int GetClassficationFromClsfTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
571 {
572         int classinfoLen = 0;
573         int readed = 0;
574         char *temp_text = NULL;
575         MMFILE_3GP_CLASSIFICATION_TAGBOX classTag = {0, };
576
577         if (!formatContext || !fp || !basic_header) {
578                 debug_error(DEBUG, "invalid param");
579                 return MMFILE_UTIL_FAIL;
580         }
581
582         readed = mmfile_read(fp, (unsigned char *)&classTag, MMFILE_3GP_CLASS_TAGBOX_LEN);
583         if (readed != MMFILE_3GP_CLASS_TAGBOX_LEN) {
584                 debug_error(DEBUG, "read classification tag header fail");
585                 goto exception;
586         }
587
588
589         classinfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_CLASS_TAGBOX_LEN;
590         if (classinfoLen == 1) {
591                 debug_error(DEBUG, "Classification Text is NULL");
592                 goto exception;
593         }
594
595         classTag.classificationInfo = g_malloc0(classinfoLen);
596
597         readed = mmfile_read(fp, (unsigned char *)classTag.classificationInfo, classinfoLen);
598         if (readed != classinfoLen) {
599                 debug_error(DEBUG, "read class info string fail");
600                 goto exception;
601         }
602
603         /* check BOM char */
604         if ((classTag.classificationInfo[0] == 0xFE) && (classTag.classificationInfo[1] == 0xFF)) {
605                 /* this char is UTF-16 */
606                 temp_text = mmfile_convert_to_utf8((const char *)&classTag.classificationInfo[2], readed - 2, MMFILE_CODESET_UTF16);
607         } else {
608                 temp_text = g_strdup((const char *)classTag.classificationInfo);
609         }
610
611         if (!formatContext->classification) {
612                 formatContext->classification = temp_text;
613         } else {
614                 mmfile_free(temp_text);
615         }
616
617         mmfile_free(classTag.classificationInfo);
618         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
619
620         return MMFILE_UTIL_SUCCESS;
621
622 exception:
623         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
624         mmfile_free(classTag.classificationInfo);
625
626         return MMFILE_UTIL_FAIL;
627 }
628
629 /**
630  * The Location Information box
631  * --------------------+-------------------+-----------------------------------+------
632  * Field                                Type                            Details                                                         Value
633  * --------------------+-------------------+-----------------------------------+------
634  * BoxHeader.Size               Unsigned int(32)
635  * BoxHeader.Type               Unsigned int(32)                                                                                'loci'
636  * BoxHeader.Version    Unsigned int(8)                                                                                 0
637  * BoxHeader.Flags              Bit(24)                                                                                                 0
638  * Pad                                  Bit(1)                                                                                                  0
639  * Language                             Unsigned int(5)[3]      Packed ISO-639-2/T language code
640  * Name                                 String                          Text of place name
641  * Role                                 Unsigned int(8)         Non-negative value indicating role
642  *                                                                                      of location
643  * Longitude                    Unsigned int(32)        Fixed-point value of the longitude
644  * Latitude                             Unsigned int(32)        Fixed-point value of the latitude
645  * Altitude                             Unsigned int(32)        Fixed-point value of the Altitude
646  * Astronomical_body    String                          Text of astronomical body
647  * Additional_notes             String                          Text of additional location-related
648  *                                                                                      information
649  * --------------------+-------------------+-----------------------------------+------
650  */
651 static int _get_char_position(unsigned char *src, char ch, int max)
652 {
653         int i;
654         for (i = 0; i < max; i++) {
655                 if (*(src + i) == ch)
656                         return i;
657         }
658
659         return -1;
660 }
661
662 static int GetLocationFromLociTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
663 {
664
665         MMFILE_3GP_LOCATION_TAGBOX lociTag = {0, };
666         int readed = 0;
667         int bufferLen = 0;
668         unsigned char *buffer = NULL;
669         unsigned char *p = NULL;
670         int pos = 0;
671         unsigned int name_sz = 0;
672         unsigned int astro_sz = 0;
673
674         int ilong, ilati, ialti;
675         float flong, flati, falti;
676
677
678         if (!formatContext || !fp || !basic_header) {
679                 debug_error(DEBUG, "invalid param");
680                 return MMFILE_UTIL_FAIL;
681         }
682
683         readed = mmfile_read(fp, (unsigned char *)&lociTag, 6);  /*6 = version + flag + pad + language */
684         if (readed != 6) {
685                 debug_error(DEBUG, "read location tag header fail");
686                 goto exception;
687         }
688
689         /*buffer len = name + role + ... + additional notes length */
690         bufferLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - 6;
691         if (bufferLen < 1) {
692                 debug_error(DEBUG, "too small buffer");
693                 goto exception;
694         }
695
696         buffer = g_malloc0(bufferLen);
697
698         readed = mmfile_read(fp, (unsigned char *)buffer, bufferLen);
699         if (readed != bufferLen) {
700                 debug_error(DEBUG, "read location tag fail");
701                 goto exception;
702         }
703         p = buffer;
704
705         /*name*/
706         pos = _get_char_position(p, '\0', readed - (1 + 4 + 4 + 4 + 2));
707         if (pos >= 0) {
708                 if (p[0] == 0xFE && p[1] == 0xFF) {
709                         lociTag.name = (unsigned char *)mmfile_convert_to_utf8((const char *)(p + 2), pos - 2, MMFILE_CODESET_UTF16);
710                 } else {
711                         lociTag.name = (unsigned char *)g_strdup((const char *)p);
712                 }
713         } else {
714                 goto exception;
715         }
716         name_sz = pos + 1;
717         p += (pos + 1);
718
719         /*role*/
720         lociTag.role = *p;
721         p++;
722
723         debug_msg(RELEASE, "long: 0x%02X 0x%02X 0x%02X 0x%02X ", *(p + 0), *(p + 1), *(p + 2), *(p + 3));
724         debug_msg(RELEASE, "lati: 0x%02X 0x%02X 0x%02X 0x%02X ", *(p + 4), *(p + 5), *(p + 6), *(p + 7));
725         debug_msg(RELEASE, "alti: 0x%02X 0x%02X 0x%02X 0x%02X ", *(p + 8), *(p + 9), *(p + 10), *(p + 11));
726
727         ilong = mmfile_io_be_uint32(*(unsigned int *)p);
728         ilati = mmfile_io_be_uint32(*(unsigned int *)(p + 4));
729         ialti = mmfile_io_be_uint32(*(unsigned int *)(p + 8));
730
731         flong = (float)ilong / (1 << 16);
732         flati = (float)ilati / (1 << 16);
733         falti = (float)ialti / (1 << 16);
734
735         /*longitude*/
736         lociTag.longitude = flong;
737         /*latitude*/
738         lociTag.latitude = flati;
739         /*altitude*/
740         lociTag.altitude = falti;
741
742         p += 12;
743
744         /*astronomical body*/
745         pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + 1));
746         if (pos >= 0) {
747                 if (p[0] == 0xFE && p[1] == 0xFF) {
748                         lociTag.astronomical_body = (unsigned char *)mmfile_convert_to_utf8((const char *)(p + 2), pos - 2, MMFILE_CODESET_UTF16);
749                 } else {
750                         lociTag.astronomical_body = (unsigned char *)g_strdup((const char *)p);
751                 }
752         } else {
753                 goto exception;
754         }
755         astro_sz = pos + 1;
756         p += (pos + 1);
757
758         /*additional notes*/
759         pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + astro_sz));
760         if (pos >= 0) {
761                 if (p[0] == 0xFE && p[1] == 0xFF) {
762                         lociTag.additional_notes = (unsigned char *)mmfile_convert_to_utf8((const char *)(p + 2), pos - 2, MMFILE_CODESET_UTF16);
763                 } else {
764                         lociTag.additional_notes = (unsigned char *)g_strdup((const char *)p);
765                 }
766         } else {
767                 goto exception;
768         }
769
770         debug_msg(RELEASE, "** Location Information **");
771         debug_msg(RELEASE, "Name             : %s", lociTag.name);
772         debug_msg(RELEASE, "Role             : %d (0: shooting, 1: real, 2: fictional, other: reserved)", lociTag.role);
773         debug_msg(RELEASE, "Longitude        : %16.16f", lociTag.longitude);
774         debug_msg(RELEASE, "Latitude         : %16.16f", lociTag.latitude);
775         debug_msg(RELEASE, "Altitude         : %16.16f", lociTag.altitude);
776         debug_msg(RELEASE, "Astronomical body: %s", lociTag.astronomical_body);
777         debug_msg(RELEASE, "Additional notes : %s", lociTag.additional_notes);
778
779         formatContext->longitude = lociTag.longitude;
780         formatContext->latitude = lociTag.latitude;
781         formatContext->altitude = lociTag.altitude;
782
783         mmfile_free(buffer);
784         mmfile_free(lociTag.name);
785         mmfile_free(lociTag.astronomical_body);
786         mmfile_free(lociTag.additional_notes);
787
788         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
789         return MMFILE_UTIL_SUCCESS;
790
791 exception:
792         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
793         mmfile_free(buffer);
794         mmfile_free(lociTag.name);
795         mmfile_free(lociTag.astronomical_body);
796         mmfile_free(lociTag.additional_notes);
797
798         return MMFILE_UTIL_FAIL;
799 }
800
801 static int GetSAUTInfoFromSMTATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
802 {
803         MMFILE_M4A_SMTA_TAGBOX smtaTag = {0, };
804         int readed = 0;
805
806         if (!formatContext || !fp || !basic_header) {
807                 debug_error(DEBUG, "invalid param");
808                 return MMFILE_UTIL_FAIL;
809         }
810
811         readed = mmfile_read(fp, (unsigned char *)&smtaTag, sizeof(MMFILE_M4A_SMTA_TAGBOX));
812         if (readed != sizeof(MMFILE_M4A_SMTA_TAGBOX)) {
813                 debug_error(DEBUG, "read smta tag header fail");
814                 goto exception;
815         }
816
817         smtaTag.length = mmfile_io_be_uint32(smtaTag.length);
818         smtaTag.value = mmfile_io_be_uint32(smtaTag.value);
819
820         debug_msg(RELEASE, "Len : 0x%x", smtaTag.length);
821         debug_msg(RELEASE, "Saut : 0x%x 0x%x 0x%x 0x%x", smtaTag.saut[0], smtaTag.saut[1], smtaTag.saut[2], smtaTag.saut[3]);
822         debug_msg(RELEASE, "Value : 0x%x", smtaTag.value);
823
824 /*
825         Samsung Metadata
826         0: None-mode
827         1: 360 normal
828         2: 360 timelapse
829         3: 180 normal
830         4: 180 timelapse
831         5: 360 looping mode
832         6: 180 looping mode
833         7: 360 slowmotion mode
834         8: 180 slowmotion mode
835 */
836         if (smtaTag.saut[0] == 's'
837             && smtaTag.saut[1] == 'a'
838             && smtaTag.saut[2] == 'u'
839             && smtaTag.saut[3] == 't') {
840                 if (smtaTag.value == 0x01) {
841                         debug_msg(RELEASE, "This has saut tag and valid value");
842                         formatContext->smta = 1;
843                 } else if (smtaTag.value == 0x02) {
844                         debug_msg(RELEASE, "This has saut tag and valid value");
845                         formatContext->smta = 2;
846                 } else {
847                         debug_error(DEBUG, "This has saut tag but invalid value");
848                         goto exception;
849                 }
850         } else {
851                 debug_error(DEBUG, "This hasn't saut tag and valid value");
852                 goto exception;
853         }
854
855         return MMFILE_UTIL_SUCCESS;
856
857 exception:
858         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
859
860         return MMFILE_UTIL_FAIL;
861 }
862
863 static int GetSA3DInfoFromMP4ATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
864 {
865         if (!formatContext || !fp || !basic_header) {
866                 debug_error(DEBUG, "invalid param");
867                 return MMFILE_UTIL_FAIL;
868         }
869
870         unsigned char *buffer;
871         int readed = 0;
872         bool is_SA3D_present = false;
873         unsigned int i = 0;
874         MMFILE_MP4A_SA3D_TAGBOX sa3dTag = {0, };
875
876         formatContext->ambisonicType = MMFILE_AMBISONIC_TYPE_UNKNOWN;
877         formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_UNKNOWN;
878         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_UNKNOWN;
879
880         mmfile_seek(fp, basic_header->start_offset, SEEK_SET);
881
882         buffer = calloc(basic_header->size + 1, sizeof(unsigned char));
883         if (!buffer) {
884                 debug_error(DEBUG, "calloc failed ");
885                 goto exception;
886         }
887
888         readed = mmfile_read(fp, buffer, basic_header->size);
889         if (readed != (int)basic_header->size) {
890                 debug_error(DEBUG, "read mp4a box failed");
891                 goto exception;
892         }
893
894         for (i = 0; i + 3 < basic_header->size; ++i)
895                 if (buffer[i] == 'S' && buffer[i + 1] == 'A' && buffer[i + 2] == '3' && buffer[i + 3] == 'D') {
896                         debug_warning(DEBUG, "SA3D data found at offset %d bytes", i);
897                         is_SA3D_present = true;
898                         break;
899                 }
900
901         if (!is_SA3D_present) {
902                 debug_warning(DEBUG, "No SA3D box found");
903                 goto exception;
904         }
905
906         mmfile_seek(fp, basic_header->start_offset + i + 4, SEEK_SET);
907
908         readed = mmfile_read(fp, (unsigned char *)&sa3dTag, sizeof(MMFILE_MP4A_SA3D_TAGBOX));
909         if (readed != sizeof(MMFILE_MP4A_SA3D_TAGBOX)) {
910                 debug_error(DEBUG, "read SA3D tag header fail");
911                 goto exception;
912         }
913
914         sa3dTag.ambisonic_order = mmfile_io_be_uint32(sa3dTag.ambisonic_order);
915         sa3dTag.num_channels = mmfile_io_be_uint32(sa3dTag.num_channels);
916         for (i = 0; i < sa3dTag.num_channels; ++i)
917                 sa3dTag.channel_map[i] = mmfile_io_be_uint32(sa3dTag.channel_map[i]);
918
919         debug_msg(RELEASE, "sa3dTag.version = %d", sa3dTag.version);
920         debug_msg(RELEASE, "sa3dTag.ambisonic_type = %d", sa3dTag.ambisonic_type);
921         debug_msg(RELEASE, "sa3dTag.ambisonic_order = %d", sa3dTag.ambisonic_order);
922         debug_msg(RELEASE, "sa3dTag.ambisonic_channel_ordering = %d", sa3dTag.ambisonic_channel_ordering);
923         debug_msg(RELEASE, "sa3dTag.ambisonic_normalization = %d", sa3dTag.ambisonic_normalization);
924         debug_msg(RELEASE, "sa3dTag.num_channels = %d", sa3dTag.num_channels);
925         for (i = 0; i < sa3dTag.num_channels; ++i)
926                 debug_msg(RELEASE, "sa3dTag.channel_map[%d] = %d", i, sa3dTag.channel_map[i]);
927
928         if (sa3dTag.version != RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
929                 debug_error(DEBUG, "SA3D tag box version is unsupported");
930                 goto exception;
931         } else {
932                 if (sa3dTag.ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
933                         formatContext->ambisonicType = MMFILE_AMBISONIC_TYPE_PERIPHONIC;
934
935                 switch (sa3dTag.ambisonic_order) {
936                         case MMFILE_AMBISONIC_ORDER_FOA: {
937                                         if (sa3dTag.num_channels == 4) {
938                                                 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_FOA;
939
940                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
941                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
942                                                                 (sa3dTag.channel_map[0] == 0) &&
943                                                                 (sa3dTag.channel_map[1] == 1) &&
944                                                                 (sa3dTag.channel_map[2] == 2) &&
945                                                                 (sa3dTag.channel_map[3] == 3))
946                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
947
948                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
949                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
950                                                                 (sa3dTag.channel_map[0] == 0) &&
951                                                                 (sa3dTag.channel_map[1] == 3) &&
952                                                                 (sa3dTag.channel_map[2] == 1) &&
953                                                                 (sa3dTag.channel_map[3] == 2))
954                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
955                                         } else {
956                                                 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond");
957                                                 goto exception;
958                                         }
959
960                                         break;
961                                 }
962                         case MMFILE_AMBISONIC_ORDER_SOA: {
963                                         if (sa3dTag.num_channels == 9) {
964                                                 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_SOA;
965
966                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
967                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
968                                                                 (sa3dTag.channel_map[0] == 0) &&
969                                                                 (sa3dTag.channel_map[1] == 1) &&
970                                                                 (sa3dTag.channel_map[2] == 2) &&
971                                                                 (sa3dTag.channel_map[3] == 3) &&
972                                                                 (sa3dTag.channel_map[4] == 4) &&
973                                                                 (sa3dTag.channel_map[5] == 5) &&
974                                                                 (sa3dTag.channel_map[6] == 6) &&
975                                                                 (sa3dTag.channel_map[7] == 7) &&
976                                                                 (sa3dTag.channel_map[8] == 8))
977                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
978
979                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
980                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
981                                                                 (sa3dTag.channel_map[0] == 0) &&
982                                                                 (sa3dTag.channel_map[1] == 3) &&
983                                                                 (sa3dTag.channel_map[2] == 1) &&
984                                                                 (sa3dTag.channel_map[3] == 2) &&
985                                                                 (sa3dTag.channel_map[4] == 6) &&
986                                                                 (sa3dTag.channel_map[5] == 7) &&
987                                                                 (sa3dTag.channel_map[6] == 5) &&
988                                                                 (sa3dTag.channel_map[7] == 8) &&
989                                                                 (sa3dTag.channel_map[8] == 4))
990                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
991                                         } else {
992                                                 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond");
993                                                 goto exception;
994                                         }
995
996                                         break;
997                                 }
998
999                         case MMFILE_AMBISONIC_ORDER_TOA: {
1000                                         if (sa3dTag.num_channels == 16) {
1001                                                 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_TOA;
1002
1003                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
1004                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
1005                                                                 (sa3dTag.channel_map[0] == 0) &&
1006                                                                 (sa3dTag.channel_map[1] == 1) &&
1007                                                                 (sa3dTag.channel_map[2] == 2) &&
1008                                                                 (sa3dTag.channel_map[3] == 3) &&
1009                                                                 (sa3dTag.channel_map[4] == 4) &&
1010                                                                 (sa3dTag.channel_map[5] == 5) &&
1011                                                                 (sa3dTag.channel_map[6] == 6) &&
1012                                                                 (sa3dTag.channel_map[7] == 7) &&
1013                                                                 (sa3dTag.channel_map[8] == 8) &&
1014                                                                 (sa3dTag.channel_map[9] == 9) &&
1015                                                                 (sa3dTag.channel_map[10] == 10) &&
1016                                                                 (sa3dTag.channel_map[11] == 11) &&
1017                                                                 (sa3dTag.channel_map[12] == 12) &&
1018                                                                 (sa3dTag.channel_map[13] == 13) &&
1019                                                                 (sa3dTag.channel_map[14] == 14) &&
1020                                                                 (sa3dTag.channel_map[15] == 15))
1021                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
1022
1023                                                 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
1024                                                                 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
1025                                                                 (sa3dTag.channel_map[0] == 0) &&
1026                                                                 (sa3dTag.channel_map[1] == 3) &&
1027                                                                 (sa3dTag.channel_map[2] == 1) &&
1028                                                                 (sa3dTag.channel_map[3] == 2) &&
1029                                                                 (sa3dTag.channel_map[4] == 6) &&
1030                                                                 (sa3dTag.channel_map[5] == 7) &&
1031                                                                 (sa3dTag.channel_map[6] == 5) &&
1032                                                                 (sa3dTag.channel_map[7] == 8) &&
1033                                                                 (sa3dTag.channel_map[8] == 4) &&
1034                                                                 (sa3dTag.channel_map[9] == 12) &&
1035                                                                 (sa3dTag.channel_map[10] == 13) &&
1036                                                                 (sa3dTag.channel_map[11] == 11) &&
1037                                                                 (sa3dTag.channel_map[12] == 14) &&
1038                                                                 (sa3dTag.channel_map[13] == 10) &&
1039                                                                 (sa3dTag.channel_map[14] == 15) &&
1040                                                                 (sa3dTag.channel_map[15] == 9))
1041                                                         formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
1042                                         } else {
1043                                                 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond");
1044                                                 goto exception;
1045                                         }
1046
1047                                         break;
1048                                 }
1049
1050                         default: {
1051                                         debug_warning(DEBUG, "Ambisonic order or format is not supported: ambix or amb formats up to 3rd order were expected.");
1052                                         goto exception;
1053                                         break;
1054                                 }
1055                 }
1056
1057                 debug_msg(RELEASE, "formatContext->ambisonic_type = %d", formatContext->ambisonicType);
1058                 debug_msg(RELEASE, "formatContext->ambisonic_order = %d", formatContext->ambisonicOrder);
1059                 debug_msg(RELEASE, "formatContext->ambisonic_format = %d", formatContext->ambisonicFormat);
1060         }
1061
1062         return MMFILE_UTIL_SUCCESS;
1063
1064 exception:
1065         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1066
1067         return MMFILE_UTIL_FAIL;
1068 }
1069
1070 static int ParseSt3dData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset)
1071 {
1072         uint8_t stereo_mode = INVALID_UINT8_VALUE;
1073         unsigned int readed = 0;
1074
1075         mmfile_seek(fp, start_offset, SEEK_SET);
1076
1077         readed = mmfile_read(fp, (unsigned char *)&stereo_mode, sizeof(uint8_t));
1078         if (readed != sizeof(uint8_t)) {
1079                 debug_error(DEBUG, "read st3d tag header fail");
1080                 return MMFILE_UTIL_FAIL;
1081         }
1082
1083         formatContext->stereoModeV2 = stereo_mode;
1084
1085         return MMFILE_UTIL_SUCCESS;
1086 }
1087
1088 static int ParseSvhdData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset, unsigned int box_size)
1089 {
1090         unsigned int readed = 0;
1091
1092         formatContext->metadataSourceV2 = (char *)calloc(1, box_size);
1093         if (!formatContext->metadataSourceV2) {
1094                 debug_error(DEBUG, "Calloc failed");
1095                 return MMFILE_UTIL_FAIL;
1096         }
1097
1098         mmfile_seek(fp, start_offset, SEEK_SET);
1099         readed = mmfile_read(fp, (unsigned char *)formatContext->metadataSourceV2, box_size);
1100         if (readed != box_size) {
1101                 debug_error(DEBUG, "read svhd tag header fail");
1102                 if (formatContext->metadataSourceV2)
1103                         free(formatContext->metadataSourceV2);
1104                 return MMFILE_UTIL_FAIL;
1105         }
1106
1107         return MMFILE_UTIL_SUCCESS;
1108 }
1109
1110 static int ParseProjData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset)
1111 {
1112         unsigned int readed = 0;
1113         typedef struct proj_box_data_s {
1114                 uint32_t proj_type;
1115                 uint8_t version;
1116                 uint8_t flags[3];
1117         } __attribute__((aligned(1), packed)) proj_box_data;
1118
1119         typedef struct prhd_box_data_s {
1120                 uint32_t projection_pose_yaw;
1121                 uint32_t projection_pose_pitch;
1122                 uint32_t projection_pose_roll;
1123         } prhd_box_data;
1124
1125         typedef struct equi_box_data_s {
1126                 uint32_t projection_bounds_top;
1127                 uint32_t projection_bounds_bottom;
1128                 uint32_t projection_bounds_left;
1129                 uint32_t projection_bounds_right;
1130         } equi_box_data;
1131
1132         typedef struct cbmp_box_data_s {
1133                 uint32_t layout;
1134                 uint32_t padding;
1135         } cbmp_box_data;
1136
1137
1138         proj_box_data proj_data;
1139         proj_data.proj_type = INVALID_UINT_VALUE;
1140
1141         prhd_box_data prhd_data;
1142         prhd_data.projection_pose_yaw = INVALID_UINT_VALUE;
1143         prhd_data.projection_pose_pitch = INVALID_UINT_VALUE;
1144         prhd_data.projection_pose_roll = INVALID_UINT_VALUE;
1145
1146         equi_box_data equi_data;
1147         equi_data.projection_bounds_top = INVALID_UINT_VALUE;
1148         equi_data.projection_bounds_bottom = INVALID_UINT_VALUE;
1149         equi_data.projection_bounds_left = INVALID_UINT_VALUE;
1150         equi_data.projection_bounds_right = INVALID_UINT_VALUE;
1151
1152         cbmp_box_data cbmp_data;
1153         cbmp_data.layout = INVALID_UINT_VALUE;
1154         cbmp_data.padding = INVALID_UINT_VALUE;
1155
1156         mmfile_seek(fp, start_offset, SEEK_SET);
1157
1158         readed = mmfile_read(fp, (unsigned char *)&proj_data, sizeof(proj_box_data));
1159         if (readed != sizeof(proj_box_data)) {
1160                 debug_error(DEBUG, "read of proj box failed");
1161                 return MMFILE_UTIL_FAIL;
1162         }
1163
1164         formatContext->projTypeV2 = mmfile_io_be_uint32(proj_data.proj_type);
1165
1166         debug_error(DEBUG, "formatContext->projTypeV2 = %d", formatContext->projTypeV2);
1167         debug_error(DEBUG, "proj_data.version = %d", proj_data.version);
1168         debug_error(DEBUG, "proj_data.flags = %d", ((uint32_t)proj_data.flags[0] << 16) +
1169                         ((uint32_t)proj_data.flags[1] << 8) + (uint32_t)proj_data.flags[2]);
1170
1171         mmfile_seek(fp, sizeof(proj_box_data), SEEK_CUR);
1172         readed = mmfile_read(fp, (unsigned char *)&prhd_data, sizeof(prhd_box_data));
1173         if (readed != sizeof(prhd_box_data)) {
1174                 debug_error(DEBUG, "read of prhd box failed");
1175                 return MMFILE_UTIL_FAIL;
1176         }
1177
1178         formatContext->poseYawV2 = mmfile_io_be_uint32(prhd_data.projection_pose_yaw);
1179         formatContext->posePitchV2 = mmfile_io_be_uint32(prhd_data.projection_pose_pitch);
1180         formatContext->poseRollV2 = mmfile_io_be_uint32(prhd_data.projection_pose_roll);
1181
1182         debug_error(DEBUG, "formatContext->poseYawV2 = %d", formatContext->poseYawV2);
1183         debug_error(DEBUG, "formatContext->posePitchV2 = %d", formatContext->posePitchV2);
1184         debug_error(DEBUG, "formatContext->poseRollV2 = %d", formatContext->poseRollV2);
1185
1186         if (formatContext->projTypeV2 == PROJECTION_TYPE_EQUI) {
1187                 debug_msg(RELEASE, "Projection type is Equirectangular");
1188                 mmfile_seek(fp, 8, SEEK_CUR); /* 8 = 4 (for size) + 4 (fourcc) */
1189                 readed = mmfile_read(fp, (unsigned char *)&equi_data, sizeof(equi_box_data));
1190                 if (readed != sizeof(equi_box_data)) {
1191                         debug_error(DEBUG, "read of equi box failed");
1192                         return MMFILE_UTIL_FAIL;
1193                 }
1194
1195                 formatContext->equiBoundsTopV2 = mmfile_io_be_uint32(equi_data.projection_bounds_top);
1196                 formatContext->equiBoundsBottomV2 = mmfile_io_be_uint32(equi_data.projection_bounds_bottom);
1197                 formatContext->equiBoundsLeftV2 = mmfile_io_be_uint32(equi_data.projection_bounds_left);
1198                 formatContext->equiBoundsRightV2 = mmfile_io_be_uint32(equi_data.projection_bounds_right);
1199
1200                 debug_error(DEBUG, "formatContext->equiBoundsTopV2 = %d", formatContext->equiBoundsTopV2);
1201                 debug_error(DEBUG, "formatContext->equiBoundsBottomV2 = %d", formatContext->equiBoundsBottomV2);
1202                 debug_error(DEBUG, "formatContext->equiBoundsLeftV2 = %d", formatContext->equiBoundsLeftV2);
1203                 debug_error(DEBUG, "formatContext->equiBoundsRightV2 = %d", formatContext->equiBoundsRightV2);
1204
1205         } else if (formatContext->projTypeV2 == PROJECTION_TYPE_CBMP) {
1206                 debug_msg(RELEASE, "Projection type is Cubemap");
1207                 mmfile_seek(fp, 8, SEEK_CUR); /* 8 = 4 (for size) + 4 (fourcc) */
1208                 readed = mmfile_read(fp, (unsigned char *)&cbmp_data, sizeof(cbmp_box_data));
1209                 if (readed != sizeof(cbmp_box_data)) {
1210                         debug_error(DEBUG, "read of cbmp box failed");
1211                         return MMFILE_UTIL_FAIL;
1212                 }
1213
1214                 formatContext->cbmpLayoutV2 = mmfile_io_be_uint32(cbmp_data.layout);
1215                 formatContext->cbmpPaddingV2 = mmfile_io_be_uint32(cbmp_data.padding);
1216
1217                 debug_error(DEBUG, "formatContext->cbmpLayoutV2 = %d", formatContext->cbmpLayoutV2);
1218                 debug_error(DEBUG, "formatContext->cbmpPaddingV2 = %d", formatContext->cbmpPaddingV2);
1219
1220         } else {
1221                 debug_msg(RELEASE, "Projection type is %d (unknown)", proj_data.proj_type);
1222                 return MMFILE_UTIL_FAIL;
1223         }
1224
1225         return MMFILE_UTIL_SUCCESS;
1226 }
1227
1228 static int GetVideoV2MetadataFromAvc1TagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1229 {
1230         if (!formatContext || !fp || !basic_header) {
1231                 debug_error(DEBUG, "invalid param");
1232                 return MMFILE_UTIL_FAIL;
1233         }
1234
1235         unsigned char *buffer;
1236         int readed = 0;
1237         unsigned int i = 0;
1238
1239         formatContext->stereoModeV2 = INVALID_UINT_VALUE;
1240         formatContext->metadataSourceV2 = NULL;
1241         formatContext->projTypeV2 = INVALID_UINT_VALUE;
1242         formatContext->poseYawV2 = INVALID_UINT_VALUE;
1243         formatContext->posePitchV2 = INVALID_UINT_VALUE;
1244         formatContext->poseRollV2 = INVALID_UINT_VALUE;
1245         formatContext->cbmpLayoutV2 = INVALID_UINT_VALUE;
1246         formatContext->cbmpPaddingV2 = INVALID_UINT_VALUE;
1247         formatContext->equiBoundsTopV2 = INVALID_UINT_VALUE;
1248         formatContext->equiBoundsBottomV2 = INVALID_UINT_VALUE;
1249         formatContext->equiBoundsLeftV2 = INVALID_UINT_VALUE;
1250         formatContext->equiBoundsRightV2 = INVALID_UINT_VALUE;
1251
1252         mmfile_seek(fp, basic_header->start_offset, SEEK_SET);
1253
1254         buffer = calloc(basic_header->size + 1, sizeof(unsigned char));
1255         if (!buffer) {
1256                 debug_error(DEBUG, "calloc failed ");
1257                 goto exception;
1258         }
1259
1260         readed = mmfile_read(fp, buffer, basic_header->size);
1261         if (readed != (int)basic_header->size) {
1262                 debug_error(DEBUG, "read st3d box failed");
1263                 goto exception;
1264         }
1265
1266         for (i = 0; i + 3 < basic_header->size; ++i) {
1267                 if ((buffer[i] == 's' && buffer[i + 1] == 't' && buffer[i + 2] == '3' && buffer[i + 3] == 'd') && (formatContext->stereoModeV2 == INVALID_UINT_VALUE)) {
1268                         debug_warning(DEBUG, "st3d data found at offset %lld", basic_header->start_offset + i);
1269                         ParseSt3dData(formatContext, fp, basic_header->start_offset + i + 4);
1270                         debug_msg(RELEASE, "formatContext->stereoModeV2 = %d", formatContext->stereoModeV2);
1271                 }
1272                 if (buffer[i] == 's' && buffer[i + 1] == 'v' && buffer[i + 2] == '3' && buffer[i + 3] == 'd') {
1273                         debug_warning(DEBUG, "sv3d data found at offset %lld", basic_header->start_offset + i);
1274                         formatContext->isSpherical = true;
1275                 }
1276                 if (buffer[i] == 's' && buffer[i + 1] == 'v' && buffer[i + 2] == 'h' && buffer[i + 3] == 'd') {
1277                         debug_warning(DEBUG, "svhd data found at offset %lld", basic_header->start_offset + i);
1278                         ParseSvhdData(formatContext, fp, basic_header->start_offset + i + 4, mmfile_io_be_uint32(*((uint32_t*)(buffer - 4 + i))));
1279                         debug_msg(RELEASE, "formatContext->metadataSourceV2 = %s (length = %zu)", formatContext->metadataSourceV2, strlen(formatContext->metadataSourceV2));
1280                 }
1281                 if (buffer[i] == 'p' && buffer[i + 1] == 'r' && buffer[i + 2] == 'o' && buffer[i + 3] == 'j') {
1282                         debug_warning(DEBUG, "proj data found at offset %lld", basic_header->start_offset + i);
1283                         ParseProjData(formatContext, fp, basic_header->start_offset + i + 4);
1284                 }
1285         }
1286
1287         return MMFILE_UTIL_SUCCESS;
1288
1289 exception:
1290         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1291
1292         return MMFILE_UTIL_FAIL;
1293 }
1294
1295 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1296 {
1297         unsigned int value = 0;
1298         int readed = 0;
1299
1300         if (!formatContext || !fp || !basic_header) {
1301                 debug_error(DEBUG, "invalid param");
1302                 return MMFILE_UTIL_FAIL;
1303         }
1304
1305         readed = mmfile_read(fp, (unsigned char *)&value, sizeof(unsigned int));
1306         if (readed != sizeof(unsigned int)) {
1307                 debug_error(DEBUG, "read cdis tag header fail");
1308                 goto exception;
1309         }
1310
1311         value = mmfile_io_be_uint32(value);
1312
1313         debug_msg(RELEASE, "Value : 0x%x", value);
1314
1315         if (value == 0x01) {
1316                 debug_msg(RELEASE, "This has cdis tag and valid value");
1317                 formatContext->cdis = 1;
1318         } else {
1319                 debug_error(DEBUG, "This has cdis tag and but invalid value");
1320                 goto exception;
1321         }
1322
1323         return MMFILE_UTIL_SUCCESS;
1324
1325 exception:
1326         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1327
1328         return MMFILE_UTIL_FAIL;
1329 }
1330
1331 static int GetTagFromMetaBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1332 {
1333         int readed = 0;
1334         MMFILE_MP4_BASIC_BOX_HEADER hdlrBoxHeader = {0, };
1335         MMFILE_MP4_BASIC_BOX_HEADER id3v2BoxHeader = {0, };
1336         MMFILE_3GP_ID3V2_BOX id3v2Box = {0, };
1337         AvFileContentInfo tagInfo = {0, };
1338         unsigned char tagVersion = 0;
1339         bool versionCheck = false;
1340         int id3v2Len = 0;
1341         unsigned int meta_version = 0;
1342         MMFILE_3GP_HANDLER_BOX hdlrBox = {0, };
1343         int id3_meta = 0;
1344 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
1345         int iTunes_meta = 0;
1346 #endif
1347
1348         /* meta box */
1349         readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
1350         if (readed != 4) {
1351                 debug_error(DEBUG, "read meta box version");
1352                 goto exception;
1353         }
1354
1355         /* hdlr box */
1356         readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1357         if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1358                 debug_error(DEBUG, "read hdlr box header");
1359                 goto exception;
1360         }
1361
1362         if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
1363                 debug_warning(DEBUG, "meta type is not hdlr");
1364                 goto exception;
1365         }
1366
1367         hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
1368         hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
1369
1370         readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
1371         if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
1372                 debug_error(DEBUG, "read hdlr box");
1373                 goto exception;
1374         }
1375
1376         hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
1377
1378         /**
1379          * check tag type (ID3v2 or iTunes)
1380          */
1381         if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
1382                 debug_msg(RELEASE, "ID3v2 tag detected.");
1383
1384                 id3_meta = 1;
1385 #ifdef ENABLE_ITUNES_META
1386                 iTunes_meta = 0;
1387 #endif
1388         } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
1389                                 mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
1390
1391                 debug_msg(RELEASE, "Apple iTunes tag detected by mdir.");
1392
1393 #ifdef ENABLE_ITUNES_META
1394                 iTunes_meta = 1;
1395 #endif
1396         } else {
1397                 debug_warning(DEBUG, "unknown meta type. 4CC:[%c%c%c%c]", ((char *)&hdlrBox.handler_type)[0],
1398                                         ((char *)&hdlrBox.handler_type)[1],
1399                                         ((char *)&hdlrBox.handler_type)[2],
1400                                         ((char *)&hdlrBox.handler_type)[3]);
1401                 /*goto exception; */
1402         }
1403
1404 #ifdef ENABLE_ITUNES_META
1405         if (!id3_meta && !iTunes_meta) {
1406                 /*Check ilst.
1407                 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
1408                 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
1409                 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
1410
1411                 const char *ilst_box = "ilst";
1412                 int buf_size = strlen(ilst_box);
1413
1414                 unsigned char read_buf[buf_size + 1];
1415                 memset(read_buf, 0x00, buf_size + 1);
1416
1417                 /* skip hdlr box */
1418                 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR);       /*+4 is hdlr size field */
1419
1420                 readed = mmfile_read(fp, read_buf, buf_size);   /* to find 'ilst' */
1421                 if (readed != buf_size) {
1422                         debug_error(DEBUG, "read fail [%d]", readed);
1423                         goto exception;
1424                 }
1425
1426                 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
1427                         debug_msg(RELEASE, "Apple iTunes tag detected by ilst.");
1428                         iTunes_meta = 1;
1429                 }
1430         }
1431 #endif
1432
1433 #ifdef ENABLE_ITUNES_META
1434         if (iTunes_meta) {
1435                 /**
1436                  * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
1437                  *
1438                  *  4cc   : 4byte
1439                  *        : 4byte       size
1440                  * 'data' : 4byte
1441                  *        : 4byte       type
1442                  *        : 4byte       unknown
1443                  */
1444 #define _ITUNES_READ_BUF_SZ             20
1445 #define _ITUNES_TRACK_NUM_SZ    4
1446 #define _ITUNES_GENRE_NUM_SZ    4
1447 #define _ITUNES_COVER_TYPE_JPEG 13
1448 #define _ITUNES_COVER_TYPE_PNG          14
1449
1450                 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
1451                 int i = 0;
1452                 int cover_sz = 0, cover_type = 0, cover_found = 0;
1453                 /* int track_found = 0; */ /* , track_num = 0; */
1454                 /* int genre_found = 0; */ /* , genre_index = 0; */
1455                 /* int artist_found = 0; */ /* , artist_sz = 0; */
1456                 int limit = basic_header->size - hdlrBoxHeader.size;
1457                 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
1458
1459                 /* for (i = 0, cover_found = 0, track_found = 0, genre_found = 0, artist_found = 0; i < limit && (cover_found == 0 || track_found == 0 || genre_found == 0 || artist_found == 0) ; i++) { */
1460                 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
1461                         readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
1462                         if (readed != _ITUNES_READ_BUF_SZ)
1463                                 goto exception;
1464
1465                         /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
1466                         but ffmpeg does not support strange cover image.
1467                         only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
1468 #if 0
1469                         /**
1470                          * Artist : Added 2010.10.28
1471                          */
1472                         if (artist_found == 0 &&
1473                             read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
1474                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1475
1476                                 artist_found = 1;
1477                                 artist_offset = mmfile_tell(fp);
1478                                 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
1479
1480                                 debug_msg(RELEASE, "----------------------------------- artist found, offset=[%lld], size=[%d]", artist_offset, artist_sz);
1481                         }
1482
1483                         /**
1484                          * Track number
1485                          */
1486                         if (track_found == 0 &&
1487                             read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
1488                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1489
1490                                 track_found = 1;
1491                                 track_offset = mmfile_tell(fp);
1492
1493                                 debug_msg(RELEASE, "----------------------------------- Track found, offset=[%lld]", track_offset);
1494                         }
1495
1496                         /**
1497                          * Genre : Added 2010.10.27
1498                          */
1499                         /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
1500                         if (genre_found == 0 &&
1501                             read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
1502                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1503
1504                                 genre_found = 1;
1505                                 genre_offset = mmfile_tell(fp);
1506
1507                                 debug_msg(RELEASE, "----------------------------------- genre found, offset=[%lld]", genre_offset);
1508                         }
1509 #endif
1510
1511                         /**
1512                          * Cover image
1513                          */
1514
1515                         if (cover_found == 0 &&
1516                             read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
1517                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1518
1519                                 cover_found = 1;
1520                                 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
1521                                 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
1522
1523                                 cover_offset = mmfile_tell(fp);
1524
1525                                 debug_msg(RELEASE, "----------------------------------- cover_found found,  offset=[%lld]", cover_offset);
1526                         }
1527
1528                         mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR);  /*FIXME: poor search*/
1529                 } /*loop*/
1530
1531                 /*ffmpeg extract artist, tracknum, except cover image. see mov_read_udta_string()*/
1532 #if 0
1533                 if (artist_found) {
1534                         if (artist_sz > 0) {
1535                                 mmfile_seek(fp, artist_offset, SEEK_SET);
1536
1537                                 if (formatContext->artist) {
1538                                         debug_msg(RELEASE, "----------------------------------- previous artist was [%s] ", formatContext->artist);
1539                                         free(formatContext->artist);
1540                                 }
1541
1542                                 debug_msg(RELEASE, "----------------------------------- new artist will be allocated with size (len+1) [%d] ", artist_sz + 1);
1543                                 formatContext->artist = g_malloc0(artist_sz + 1);
1544
1545                                 if (formatContext->artist) {
1546                                         readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1547                                         formatContext->artist[artist_sz] = '\0';
1548
1549                                         debug_msg(RELEASE, "----------------------------------- new artist is [%s] ", formatContext->artist);
1550
1551                                         if (readed != artist_sz) {
1552                                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d", readed, artist_sz);
1553                                                 mmfile_free(formatContext->artist);
1554                                         }
1555                                 }
1556                         }
1557                 }
1558
1559                 if (track_found) {
1560                         mmfile_seek(fp, track_offset, SEEK_SET);
1561                         readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1562                         if (readed != _ITUNES_TRACK_NUM_SZ) {
1563                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d", readed, _ITUNES_TRACK_NUM_SZ);
1564                         } else {
1565                                 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1566                                 if (!formatContext->tagTrackNum) {
1567                                         memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1568                                         snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1569                                         formatContext->tagTrackNum = g_strdup((const char *)read_buf);
1570                                 }
1571                         }
1572                 }
1573
1574                 if (genre_found) {
1575                         mmfile_seek(fp, genre_offset, SEEK_SET);
1576                         readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1577                         if (readed != _ITUNES_GENRE_NUM_SZ) {
1578                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d", readed, _ITUNES_GENRE_NUM_SZ);
1579                         } else {
1580                                 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1581                                 debug_msg(RELEASE, "genre index=[%d] ", genre_index);
1582
1583                                 if (genre_index > 0 && genre_index < GENRE_COUNT)       {
1584                                         if (!formatContext->genre) {
1585                                                 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1586                                                 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1587                                                 debug_msg(RELEASE, "genre string=[%s] ", read_buf);
1588                                                 formatContext->genre = g_strdup((const char *)read_buf);
1589                                         }
1590                                 }
1591                         }
1592                 }
1593 #endif
1594
1595                 /*
1596                         1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1597                         Music Cover Art Image Profile
1598                         - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1599                         - RGB (screen standard)
1600                         - Minimum size of 600 x 600 pixels
1601                         - Images must be at least 72 dpi
1602
1603                         2)I found below info from google.
1604                         cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1605
1606                         3)So, FIXME when cover image format is tif!
1607                 */
1608                 if (cover_found) {
1609                         if (cover_sz > 0) {
1610                                 mmfile_seek(fp, cover_offset, SEEK_SET);
1611
1612                                 formatContext->artwork = g_malloc0(cover_sz);
1613                                 formatContext->artworkSize = cover_sz;
1614                                 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1615                                         formatContext->artworkMime = g_strdup("image/jpeg");
1616                                 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1617                                         formatContext->artworkMime = g_strdup("image/png");
1618                                         /*} else if (cover_type == _ITUNES_COVER_TYPE_TIF) {
1619                                                 formatContext->artworkMime = g_strdup("image/tif");*/
1620                                 } else {
1621                                         debug_warning(DEBUG, "Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1622                                         formatContext->artworkMime = g_strdup("image/jpeg");
1623                                 }
1624
1625                                 if (formatContext->artwork) {
1626                                         readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1627                                         if (readed != cover_sz) {
1628                                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d", readed, cover_sz);
1629                                                 mmfile_free(formatContext->artwork);
1630                                                 formatContext->artworkSize = 0;
1631                                                 mmfile_free(formatContext->artworkMime);
1632                                         }
1633                                 }
1634                         }
1635                 }
1636
1637                 /*reset seek position*/
1638                 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1639
1640                 return MMFILE_UTIL_SUCCESS;
1641
1642         } else
1643 #endif
1644                 if (id3_meta) {
1645                         /**
1646                          * ID3v2
1647                          */
1648                         /* skip hdlr box name */
1649                         mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1650
1651                         /* id3 tag box */
1652                         readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1653                         if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1654                                 debug_error(DEBUG, "read id3v2 box header");
1655                                 goto exception;
1656                         }
1657
1658                         id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1659                         id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1660
1661                         if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1662                                 debug_warning(DEBUG, "meta type is not id3v2");
1663                                 goto exception;
1664                         }
1665
1666                         readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1667                         if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1668                                 debug_error(DEBUG, "read id3v2 box");
1669                                 goto exception;
1670                         }
1671
1672                         id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1673
1674                         id3v2Box.id3v2Data = g_malloc0(id3v2Len);
1675
1676                         readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1677                         if (readed != id3v2Len) {
1678                                 debug_error(DEBUG, "read id3tag data error");
1679                                 goto exception;
1680                         }
1681
1682                         /* check id3v2 */
1683                         if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1684                                 debug_error(DEBUG, "it is not id3tag");
1685                                 goto exception;
1686                         }
1687
1688                         if (id3v2Box.id3v2Data[3] == 0xFF ||  id3v2Box.id3v2Data[4] == 0xFF ||
1689                             id3v2Box.id3v2Data[6] >= 0x80 ||  id3v2Box.id3v2Data[7] >= 0x80 ||
1690                             id3v2Box.id3v2Data[8] >= 0x80 ||  id3v2Box.id3v2Data[9] >= 0x80) {
1691                                 debug_error(DEBUG, "it is not valid id3tag");
1692                                 goto exception;
1693                         }
1694
1695                         tagVersion = id3v2Box.id3v2Data[3];
1696                         if (tagVersion > 4) {
1697                                 debug_error(DEBUG, "tag version is too high");
1698                                 goto exception;
1699                         }
1700
1701                         tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1702                         tagInfo.tagV2Info.tagLen += (((id3v2Box.id3v2Data[6] & 0x7F) << 21) | ((id3v2Box.id3v2Data[7] & 0x7F) << 14) | ((id3v2Box.id3v2Data[8] & 0x7F) << 7) | ((id3v2Box.id3v2Data[9] & 0x7F)));
1703                         tagInfo.tagV2Info.tagVersion = tagVersion;
1704                         tagInfo.fileLen = id3v2Len;
1705
1706                         /* set id3v2 data to formatContext */
1707                         switch (tagVersion) {
1708                         case 2:
1709                                 versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data, formatContext->extract_artwork);
1710                                 break;
1711                         case 3:
1712                                 versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data, formatContext->extract_artwork);
1713                                 break;
1714                         case 4:
1715                                 versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data, formatContext->extract_artwork);
1716                                 break;
1717                         case 1:
1718                         default:
1719                                 debug_error(DEBUG, "tag vesion is not support");
1720                                 versionCheck = false;
1721                                 break;
1722                         }
1723
1724                         if (versionCheck == false) {
1725                                 debug_error(DEBUG, "tag parsing is fail");
1726                                 goto exception;
1727                         }
1728
1729                         formatContext->title = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_TITLE].value);
1730                         formatContext->artist = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_ARTIST].value);
1731                         formatContext->copyright = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_COPYRIGHT].value);
1732                         formatContext->comment = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_COMMENT].value);
1733                         formatContext->album = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_ALBUM].value);
1734                         formatContext->album_artist = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_ALBUM_ARTIST].value);
1735                         formatContext->year = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_YEAR].value);
1736                         formatContext->genre = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_GENRE].value);
1737                         formatContext->tagTrackNum = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_TRACKNUM].value);
1738                         formatContext->composer = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_COMPOSER].value);
1739                         formatContext->classification = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_CONTENT_GROUP].value);
1740                         formatContext->conductor = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_CONDUCTOR].value);
1741
1742                         if (tagInfo.imageInfo.pImageBuf && tagInfo.imageInfo.imageLen > 0) {
1743                                 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1744                                 formatContext->artwork = g_memdup2(tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1745                         }
1746
1747                         mm_file_free_AvFileContentInfo(&tagInfo);
1748                         mmfile_free(id3v2Box.id3v2Data);
1749
1750                         /*reset seek position*/
1751                         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1752
1753                         return MMFILE_UTIL_SUCCESS;
1754
1755                 }
1756
1757
1758 exception:
1759         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1760         mmfile_free(id3v2Box.id3v2Data);
1761         mm_file_free_AvFileContentInfo(&tagInfo);
1762
1763         return MMFILE_UTIL_FAIL;
1764 }
1765
1766 int mm_file_get_int_value_from_xml_string(const char* xml_str, const char* param_name, int* value)
1767 {
1768         char *value_start, *value_end, *endptr;
1769         const short value_length_max = 12;
1770         char init_view_ret[value_length_max];
1771         int value_length = 0;
1772
1773         if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1774                 debug_error(DEBUG, "error: incorrect or non-existing parameter");
1775                 return MMFILE_UTIL_FAIL;
1776         }
1777
1778         value_start = strstr(xml_str, param_name) + strlen(param_name);
1779         while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1780                 value_start++;
1781
1782         value_end = strchr(value_start, '<');
1783         if (!value_end) {
1784                 debug_error(DEBUG, "error: incorrect XML");
1785                 return MMFILE_UTIL_FAIL;
1786         }
1787
1788         value_length = value_end - value_start;
1789         while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1790                 value_length--;
1791
1792         int i = 0;
1793         if (value_start[i] == '+' || value_start[i] == '-')
1794                         i++;
1795         while (i < value_length) {
1796                 if (value_start[i] < '0' || value_start[i] > '9') {
1797                         debug_error(DEBUG, "error: incorrect value, integer was expected");
1798                         return MMFILE_UTIL_FAIL;
1799                 }
1800                 i++;
1801         }
1802
1803         if (value_length >= value_length_max || value_length < 1) {
1804                 debug_error(DEBUG, "error: empty XML value or incorrect range");
1805                 return MMFILE_UTIL_FAIL;
1806         }
1807
1808         memset(init_view_ret, 0x00, value_length_max);
1809         if (g_strlcpy(init_view_ret, value_start, value_length_max) >= value_length_max) {
1810                 debug_error(DEBUG, "error: truncation occurred");
1811                 return MMFILE_UTIL_FAIL;
1812         }
1813
1814
1815         *value = strtol(init_view_ret, &endptr, 10);
1816         if (endptr == init_view_ret) {
1817                 debug_error(DEBUG, "error: no digits were found");
1818                 return MMFILE_UTIL_FAIL;
1819         }
1820
1821         return MMFILE_UTIL_SUCCESS;
1822 }
1823
1824 int mm_file_get_string_value_from_xml_string(const char* xml_str, const char* param_name, char** value)
1825 {
1826         char *value_start, *value_end;
1827         const short value_length_max = 256;
1828         int value_length = 0;
1829
1830         if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1831                 debug_error(DEBUG, "error: incorrect or non-existing parameter");
1832                 return MMFILE_UTIL_FAIL;
1833         }
1834
1835         value_start = strstr(xml_str, param_name) + strlen(param_name);
1836         while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1837                 value_start++;
1838
1839         value_end = strchr(value_start, '<');
1840         if (!value_end) {
1841                 debug_error(DEBUG, "error: incorrect XML");
1842                 return MMFILE_UTIL_FAIL;
1843         }
1844
1845         value_length = value_end - value_start;
1846         while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1847                 value_length--;
1848
1849         if (value_length >= value_length_max || value_length < 1) {
1850                 debug_error(DEBUG, "error: empty XML value or incorrect range");
1851                 return MMFILE_UTIL_FAIL;
1852         }
1853
1854         *value = (char*)calloc(value_length, sizeof(char));
1855         if (*value == NULL) {
1856                 debug_error(DEBUG, "error: calloc failed");
1857                 return MMFILE_UTIL_FAIL;
1858         }
1859         strncpy(*value, value_start, value_length);
1860
1861         return MMFILE_UTIL_SUCCESS;
1862 }
1863
1864 int mm_file_get_bool_value_from_xml_string(const char* xml_str, const char* param_name, bool* value)
1865 {
1866         char *value_start = NULL;
1867         char *value_end = NULL;
1868         int value_length = 0;
1869
1870         if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1871                 debug_error(DEBUG, "error: incorrect or non-existing parameter");
1872                 return MMFILE_UTIL_FAIL;
1873         }
1874
1875         value_start = strstr(xml_str, param_name) + strlen(param_name);
1876         while ((value_start != NULL) && ((value_start[0] == ' ') || (value_start[0] == '\t')))
1877                 value_start++;
1878
1879         value_end = strchr(value_start, '<');
1880         if (value_end == NULL) {
1881                 debug_error(DEBUG, "error: incorrect XML.");
1882                 return MMFILE_UTIL_FAIL;
1883         }
1884
1885         value_length = value_end - value_start;
1886         while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1887                 value_length--;
1888
1889         if (value_length < 1) {
1890                 debug_error(DEBUG, "error: empty XML value or incorrect range");
1891                 return MMFILE_UTIL_FAIL;
1892         }
1893
1894         *value = strstr(value_start, "true") ? true : false;
1895
1896         return MMFILE_UTIL_SUCCESS;
1897 }
1898
1899 int ParseSpatialVideoMetadataFromXMLString(const char *xmlStr, MMFileFormatContext *formatContext)
1900 {
1901         const char is_spherical_str[] = "<GSpherical:Spherical>";
1902         const char is_stitched_str[] = "<GSpherical:Stitched>";
1903         const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
1904         const char projection_type_str[] = "<GSpherical:ProjectionType>";
1905         const char stereo_mode_str[] = "<GSpherical:StereoMode>";
1906         const char source_count_str[] = "<GSpherical:SourceCount>";
1907         const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
1908         const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
1909         const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
1910         const char timestamp_str[] = "<GSpherical:Timestamp>";
1911         const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
1912         const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
1913         const char cropped_area_image_width_str[] = "<GSpherical:CroppedAreaImageWidthPixels>";
1914         const char cropped_area_image_height_str[] = "<GSpherical:CroppedAreaImageHeightPixels>";
1915         const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
1916         const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
1917
1918         mm_file_get_bool_value_from_xml_string(xmlStr, is_spherical_str, (bool*)&formatContext->isSpherical);
1919         mm_file_get_bool_value_from_xml_string(xmlStr, is_stitched_str, (bool*)&formatContext->isStitched);
1920
1921         debug_msg(RELEASE, "isSpherical = %d", formatContext->isSpherical);
1922         debug_msg(RELEASE, "isStitched = %d", formatContext->isStitched);
1923
1924         if (formatContext->isSpherical && formatContext->isStitched) {
1925                 mm_file_get_string_value_from_xml_string(xmlStr, stitching_software_str, &formatContext->stitchingSoftware);
1926                 mm_file_get_string_value_from_xml_string(xmlStr, projection_type_str, &formatContext->projectionType);
1927                 mm_file_get_string_value_from_xml_string(xmlStr, stereo_mode_str, &formatContext->stereoMode);
1928                 mm_file_get_int_value_from_xml_string(xmlStr, source_count_str, &formatContext->sourceCount);
1929                 mm_file_get_int_value_from_xml_string(xmlStr, init_view_heading_str, &formatContext->initViewHeading);
1930                 mm_file_get_int_value_from_xml_string(xmlStr, init_view_pitch_str, &formatContext->initViewPitch);
1931                 mm_file_get_int_value_from_xml_string(xmlStr, init_view_roll_str, &formatContext->initViewRoll);
1932                 mm_file_get_int_value_from_xml_string(xmlStr, timestamp_str, &formatContext->timestamp);
1933                 mm_file_get_int_value_from_xml_string(xmlStr, full_pano_width_str, &formatContext->fullPanoWidth);
1934                 mm_file_get_int_value_from_xml_string(xmlStr, full_pano_height_str, &formatContext->fullPanoHeight);
1935                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_width_str, &formatContext->croppedAreaImageWidth);
1936                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_height_str, &formatContext->croppedAreaImageHeight);
1937                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_left_str, &formatContext->croppedAreaLeft);
1938                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_top_str, &formatContext->croppedAreaTop);
1939
1940                 debug_msg(RELEASE, "stitchingSoftware = %s", formatContext->stitchingSoftware);
1941                 debug_msg(RELEASE, "projectionType = %s", formatContext->projectionType);
1942                 debug_msg(RELEASE, "stereoMode = %s", formatContext->stereoMode);
1943                 debug_msg(RELEASE, "sourceCount %d", formatContext->sourceCount);
1944                 debug_msg(RELEASE, "initViewHeading = %d", formatContext->initViewHeading);
1945                 debug_msg(RELEASE, "initViewPitch = %d", formatContext->initViewPitch);
1946                 debug_msg(RELEASE, "initViewRoll = %d", formatContext->initViewRoll);
1947                 debug_msg(RELEASE, "timestamp = %d", formatContext->timestamp);
1948                 debug_msg(RELEASE, "fullPanoWidthPixels = %d", formatContext->fullPanoWidth);
1949                 debug_msg(RELEASE, "fullPanoHeightPixels = %d", formatContext->fullPanoHeight);
1950                 debug_msg(RELEASE, "croppedAreaImageWidth = %d", formatContext->croppedAreaImageWidth);
1951                 debug_msg(RELEASE, "croppedAreaImageHeight = %d", formatContext->croppedAreaImageHeight);
1952                 debug_msg(RELEASE, "croppedAreaLeft = %d", formatContext->croppedAreaLeft);
1953                 debug_msg(RELEASE, "croppedAreaTop = %d", formatContext->croppedAreaTop);
1954         }
1955
1956         return MMFILE_UTIL_SUCCESS;
1957 }
1958
1959 #define BIG_CONTENT_BOX_SIZE_LEN 8
1960
1961 int MMFileUtilGetMetaDataFromMKV(MMFileFormatContext *formatContext)
1962 {
1963         MMFileIOHandle *fp = NULL;
1964         long long probe_size = 10000;
1965         unsigned char *buffer = NULL;
1966         int ret = 0;
1967         long long i;
1968         long long file_size = 0;
1969
1970         MMFILE_WEBM_PROJ_V2_BOX v2box = { 0, };
1971         MMFILE_WEBM_EQUI_PROJ_V2_BOX equi = { 0, };
1972         MMFILE_WEBM_CBMP_PROJ_V2_BOX cbmp = { 0, };
1973         MMFILE_WEBM_POSE_ELEMENT_V2_BOX pose = { 0, };
1974
1975         ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1976         if (ret == MMFILE_UTIL_FAIL) {
1977                 debug_error(DEBUG, "error: mmfile_open");
1978                 goto exit;
1979         }
1980
1981         file_size = mmfile_seek(fp, 0, SEEK_END);
1982         if (file_size == MMFILE_UTIL_FAIL) {
1983                 debug_error(DEBUG, "mmfile operation failed");
1984                 goto exit;
1985         }
1986
1987         probe_size = (file_size > probe_size) ? probe_size : file_size;
1988         buffer = (unsigned char *)malloc(probe_size * sizeof(unsigned char));
1989         if (!buffer) {
1990                 debug_error(DEBUG, "malloc failed");
1991                 goto exit;
1992         }
1993
1994         ret = mmfile_seek(fp, 0, SEEK_SET);
1995         if (ret == MMFILE_UTIL_FAIL) {
1996                 debug_error(DEBUG, "mmfile operation failed");
1997                 goto exit;
1998         }
1999
2000         ret = mmfile_read(fp, buffer, probe_size * sizeof(unsigned char));
2001         if (ret == MMFILE_UTIL_FAIL) {
2002                 debug_error(DEBUG, "mmfile operation failed");
2003                 goto exit;
2004         }
2005
2006         /* FIXME (m.alieksieie): It's better to use some EBML parser here*/
2007         for (i = 0; i + 3 < probe_size; ++i) {
2008                 if (*(unsigned int *)(buffer + i) == FOURCC('e', 'q', 'u', 'i') ||
2009                                 *(unsigned int *)(buffer + i) == FOURCC('c', 'b', 'm', 'p')) {
2010                         debug_msg(DEBUG, "projection data found at offset %lld bytes", i);
2011                         break;
2012                 }
2013         }
2014
2015         if (i + 3 == probe_size) {
2016                 debug_msg(DEBUG, "projection info wasn't found");
2017                 ret = MMFILE_UTIL_SUCCESS;
2018                 goto exit;
2019         }
2020
2021         if ((i - sizeof(MMFILE_WEBM_PROJ_V2_BOX)) < 0) {
2022                 debug_error(DEBUG, "error: invalid supposed projection info location");
2023                 ret = MMFILE_UTIL_FAIL;
2024                 goto exit;
2025         }
2026
2027         ret = mmfile_seek(fp, i - sizeof(MMFILE_WEBM_PROJ_V2_BOX), SEEK_SET);
2028         if (ret == MMFILE_UTIL_FAIL) {
2029                 debug_error(DEBUG, "error: failed to seek to the supposed projection info location");
2030                 goto exit;
2031         }
2032
2033         ret = mmfile_read(fp, (unsigned char *)&v2box, sizeof(MMFILE_WEBM_PROJ_V2_BOX));
2034         if (ret == MMFILE_UTIL_FAIL) {
2035                 debug_error(DEBUG, "mmfile operation failed");
2036                 goto exit;
2037         }
2038
2039         if (v2box.proj_type_box_value == PROJECTION_TYPE_EQUI) {
2040                 debug_msg(DEBUG, "Equirectangular projection is used");
2041
2042                 ret = mmfile_read(fp, (unsigned char *)&equi, sizeof(MMFILE_WEBM_EQUI_PROJ_V2_BOX));
2043                 if (ret == MMFILE_UTIL_FAIL) {
2044                         debug_error(DEBUG, "error: failed to read equirectangular element");
2045                         goto exit;
2046                 }
2047                 if (strncmp((char *)equi.proj_priv_box_name, "equi", 4) == 0) {
2048                         formatContext->equiBoundsTopV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_top);
2049                         formatContext->equiBoundsBottomV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_bottom);
2050                         formatContext->equiBoundsLeftV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_left);
2051                         formatContext->equiBoundsRightV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_right);
2052                 } else {
2053                         debug_error(DEBUG, "error: failed to read equirectangular element");
2054                         ret = MMFILE_UTIL_SUCCESS;
2055                         goto exit;
2056                 }
2057         }
2058         if (v2box.proj_type_box_value == PROJECTION_TYPE_CBMP) {
2059                 debug_msg(DEBUG, "Cubemap projection is used");
2060
2061                 ret = mmfile_read(fp, (unsigned char *)&cbmp, sizeof(MMFILE_WEBM_CBMP_PROJ_V2_BOX));
2062                 if (ret == MMFILE_UTIL_FAIL) {
2063                         debug_error(DEBUG, "error: failed to read cubemap element");
2064                         goto exit;
2065                 }
2066                 if (strncmp((char *)cbmp.proj_priv_box_name, "cbmp", 4) == 0) {
2067                         formatContext->cbmpLayoutV2 = mmfile_io_be_uint32(cbmp.cbmp_projection_layout);
2068                         formatContext->cbmpPaddingV2 = mmfile_io_be_uint32(cbmp.cbmp_projection_padding);
2069                 } else {
2070                         debug_error(DEBUG, "error: failed to read cubemap element");
2071                         ret = MMFILE_UTIL_FAIL;
2072                         goto exit;
2073                 }
2074         }
2075
2076         ret = mmfile_read(fp, (unsigned char *)&pose, sizeof(MMFILE_WEBM_POSE_ELEMENT_V2_BOX));
2077         if (ret == MMFILE_UTIL_FAIL) {
2078                 debug_error(DEBUG, "error: failed to read pose info");
2079                 goto exit;
2080         }
2081
2082         if (pose.pose_yaw_element_id == POSE_YAW_ELEMENT_ID) {
2083                 formatContext->poseYawV2 = (uint)mmfile_io_be_float32(pose.pose_yaw_element_value);
2084         } else {
2085                 debug_error(DEBUG, "error: failed to pose yaw element");
2086                 ret = MMFILE_UTIL_FAIL;
2087                 goto exit;
2088         }
2089         if (pose.pose_pitch_element_id == POSE_PITCH_ELEMENT_ID) {
2090                 formatContext->posePitchV2 = (uint)mmfile_io_be_float32(pose.pose_pitch_element_value);
2091         } else {
2092                 debug_error(DEBUG, "error: failed to pose pitch element");
2093                 ret = MMFILE_UTIL_FAIL;
2094                 goto exit;
2095         }
2096         if (pose.pose_roll_element_id == POSE_ROLL_ELEMENT_ID) {
2097                 formatContext->poseRollV2 = (uint)mmfile_io_be_float32(pose.pose_roll_element_value);
2098         } else {
2099                 debug_error(DEBUG, "error: failed to pose roll element");
2100                 ret = MMFILE_UTIL_FAIL;
2101                 goto exit;
2102         }
2103
2104 exit:
2105         mmfile_close(fp);
2106
2107         if (buffer)
2108                 free(buffer);
2109
2110         return ret;
2111 }
2112
2113 int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
2114 {
2115         MMFileIOHandle *fp = NULL;
2116         int ret = 0;
2117         int readed;
2118         unsigned long long chunk_size = 0;
2119         long long moov_end = 0;
2120         MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
2121         int junk_counter = 0;
2122
2123         ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
2124         if (ret == MMFILE_UTIL_FAIL) {
2125                 debug_error(DEBUG, "error: mmfile_open");
2126                 goto exit;
2127         }
2128
2129         basic_header.start_offset = mmfile_tell(fp);
2130         if (basic_header.start_offset < 0) {
2131                 debug_error(DEBUG, "error: mmfile_tell");
2132                 goto exit;
2133         }
2134
2135         if (g_junk_counter_limit == 0)
2136                 g_junk_counter_limit = mmfile_get_int_from_ini(MMFILE_INI_JUNKCNTLIMIT, MMFILE_DEFAULT_JUNKCNTLIMIT);
2137
2138         while ((ret != MMFILE_UTIL_FAIL) && ((readed = mmfile_read(fp, (unsigned char *)&basic_header, MMFILE_MP4_BASIC_BOX_HEADER_LEN)) == MMFILE_MP4_BASIC_BOX_HEADER_LEN)) {
2139                 basic_header.size = mmfile_io_be_uint32(basic_header.size);
2140                 basic_header.type = mmfile_io_le_uint32(basic_header.type);
2141
2142                 if (basic_header.size == 0) {
2143                         debug_warning(DEBUG, "header is invalid.");
2144                         basic_header.size = readed;
2145                         basic_header.type = 0;
2146                         chunk_size = basic_header.size;
2147
2148                         if ((moov_end != 0) && (moov_end < basic_header.start_offset)) {
2149                                 debug_msg(DEBUG, "found junk data but moov data already was extracted, so junk counter will be increase: %d", junk_counter);
2150                                 junk_counter++;
2151
2152                                 /* stop the loop for junk case. */
2153                                 if ((g_junk_counter_limit > 0) && (junk_counter > g_junk_counter_limit)) {
2154                                         debug_msg(DEBUG, "stop the loop by junk-data checker");
2155                                         ret = MMFILE_UTIL_FAIL;
2156                                         continue;
2157                                 }
2158                         }
2159                 } else if (basic_header.size == 1) {
2160                         int i = 0;
2161                         unsigned char temp[BIG_CONTENT_BOX_SIZE_LEN] = {0, };
2162                         unsigned long long size = 0;
2163
2164                         mmfile_read(fp, (unsigned char *)&temp, BIG_CONTENT_BOX_SIZE_LEN);
2165
2166                         for (i = 0; i < BIG_CONTENT_BOX_SIZE_LEN; i++)
2167                                 size |= (unsigned long long)temp[i] << (BIG_CONTENT_BOX_SIZE_LEN - 1 - i) * BIG_CONTENT_BOX_SIZE_LEN;
2168                         chunk_size = size;
2169                         junk_counter = 0;
2170                 } else {
2171                         chunk_size = basic_header.size;
2172                         junk_counter = 0;
2173                 }
2174
2175                 switch (basic_header.type) {
2176                         case FOURCC('m', 'o', 'o', 'v'): {
2177                                         debug_msg(RELEASE, "MPEG4: [moov] SIZE: [%lld]Byte", chunk_size);
2178                                         moov_end = basic_header.start_offset + chunk_size;
2179                                         break;
2180                                 }
2181                         case FOURCC('u', 'd', 't', 'a'): {
2182                                         debug_msg(RELEASE, "MPEG4: [udat] SIZE: [%lld]Byte", chunk_size);
2183                                         break;
2184                                 }
2185                                 /*/////////////////////////////////////////////////////////////// */
2186                                 /*                  Extracting Tag Data                        // */
2187                                 /*/////////////////////////////////////////////////////////////// */
2188                         case FOURCC('t', 'i', 't', 'l'): {
2189                                         debug_msg(RELEASE, "MPEG4: [titl] SIZE: [%lld]Byte", chunk_size);
2190                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
2191                                         break;
2192                                 }
2193                         case FOURCC('d', 's', 'c', 'p'): {
2194                                         debug_msg(RELEASE, "MPEG4: [dscp] SIZE: [%lld]Byte", chunk_size);
2195                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
2196                                         break;
2197                                 }
2198                         case FOURCC('c', 'p', 'r', 't'): {
2199                                         debug_msg(RELEASE, "MPEG4: [cprt] SIZE: [%lld]Byte", chunk_size);
2200                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
2201                                         break;
2202                                 }
2203                         case FOURCC('p', 'e', 'r', 'f'): {
2204                                         debug_msg(RELEASE, "MPEG4: [perf] SIZE: [%lld]Byte", chunk_size);
2205                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
2206                                         break;
2207                                 }
2208                         case FOURCC('a', 'u', 't', 'h'): {
2209                                         debug_msg(RELEASE, "MPEG4: [auth] SIZE: [%lld]Byte", chunk_size);
2210                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
2211                                         break;
2212                                 }
2213                         case FOURCC('g', 'n', 'r', 'e'): {
2214                                         debug_msg(RELEASE, "MPEG4: [gnre] SIZE: [%lld]Byte", chunk_size);
2215                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
2216                                         break;
2217                                 }
2218                         case FOURCC('a', 'l', 'b', 'm'): {
2219                                         debug_msg(RELEASE, "MPEG4: [albm] SIZE: [%lld]Byte", chunk_size);
2220                                         GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
2221                                         break;
2222                                 }
2223                         case FOURCC('y', 'r', 'r', 'c'): {
2224                                         debug_msg(RELEASE, "MPEG4: [yrrc] SIZE: [%lld]Byte", chunk_size);
2225                                         GetYearFromYearTagBox(formatContext, fp, &basic_header);
2226                                         break;
2227                                 }
2228                         case FOURCC('r', 't', 'n', 'g'): {
2229                                         debug_msg(RELEASE, "MPEG4: [rtng] SIZE: [%lld]Byte", chunk_size);
2230                                         GetRatingFromRatingTagBox(formatContext, fp, &basic_header);  /* not use */
2231                                         break;
2232                                 }
2233                         case FOURCC('c', 'l', 's', 'f'): {
2234                                         debug_msg(RELEASE, "MPEG4: [clsf] SIZE: [%lld]Byte", chunk_size);
2235                                         GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
2236                                         break;
2237                                 }
2238                         case FOURCC('k', 'y', 'w', 'd'): {
2239                                         debug_msg(RELEASE, "MPEG4: [kywd] SIZE: [%lld]Byte", chunk_size);
2240                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2241                                         break;
2242                                 }
2243                         case FOURCC('l', 'o', 'c', 'i'): {
2244                                         debug_msg(RELEASE, "MPEG4: [loci] SIZE: [%lld]Byte", chunk_size);
2245                                         GetLocationFromLociTagBox(formatContext, fp, &basic_header);
2246                                         break;
2247                                 }
2248                                 /* Check smta in user data field (moov) to be compatible with android */
2249                         case FOURCC('s', 'm', 't', 'a'): {
2250                                         debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte", chunk_size);
2251                                         GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
2252                                         break;
2253                                 }
2254                                 /* Check cdis in user data field (moov) to be compatible with android */
2255                         case FOURCC('c', 'd', 'i', 's'): {
2256                                         debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte", chunk_size);
2257                                         GetValueFromCDISTagBox(formatContext, fp, &basic_header);
2258                                         break;
2259                                 }
2260                                 /*/////////////////////////////////////////////////////////////// */
2261                                 /*                  Extracting ID3 Tag Data                    // */
2262                                 /*/////////////////////////////////////////////////////////////// */
2263                         case FOURCC('m', 'e', 't', 'a'): {
2264                                         debug_msg(RELEASE, "MPEG4: [meta] SIZE: [%lld]Byte", chunk_size);
2265                                         GetTagFromMetaBox(formatContext, fp, &basic_header);
2266                                         break;
2267                                 }
2268
2269                         case FOURCC('t', 'r', 'a', 'k'): {
2270                                         debug_msg(RELEASE, "MPEG4: [trak] SIZE: [%lld]Byte", chunk_size);
2271                                         break;
2272                                 }
2273                         case FOURCC('u', 'u', 'i', 'd'): {
2274                                         unsigned long uuid[4] = {0, };
2275
2276                                         debug_msg(RELEASE, "MPEG4: [uuid] SIZE: [%lld]Byte", chunk_size);
2277
2278                                         mmfile_read(fp, (unsigned char *)uuid, sizeof(uuid));
2279
2280                                         if (mmfile_io_be_uint32(uuid[0]) == 0xffcc8263
2281                                                 && mmfile_io_be_uint32(uuid[1]) == 0xf8554a93
2282                                                 && mmfile_io_be_uint32(uuid[2]) == 0x8814587a
2283                                                 && mmfile_io_be_uint32(uuid[3]) == 0x02521fdd) {
2284                                                 char *str = NULL;
2285                                                 str = (char *)malloc(basic_header.size);
2286
2287                                                 if (str != NULL) {
2288                                                         memset(str, 0, basic_header.size);
2289                                                         mmfile_read(fp, (unsigned char *)str, basic_header.size);
2290 #if 0
2291 /* The block is superseded */
2292                                                         if (strstr(str, "<GSpherical:Spherical>true</GSpherical:Spherical>"))
2293                                                                 formatContext->is_360 = 1;
2294                                                         else
2295                                                                 formatContext->is_360 = 0;
2296 /* Image can be stitched even if it is not spherical */
2297                                                         if (formatContext->is_360 == 1) {
2298                                                                 if (strstr(str, "<GSpherical:Stitched>true</GSpherical:Stitched>"))
2299                                                                         formatContext->stitched = MMFILE_360_STITCHED;
2300                                                                 else
2301                                                                         formatContext->stitched = MMFILE_360_NON_STITCHED;
2302                                                         } else {
2303 /* Image can be stitched or non-stitched. Usage of some 3rd value is superfluous */
2304                                                                 formatContext->stitched = MMFILE_360_NONE;
2305                                                         }
2306 #endif
2307
2308                                                         debug_msg(RELEASE, "Extracting tags from UUID XML string %s", str);
2309
2310                                                         ParseSpatialVideoMetadataFromXMLString(str, formatContext);
2311                                                 }
2312                                         }
2313                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2314
2315                                         break;
2316                                 }
2317                         case FOURCC('m', 'd', 'i', 'a'): {
2318                                         debug_msg(RELEASE, "MPEG4: [mdia] SIZE: [%lld]Byte", chunk_size);
2319                                         break;
2320                                 }
2321                         case FOURCC('m', 'i', 'n', 'f'): {
2322                                         debug_msg(RELEASE, "MPEG4: [minf] SIZE: [%lld]Byte", chunk_size);
2323                                         break;
2324                                 }
2325                         case FOURCC('s', 't', 'b', 'l'): {
2326                                         debug_msg(RELEASE, "MPEG4: [stbl] SIZE: [%lld]Byte", chunk_size);
2327                                         break;
2328                                 }
2329                         case FOURCC('s', 't', 's', 'd'): {
2330                                         debug_msg(RELEASE, "MPEG4: [stsd] SIZE: [%lld]Byte", chunk_size);
2331                                         break;
2332                                 }
2333                         case FOURCC('m', 'p', '4', 'a'): {
2334                                         debug_msg(RELEASE, "MPEG4: [mp4a] SIZE: [%lld]Byte", chunk_size);
2335                                         GetSA3DInfoFromMP4ATagBox(formatContext, fp, &basic_header);
2336                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2337                                         break;
2338                                 }
2339                         case FOURCC('a', 'v', 'c', '1'): {
2340                                         debug_msg(RELEASE, "MPEG4: [avc1] SIZE: [%lld]Byte (offset: %lld)", chunk_size, basic_header.start_offset);
2341                                         GetVideoV2MetadataFromAvc1TagBox(formatContext, fp, &basic_header);
2342                                         break;
2343                                 }
2344                         default: {
2345                                         debug_msg(RELEASE, "4CC: Not Support [%c%c%c%c]. So skip it. Size [%lld Byte]",
2346                                                                 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
2347                                                                 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3], chunk_size);
2348                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2349                                         break;
2350                                 }
2351                 }
2352
2353                 if (ret == MMFILE_UTIL_FAIL) {
2354                         debug_error(DEBUG, "mmfile operation is error");
2355                         ret = -1;
2356                         goto exit;
2357                 }
2358
2359                 long long new_pos = mmfile_tell(fp);
2360
2361                 if ((moov_end == 0) && (new_pos <= basic_header.start_offset)) {
2362                         debug_error(DEBUG, "Wrong position");
2363                         ret = MMFILE_UTIL_FAIL;
2364                         continue;
2365                 }
2366                 basic_header.start_offset = new_pos;
2367
2368         }
2369
2370 exit:
2371         mmfile_close(fp);
2372         return ret;
2373 }
2374
2375 static bool __get_genre_num(const char *buffer, int *si)
2376 {
2377         int len = strlen(buffer);
2378         char *tmp_genre = NULL;
2379
2380         /* Genre format: (###), ### */
2381         if (len > 6 || len == 0)
2382                 return false;
2383
2384         /* Check first c */
2385         if (len == 1) {
2386                 if (!g_ascii_isdigit(buffer[0]))
2387                         return false;
2388         } else {
2389                 if (!g_ascii_isdigit(buffer[1]))
2390                         return false;
2391         }
2392
2393         /* Remove bind () if exist */
2394         tmp_genre = g_strdup(buffer);
2395         if (g_str_has_prefix(tmp_genre, "(") && g_str_has_suffix(tmp_genre, ")"))
2396                 tmp_genre[0] = '0';
2397
2398         *si = atoi(tmp_genre);
2399         g_free(tmp_genre);
2400
2401         return true;
2402 }
2403
2404 static bool make_characterset_array(char ***charset_array)
2405 {
2406         char *locale = MMFileUtilGetLocale();
2407
2408         *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
2409
2410         if (*charset_array == NULL) {
2411                 debug_error(DEBUG, "calloc failed ");
2412                 if (locale != NULL)
2413                         free(locale);
2414                 return false;
2415         }
2416
2417         if (locale != NULL) {
2418                 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
2419         } else {
2420                 debug_error(DEBUG, "get locale failed");
2421                 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
2422         }
2423
2424         (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
2425         (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
2426         (*charset_array)[AV_ID3V2_UTF8] = strdup(MMFILE_CODESET_UTF8);
2427
2428         return true;
2429 }
2430
2431 static bool release_characterset_array(char **charset_array)
2432 {
2433         int i = 0;
2434
2435         if (!charset_array)
2436                 return false;
2437
2438         for (i = 0; i < AV_ID3V2_MAX; i++) {
2439                 if (charset_array[i] != NULL) {
2440                         free(charset_array[i]);
2441                         charset_array[i] = NULL;
2442                 }
2443         }
2444
2445         free(charset_array);
2446         charset_array = NULL;
2447
2448         return true;
2449 }
2450
2451 static void init_content_info(AvFileContentInfo *pInfo)
2452 {
2453         int i=0;
2454
2455         for(i = 0; i < AV_ID3TAG_MAX; i++)
2456                 pInfo->tagInfo[i].value = NULL;
2457
2458         pInfo->imageInfo.bURLInfo = false;
2459         pInfo->imageInfo.pImageBuf = NULL;
2460         pInfo->imageInfo.imageLen = 0;
2461 }
2462
2463 static void __id3tag_skip_newline(unsigned char *pTagVal, int *nTagLen, int *offset)
2464 {
2465         /* skip newline in text encoding of ID3 tag frame */
2466         while ((NEWLINE_OF_UTF16(pTagVal + *offset) || NEWLINE_OF_UTF16_R(pTagVal + *offset)) && *nTagLen > 4) {
2467                 *nTagLen -= 4;
2468                 *offset += 4;
2469         }
2470 }
2471
2472 static int __id3tag_get_text_encoding_v222(unsigned char *pTagVal, int offset)
2473 {
2474         if (pTagVal[offset - 1] == 0x00)
2475                 return AV_ID3V2_ISO_8859;
2476
2477         return AV_ID3V2_UTF16;
2478 }
2479
2480 static int __id3tag_get_text_encoding_v223(unsigned char *pTagVal, int *npTagLen, int nTextEnc, int *offset)
2481 {
2482         if ((IS_ENCODEDBY_UTF16(pTagVal + *offset) || IS_ENCODEDBY_UTF16_R(pTagVal + *offset)) && *npTagLen > 2) {
2483                 __id3tag_skip_newline(pTagVal, npTagLen, offset);
2484
2485                 if (IS_ENCODEDBY_UTF16(pTagVal + *offset) && (*npTagLen > 2)) {
2486                         *npTagLen -= 2;
2487                         *offset += 2;
2488                         return AV_ID3V2_UTF16;
2489                 } else if (IS_ENCODEDBY_UTF16_R(pTagVal + *offset) && (*npTagLen > 2)) {
2490                         *npTagLen -= 2;
2491                         *offset += 2;
2492                         return AV_ID3V2_UTF16_BE;
2493                 } else if (IS_ENCODEDBY_UTF16(pTagVal + *offset + 1) && (*npTagLen > 3)) {
2494                         *npTagLen -= 3;
2495                         *offset += 3;
2496                         return AV_ID3V2_UTF16;
2497                 } else if (IS_ENCODEDBY_UTF16_R(pTagVal + *offset + 1)  && (*npTagLen > 3)) {
2498                         *npTagLen -= 3;
2499                         *offset += 3;
2500                         return AV_ID3V2_UTF16_BE;
2501                 } else {
2502                         debug_msg(RELEASE, "id3tag never get here!!");
2503                         return nTextEnc;        /* default bypass */
2504                 }
2505         } else {
2506                 while ((pTagVal[*offset] < 0x20) && (*offset < *npTagLen)) { /* text string encoded by ISO-8859-1 */
2507                         (*npTagLen)--;
2508                         (*offset)++;
2509                 }
2510                 return AV_ID3V2_ISO_8859;
2511         }
2512 }
2513
2514 static int __id3tag_get_text_encoding_v224(unsigned char *pTagVal, int *npTagLen, int nTextEnc, int *offset)
2515 {
2516         if (nTextEnc == AV_ID3V2_UTF16 || nTextEnc == AV_ID3V2_UTF16_BE) {
2517                 __id3tag_skip_newline(pTagVal, npTagLen, offset);
2518
2519                 if ((IS_ENCODEDBY_UTF16(pTagVal + *offset) || IS_ENCODEDBY_UTF16_R(pTagVal + *offset)) && *npTagLen > 2) {
2520                         *npTagLen -= 2;
2521                         *offset += 2;
2522                         return AV_ID3V2_UTF16;
2523                 } else {
2524                         debug_msg(RELEASE, "id3tag never get here!!");
2525                         return nTextEnc;        /* default bypass */
2526                 }
2527         } else if (nTextEnc == AV_ID3V2_UTF8) {
2528                 while (pTagVal[*offset] < 0x20 && (*offset < *npTagLen)) { /* text string encoded by UTF-8 */
2529                         (*npTagLen)--;
2530                         (*offset)++;
2531                 }
2532                 return AV_ID3V2_UTF8;
2533         } else {
2534                 while (pTagVal[*offset] < 0x20 && (*offset < *npTagLen)) { /* text string encoded by ISO-8859-1 */
2535                         (*npTagLen)--;
2536                         (*offset)++;
2537                 }
2538                 return AV_ID3V2_ISO_8859;
2539         }
2540 }
2541
2542 static void __id3tag_parse_SYLT(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet, int textEncodingType, int offset)
2543 {
2544         int idx = 0;
2545         int copy_len = 0;
2546         int copy_start_pos = offset;
2547         AvSynclyricsInfo *synclyrics_info = NULL;
2548         GList *synclyrics_info_list = NULL;
2549
2550         if (nTagLen < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2551                 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)", nTagLen);
2552                 return;
2553         }
2554
2555         if ((textEncodingType == AV_ID3V2_UTF16) || (textEncodingType == AV_ID3V2_UTF16_BE)) {
2556                 debug_warning(DEBUG, "[%d] not implemented", textEncodingType);
2557                 return;
2558         }
2559
2560         for (idx = 0; idx < nTagLen; idx++) {
2561                 if (pTagVal[offset + idx] == 0x00) {
2562                         synclyrics_info = g_new0(AvSynclyricsInfo, 1);
2563                         if (textEncodingType == AV_ID3V2_UTF8)
2564                                 synclyrics_info->lyric_info = g_memdup2(pTagVal + copy_start_pos, copy_len + 1);
2565                         else
2566                                 synclyrics_info->lyric_info = mmfile_convert_to_utf8((const char *)&pTagVal[copy_start_pos], copy_len, pCharSet);
2567
2568                         synclyrics_info->time_info = (unsigned long)pTagVal[offset + idx + 1] << 24 | (unsigned long)pTagVal[offset + idx + 2] << 16 | (unsigned long)pTagVal[offset + idx + 3] << 8  | (unsigned long)pTagVal[offset + idx + 4];
2569                         idx += 4;
2570                         copy_start_pos = offset + idx + 1;
2571                         debug_msg(RELEASE, "[%lu][%s] idx[%d], copy_len[%d] copy_start_pos[%d]", synclyrics_info->time_info, synclyrics_info->lyric_info, idx, copy_len, copy_start_pos);
2572                         copy_len = 0;
2573                         synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
2574                 }
2575                 copy_len++;
2576         }
2577
2578         pInfo->pSyncLyrics = synclyrics_info_list;
2579 }
2580
2581 static bool __id3tag_parse_PIC_format(AvFileContentInfo *pInfo, unsigned char *pTagVal, int *offset)
2582 {
2583         unsigned int idx = 0;
2584
2585         /* get the mime type of Attached PICture, it is text string */
2586
2587         if (pTagVal[*offset] == '\0') {
2588                 debug_msg(RELEASE, "The picture format of PIC is not included");
2589                 return false;
2590         }
2591
2592         /* init ext variable */
2593         memset(pInfo->imageInfo.imageExt, 0, sizeof(pInfo->imageInfo.imageExt));
2594         /* get ext */
2595         while ((idx < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && (pTagVal[idx] != '\0')) {
2596                 pInfo->imageInfo.imageExt[idx] = pTagVal[idx];
2597                 idx++;
2598         }
2599
2600         *offset += idx;
2601
2602         return true;
2603 }
2604
2605 static bool __id3tag_parse_APIC_mimetype(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, int *offset)
2606 {
2607         unsigned int idx = 0;
2608         const char *MIME_PRFIX = "image/";
2609
2610         /* get the mime type of Attached PICture, it is text string */
2611
2612         if (pTagVal[*offset] == '\0') {
2613                 pInfo->imageInfo.imgMimetypeLen = 0;
2614                 debug_msg(RELEASE, "The MIME type of APIC is not included");
2615                 return false;
2616         }
2617
2618         /* init mimetype variable */
2619         memset(pInfo->imageInfo.imageMIMEType, 0, sizeof(pInfo->imageInfo.imageMIMEType));
2620         /* get mimetype */
2621         while ((idx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && (pTagVal[idx] != '\0')) {
2622                 pInfo->imageInfo.imageMIMEType[idx] = pTagVal[idx];
2623                 idx++;
2624         }
2625         pInfo->imageInfo.imgMimetypeLen = idx;
2626
2627         *offset += idx;
2628
2629         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2630                 pInfo->imageInfo.imgMimetypeLen = 0;
2631                 debug_error(DEBUG, "MIME type(%s) is not image", pInfo->imageInfo.imageMIMEType);
2632                 return false;
2633         }
2634
2635         if ((pTagVal[*offset] != '\0') || (nTagLen <= *offset)) {
2636                 debug_msg(RELEASE, "pTagVal[offset](%d) mimetype is not NULL terminated! realCpyFrameNum - offset(%d)",
2637                                         pTagVal[*offset], nTagLen - *offset);
2638                 return true;
2639         }
2640
2641         (*offset)++;/* end of MIME('\0', 1byte) */
2642         debug_msg(RELEASE, "after scaning Mime type offset(%d) value!", *offset);
2643
2644         return true;
2645 }
2646
2647 static void __id3tag_parse_APIC_pictype(AvFileContentInfo *pInfo, unsigned char *pTagVal, int *offset)
2648 {
2649         /* get the picture type of Attached PICture, it is 1byte(0xff) */
2650
2651         if (pTagVal[*offset] < MP3_ID3V2_PICTURE_TYPE_MAX)
2652                 pInfo->imageInfo.pictureType = pTagVal[*offset];
2653         else
2654                 debug_msg(RELEASE, "APIC image has invalid picture type(0x%x)", pTagVal[*offset]);
2655
2656         (*offset)++;/* PictureType(1byte) */
2657         debug_msg(RELEASE, "after scaning PictureType(%d) offset(%d) value!", pInfo->imageInfo.pictureType, *offset);
2658 }
2659
2660 static void __id3tag_parse_APIC_desc(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet, int *offset)
2661 {
2662         /* get the description of Attached PICture, it is text string */
2663
2664         int idx = 0;
2665         unsigned int tag_len = 0;
2666         char *tmp_desc = NULL;
2667
2668         if (pTagVal[*offset] == 0x0) {
2669                 debug_msg(RELEASE, "The description of APIC is not included!!!");
2670                 return;
2671         }
2672
2673         while (1) {
2674                 if (pTagVal[*offset + idx] == '\0') {
2675                         if (nTagLen < (*offset + idx)) {
2676                                 debug_error(DEBUG, "End of APIC Tag %d %d %d", nTagLen, *offset, idx);
2677                                 break;
2678                         }
2679                         /* check end of image description */
2680                         if ((pTagVal[*offset + idx + 1] == gTagJPEGHeader[0]) ||
2681                                 (pTagVal[*offset + idx + 1] == gTagPNGHeader[0])) {
2682                                 debug_msg(RELEASE, "length of description (%d)", idx);
2683                                 break;
2684                         }
2685                 }
2686                 idx++;
2687         }
2688
2689         tag_len = idx + 1;      /* length of description + '\0' */
2690
2691         tmp_desc = g_memdup2(pTagVal + *offset, tag_len);
2692
2693         /* convert description */
2694         pInfo->imageInfo.imageDescription = mmfile_convert_to_utf8(tmp_desc, tag_len, pCharSet);
2695         mmfile_free(tmp_desc);
2696         debug_msg(RELEASE, "new_desc %s", pInfo->imageInfo.imageDescription);
2697
2698         *offset += idx;
2699         if ((pTagVal[*offset] != '\0') || (nTagLen <= *offset)) {
2700                 debug_msg(RELEASE, "pTagVal[offset](%d) description is not NULL terminated! realCpyFrameNum - offset(%d)",
2701                                         pTagVal[*offset], nTagLen - *offset);
2702                 return;
2703         }
2704         (*offset)++; /* end of desceription(1byte) */
2705 }
2706
2707 static void __id3tag_parse_APIC_picture(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, int *offset)
2708 {
2709         /* get the picture of Attached PICture, it is binary data */
2710
2711         /* some content has useless '\0' in front of picture data */
2712         while (pTagVal[*offset] == '\0') {
2713                 (*offset)++;
2714         }
2715
2716         debug_msg(RELEASE, "after scaning APIC description offset(%d) value!", *offset);
2717
2718         if (nTagLen <= *offset) {
2719                 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - offset(%d)", nTagLen, *offset);
2720                 return;
2721         }
2722
2723         pInfo->imageInfo.imageLen = nTagLen - *offset;
2724         pInfo->imageInfo.pImageBuf = g_memdup2(pTagVal + *offset, pInfo->imageInfo.imageLen);
2725
2726         /* if mimetype is "-->", image date has an URL */
2727         if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2728                 pInfo->imageInfo.bURLInfo = true;
2729 }
2730
2731 static bool _mm_file_id3tag_parse_PIC(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet)
2732 {
2733         /* current position to read pTagVal */
2734         int offset = 0;
2735
2736         debug_fenter(RELEASE);
2737
2738         if (!__id3tag_parse_PIC_format(pInfo, pTagVal, &offset)) {
2739                 debug_msg(RELEASE, "PIC is not valid");
2740                 return false;
2741         }
2742
2743         __id3tag_parse_APIC_pictype(pInfo, pTagVal, &offset);
2744         __id3tag_parse_APIC_desc(pInfo, pTagVal, nTagLen, pCharSet, &offset);
2745         __id3tag_parse_APIC_picture(pInfo, pTagVal, nTagLen, &offset);
2746
2747         debug_fleave(RELEASE);
2748
2749         return true;
2750 }
2751
2752 static bool _mm_file_id3tag_parse_APIC(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet)
2753 {
2754         int offset = 0;
2755
2756         debug_fenter(RELEASE);
2757
2758         if (!__id3tag_parse_APIC_mimetype(pInfo, pTagVal, nTagLen, &offset)) {
2759                 debug_msg(RELEASE, "APIC is not valid");
2760                 return false;
2761         }
2762
2763         __id3tag_parse_APIC_pictype(pInfo, pTagVal, &offset);
2764         __id3tag_parse_APIC_desc(pInfo, pTagVal, nTagLen, pCharSet, &offset);
2765         __id3tag_parse_APIC_picture(pInfo, pTagVal, nTagLen, &offset);
2766
2767         debug_fleave(RELEASE);
2768
2769         return true;
2770 }
2771
2772 static char * __id3tag_get_v110(const char *buf, ssize_t len, const char *locale)
2773 {
2774         char *tmp_str = NULL;
2775
2776         mm_file_retv_if_fails(buf, NULL);
2777         mm_file_retv_if_fails(locale, NULL);
2778
2779         tmp_str = mmfile_convert_to_utf8(buf, len, locale);
2780
2781         /* ID3v1 tag need check length or space. */
2782         if (tmp_str && (strlen(tmp_str) == 0 || g_ascii_isspace(tmp_str[0])))
2783                 mmfile_free(tmp_str);
2784
2785         return tmp_str;
2786 }
2787
2788 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo, unsigned char *buffer)
2789 {
2790         const char *locale = MMFileUtilGetLocale();
2791
2792         debug_msg(RELEASE, "ID3tag v110--------------------------------------------------------------");
2793
2794         if (!pInfo->tagInfo[AV_ID3TAG_TITLE].value) {
2795                 pInfo->tagInfo[AV_ID3TAG_TITLE].value = __id3tag_get_v110((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, locale);
2796
2797                 debug_msg(RELEASE, "pInfo->pTitle returned =(%s)", pInfo->tagInfo[AV_ID3TAG_TITLE].value);
2798         }
2799
2800         if (!pInfo->tagInfo[AV_ID3TAG_ARTIST].value) {
2801                 pInfo->tagInfo[AV_ID3TAG_ARTIST].value = __id3tag_get_v110((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, locale);
2802
2803                 debug_msg(RELEASE, "pInfo->pArtist returned =(%s)", pInfo->tagInfo[AV_ID3TAG_ARTIST].value);
2804         }
2805
2806         if (!pInfo->tagInfo[AV_ID3TAG_ALBUM].value) {
2807                 pInfo->tagInfo[AV_ID3TAG_ALBUM].value = __id3tag_get_v110((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, locale);
2808
2809                 debug_msg(RELEASE, "pInfo->pAlbum returned =(%s)", pInfo->tagInfo[AV_ID3TAG_ALBUM].value);
2810         }
2811
2812         if (!pInfo->tagInfo[AV_ID3TAG_YEAR].value) {
2813                 pInfo->tagInfo[AV_ID3TAG_YEAR].value = __id3tag_get_v110((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, locale);
2814
2815                 debug_msg(RELEASE, "pInfo->pYear returned =(%s)", pInfo->tagInfo[AV_ID3TAG_YEAR].value);
2816         }
2817
2818         if (!pInfo->tagInfo[AV_ID3TAG_COMMENT].value) {
2819                 pInfo->tagInfo[AV_ID3TAG_COMMENT].value = __id3tag_get_v110((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, locale);
2820
2821                 debug_msg(RELEASE, "pInfo->pComment returned =(%s)", pInfo->tagInfo[AV_ID3TAG_COMMENT].value);
2822         }
2823
2824         if (!pInfo->tagInfo[AV_ID3TAG_TRACKNUM].value) {
2825                 pInfo->tagInfo[AV_ID3TAG_TRACKNUM].value = g_malloc0(ID3TAG_V110_TRACK_NUM_DIGIT);
2826                 pInfo->tagInfo[AV_ID3TAG_TRACKNUM].value[ID3TAG_V110_TRACK_NUM_DIGIT - 1] = 0;
2827                 snprintf(pInfo->tagInfo[AV_ID3TAG_TRACKNUM].value, ID3TAG_V110_TRACK_NUM_DIGIT, "%04d", (int)buffer[126]);
2828
2829                 debug_msg(RELEASE, "pInfo->pTrackNum returned =(%s)", pInfo->tagInfo[AV_ID3TAG_TRACKNUM].value);
2830         }
2831
2832         /*ID3V2 genre is stored in pInfo->tagInfo[AV_ID3TAG_GENRE].value */
2833         /*pInfo->genre is used when ID3V2 genre is invalid, or empty. */
2834         pInfo->genre = buffer[127];
2835         debug_msg(RELEASE, "pInfo->genre returned genre number (%d)", pInfo->genre);
2836
2837         return true;
2838 }
2839
2840 static AvID3TagList __get_tag_info_v222(const unsigned char *tag)
2841 {
2842         unsigned int n = 0;
2843         int i = 0;
2844
2845         while (i < 2) {
2846                 n  += tag[i++] - 'A' + 1;
2847                 n  <<= 5;
2848         }
2849         n  += tag[2];   //num, char mixted
2850
2851         for (i = 0; i < ID3TAG_NUM_V22; i++) {
2852                 if (n == tag_info_v22[i].int_name) {
2853                         return tag_info_v22[i].tag;
2854                 }
2855         }
2856
2857         debug_msg(RELEASE, "(%s) This Frame ID currently not Supports!!", tag);
2858
2859         return AV_ID3TAG_MAX;
2860 }
2861
2862 static AvID3TagList __get_tag_info_v223(const unsigned char *tag)
2863 {
2864         unsigned int n = 0;
2865         int i = 0;
2866
2867         while (i < 3) {
2868                 n  += tag[i++] - 'A' + 1;
2869                 n  <<= 5;
2870         }
2871         n  += tag[3];   //num, char mixted
2872
2873         for (i = 0; i < ID3TAG_NUM_V23; i++) {
2874                 if (n == tag_info_v23[i].int_name) {
2875                         return tag_info_v23[i].tag;
2876                 }
2877         }
2878
2879         debug_msg(RELEASE, "(%s) This Frame ID currently not Supports!!", tag);
2880
2881         return AV_ID3TAG_MAX;
2882 }
2883
2884
2885 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer, bool extract_artwork)
2886 {
2887         int curPos = MP3_TAGv2_HEADER_LEN;
2888         int frameLen = 0;
2889         int encOffset = 0;
2890         int encType = 0;
2891         char **charset_array = NULL;
2892         AvID3TagList tag_id = AV_ID3TAG_MAX;
2893
2894         if (pInfo->tagV2Info.tagLen <= 0)
2895                 return false;
2896
2897         make_characterset_array(&charset_array);
2898         init_content_info(pInfo);
2899
2900         debug_msg(RELEASE, "ID3tag v222--------------------------------------------------------------");
2901
2902         while (curPos + MP3_TAGv2_22_TXT_HEADER_LEN < pInfo->tagV2Info.tagLen) {
2903                 if (!g_ascii_isalnum(buffer[curPos]) || !g_ascii_isalnum(buffer[curPos + 1]) || !g_ascii_isalnum(buffer[curPos + 2]))
2904                         break;
2905
2906                 tag_id = __get_tag_info_v222(&buffer[curPos]);
2907                 frameLen = buffer[curPos + 3] << 16 | buffer[curPos + 4] << 8 | buffer[curPos + 5];
2908                 curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
2909                 if (curPos + frameLen > pInfo->tagV2Info.tagLen)
2910                         break;
2911
2912                 if (frameLen <= 0)
2913                         continue;
2914
2915                 if (tag_id == AV_ID3TAG_MAX || pInfo->tagInfo[tag_id].value)
2916                         goto NEXT;
2917
2918                 if (buffer[curPos] == 0x00) {
2919                         encOffset = 1;
2920                         encType = AV_ID3V2_ISO_8859;
2921                 } else if (buffer[curPos] == 0x01) {
2922                         encOffset = 1;
2923                         encType = AV_ID3V2_UTF16;
2924                 }
2925
2926                 /*in order to deliver valid string to MP */
2927                 while ((buffer[curPos + encOffset] < 0x20) && (encOffset < frameLen))
2928                         encOffset++;
2929
2930                 if (frameLen == encOffset) {
2931                         debug_warning(DEBUG, "warning: invalid frame length %d %d", frameLen, encOffset);
2932                         goto NEXT;
2933                 }
2934
2935                 curPos += encOffset;
2936                 frameLen -= encOffset;
2937
2938                 switch (tag_id) {
2939                 case AV_ID3TAG_COMMENT:
2940                         /*
2941                         https://id3.org/id3v2-00
2942                         Comment                   "COM"
2943                         Frame size                $xx xx xx
2944                         Text encoding             $xx
2945                         Language                  $xx xx xx
2946                         Short content description <textstring> $00 (00)
2947                         The actual text           <textstring>
2948                         */
2949                         if (frameLen <= 4) {
2950                                 debug_msg(RELEASE, "Too small to parse frameLen(%d)", frameLen);
2951                                 break;
2952                         }
2953
2954                         if (buffer[curPos + 4] > 0x20 && (buffer[curPos + 3] == 0x00 || buffer[curPos + 3] == 0x01)) {
2955                                 encType = __id3tag_get_text_encoding_v222(&buffer[curPos], 4);
2956                                 /*skip language data! */
2957                                 curPos += 4;
2958                                 frameLen -= 4;
2959                                 pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
2960                         } else {
2961                                 debug_msg(RELEASE, "Failed to get tag: frameLen(%d)", frameLen);
2962                         }
2963
2964                         break;
2965
2966                 case AV_ID3TAG_PICTURE:
2967                         if (extract_artwork)
2968                                 _mm_file_id3tag_parse_PIC(pInfo, &buffer[curPos], frameLen, charset_array[encType]);
2969                         break;
2970
2971                 default:
2972                         pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
2973                         break;
2974                 }
2975
2976                 if (pInfo->tagInfo[tag_id].value)
2977                         debug_msg(RELEASE, "[%d] returned = (%s)", tag_id, pInfo->tagInfo[tag_id].value);
2978 NEXT:
2979                 curPos += frameLen;
2980                 encOffset = 0;
2981                 encType = 0;
2982         }
2983
2984         release_characterset_array(charset_array);
2985
2986         return true;
2987 }
2988
2989 static void __get_v223_encoding_info(const unsigned char *buffer,
2990                                                                         int length,
2991                                                                         int *offset,
2992                                                                         unsigned int *type)
2993 {
2994         int _offset = 0;
2995
2996         if (!buffer || !offset || !type)
2997                 return;
2998
2999         if (IS_ENCODEDBY_UTF16(buffer)) {
3000                 *offset = 2;
3001                 *type = AV_ID3V2_UTF16;
3002                 return;
3003         }
3004         if (IS_ENCODEDBY_UTF16_R(buffer)) {
3005                 *offset = 2;
3006                 *type = AV_ID3V2_UTF16_BE;
3007                 return;
3008         }
3009         if (IS_ENCODEDBY_UTF16(buffer + 1)) {
3010                 *offset = 3;
3011                 *type = AV_ID3V2_UTF16;
3012                 return;
3013         }
3014         if (IS_ENCODEDBY_UTF16_R(buffer + 1)) {
3015                 *offset = 3;
3016                 *type = AV_ID3V2_UTF16_BE;
3017                 return;
3018         }
3019
3020         if (buffer[0] == 0x00) {
3021                 *offset = 1;
3022         } else {
3023                 while ((buffer[_offset] < 0x20) && (_offset < length))
3024                         _offset++;
3025                 *offset = _offset;
3026         }
3027         *type = AV_ID3V2_ISO_8859;
3028 }
3029
3030 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer, bool extract_artwork)
3031 {
3032         int extendedHeaderLen = 0;
3033         int frameLen = 0;
3034         int curPos = MP3_TAGv2_HEADER_LEN;
3035         int encOffset = 0;
3036         unsigned int encType = 0;
3037         char **charset_array = NULL;
3038         AvID3TagList tag_id = AV_ID3TAG_MAX;
3039         char *lang_info = NULL;
3040
3041         if (pInfo->tagV2Info.tagLen <= 0)
3042                 return false;
3043
3044         make_characterset_array(&charset_array);
3045         init_content_info(pInfo);
3046
3047         debug_msg(RELEASE, "ID3tag v223--------------------------------------------------------------");
3048         if (buffer[5] & 0x40) {
3049                 /* if extended header exists, skip it*/
3050                 extendedHeaderLen = buffer[10] << 21 | buffer[11] << 14 | buffer[12] << 7 | buffer[13];
3051                 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d", extendedHeaderLen);
3052                 if (extendedHeaderLen > pInfo->tagV2Info.tagLen - MP3_TAGv2_HEADER_LEN) {
3053                         debug_error(DEBUG, "extended header too long.");
3054                 } else {
3055                         curPos += extendedHeaderLen;
3056                         curPos += 4;
3057                 }
3058         }
3059
3060         while (curPos + MP3_TAGv2_23_TXT_HEADER_LEN < pInfo->tagV2Info.tagLen) {
3061                 if (!g_ascii_isalnum(buffer[curPos]) || !g_ascii_isalnum(buffer[curPos + 1]) ||
3062                         !g_ascii_isalnum(buffer[curPos + 2]) || !g_ascii_isalnum(buffer[curPos + 3]))
3063                         break;
3064
3065                 tag_id = __get_tag_info_v223(&buffer[curPos]);
3066                 frameLen = buffer[curPos + 4] << 24 | buffer[curPos + 5] << 16 | buffer[curPos + 6] << 8 | buffer[curPos + 7];
3067                 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
3068                 if (curPos + frameLen > pInfo->tagV2Info.tagLen)
3069                         break;
3070
3071                 if (frameLen <= 0)
3072                         continue;
3073
3074                 if (tag_id == AV_ID3TAG_MAX || pInfo->tagInfo[tag_id].value)
3075                         goto NEXT;
3076
3077                 __get_v223_encoding_info(buffer + curPos, frameLen, &encOffset, &encType);
3078                 if (frameLen <= encOffset) {
3079                         debug_warning(DEBUG, "warning: invalid frame length %d %d", frameLen, encOffset);
3080                         goto NEXT;
3081                 }
3082
3083                 curPos += encOffset;
3084                 frameLen -= encOffset;
3085                 encOffset = 0;
3086
3087                 if (encType != AV_ID3V2_UTF16 && encType != AV_ID3V2_UTF16_BE) {
3088                         if (tag_id != AV_ID3TAG_COMMENT && tag_id != AV_ID3TAG_UNSYNCLYRICS && tag_id != AV_ID3TAG_SYNCLYRICS) {
3089                                 debug_msg(RELEASE, "get the new text encoding type");
3090                                 encType = buffer[curPos - 1];
3091                         }
3092                 }
3093
3094                 if (encType > AV_ID3V2_MAX) {
3095                         debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%u], TAG ID[%d]", encType, tag_id);
3096                         goto NEXT;
3097                 }
3098
3099                 switch (tag_id) {
3100                 case AV_ID3TAG_COMMENT:
3101                         if (frameLen <= 3) {
3102                                 debug_msg(RELEASE, "Description info too small to parse frameLen(%d)", frameLen);
3103                                 break;
3104                         }
3105                         frameLen -= 3;
3106                         encOffset = 3;
3107
3108                         if (buffer[curPos] != 0x00 && buffer[curPos] != 0xFF && buffer[curPos] != 0xFE) {
3109                                 debug_msg(RELEASE, "failed to get Comment: frameLen(%d)", frameLen);
3110                         }
3111
3112                         encType = __id3tag_get_text_encoding_v223(&buffer[curPos], &frameLen, encType, &encOffset);
3113                         debug_msg(RELEASE, "encOffset(%d) encType(%u), frameLen(%d)", encOffset, encType, frameLen);
3114                         curPos += encOffset;
3115                         pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
3116                         break;
3117
3118                 case AV_ID3TAG_SYNCLYRICS:
3119                         if (frameLen <= 5) {
3120                                 debug_msg(RELEASE, "Synchronised lyrics too small to parse frameLen(%d)", frameLen);
3121                                 break;
3122                         }
3123                         frameLen -= 5;
3124                         encOffset = 5;
3125
3126                         if (buffer[curPos] != 0x00 && buffer[curPos] != 0xFF && buffer[curPos] != 0xFE) {
3127                                 debug_msg(RELEASE, "failed to get Synchronised lyrics Info curPos(%d), frameLen(%d)", curPos, frameLen);
3128                         }
3129                         encType = __id3tag_get_text_encoding_v223(&buffer[curPos], &frameLen, encType, &encOffset);
3130                         debug_msg(RELEASE, "encOffset(%d) encType(%u), frameLen(%d)", encOffset, encType, frameLen);
3131                         curPos += encOffset;
3132                         __id3tag_parse_SYLT(pInfo, buffer, frameLen, charset_array[encType], encType, curPos);
3133                         break;
3134
3135                 case AV_ID3TAG_UNSYNCLYRICS:
3136                         lang_info = strndup((const char *)&buffer[curPos], 3);
3137
3138                         if (frameLen <= 3) {
3139                                 debug_msg(RELEASE, "Unsynchronised lyrics too small to parse frameLen(%d)", frameLen);
3140                                 mmfile_free(lang_info);
3141                                 break;
3142                         }
3143                         frameLen -= 3;
3144                         encOffset = 3;
3145
3146                         if (buffer[curPos] != 0x00 && buffer[curPos] != 0xFF && buffer[curPos] != 0xFE) {
3147                                 debug_msg(RELEASE, "failed to get Unsynchronised lyrics Info curPos(%d), frameLen(%d)", curPos, frameLen);
3148                         }
3149                         encType = __id3tag_get_text_encoding_v223(&buffer[curPos], &frameLen, encType, &encOffset);
3150
3151                         char *char_set = NULL;
3152
3153                         debug_msg(RELEASE, "encOffset(%d) encType(%u), frameLen(%d)", encOffset, encType, frameLen);
3154
3155                         if (encType == AV_ID3V2_ISO_8859) {
3156                                 if (lang_info != NULL && !g_ascii_strcasecmp(lang_info, "KOR")) {
3157                                         char_set = strdup("EUC-KR");
3158                                 } else {
3159                                         char_set = mmfile_get_charset((const char *)&buffer[curPos]);
3160                                 }
3161                                 mmfile_free(lang_info);
3162                         }
3163
3164                         curPos += encOffset;
3165
3166                         if (!char_set) {
3167                                 pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
3168                         } else {
3169                                 pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, char_set);
3170                                 mmfile_free(char_set);
3171                         }
3172                         mmfile_free(lang_info);
3173                         break;
3174
3175                 case AV_ID3TAG_PICTURE:
3176                         if (extract_artwork)
3177                                 _mm_file_id3tag_parse_APIC(pInfo, &buffer[curPos], frameLen, charset_array[encType]);
3178                         break;
3179
3180                 default:
3181                         pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
3182                         break;
3183                 }
3184
3185                 if (pInfo->tagInfo[tag_id].value)
3186                         debug_msg(RELEASE, "[%d] returned = (%s)", tag_id, pInfo->tagInfo[tag_id].value);
3187 NEXT:
3188                 curPos += frameLen;
3189                 encOffset = 0;
3190                 encType = 0;
3191         }
3192
3193         release_characterset_array(charset_array);
3194
3195         return true;
3196 }
3197
3198 static void __get_v224_encoding_info(const unsigned char *buffer,
3199                                                                         int length,
3200                                                                         int *offset,
3201                                                                         unsigned int *type)
3202 {
3203         int _offset = 0;
3204
3205         if (!buffer || !offset || !type)
3206                 return;
3207
3208         /*in case of UTF 16 encoding */
3209         /*buffer+(position-length) data should '0x01' but in order to expansion, we don't accurately check the value. */
3210         if (IS_ENCODEDBY_UTF16(buffer)) {
3211                 *offset = 2;
3212                 *type = AV_ID3V2_UTF16;
3213                 return;
3214         }
3215
3216         if (IS_ENCODEDBY_UTF16_R(buffer)) {
3217                 *offset = 2;
3218                 *type = AV_ID3V2_UTF16_BE;
3219                 return;
3220         }
3221
3222         if (IS_ENCODEDBY_UTF16(buffer + 1)) {
3223                 *offset = 3;
3224                 *type = AV_ID3V2_UTF16;
3225                 return;
3226         }
3227         if (IS_ENCODEDBY_UTF16_R(buffer + 1)) {
3228                 *offset = 3;
3229                 *type = AV_ID3V2_UTF16_BE;
3230                 return;
3231         }
3232
3233         /*in case of UTF-16 BE encoding */
3234         if (buffer[0] == 0x02) {
3235                 _offset = 1;
3236                 while ((buffer[_offset] == '\0') && (_offset < length))
3237                         _offset++;/*null skip! */
3238                 *offset = _offset;
3239                 *type = AV_ID3V2_UTF16_BE;
3240                 return;
3241         }
3242
3243         /*in case of UTF8 encoding */
3244         if (buffer[0] == 0x03) {
3245                 _offset = 1;
3246                 while ((buffer[_offset] == '\0') && (_offset < length))
3247                         _offset++;/*null skip! */
3248                 *offset = _offset;
3249                 *type = AV_ID3V2_UTF8;
3250                 return;
3251         }
3252         /*in case of ISO-8859-1 encoding */
3253         /*buffer+(position-length) data should 0x00 but in order to expansion, we don't accurately check the value. */
3254         _offset = 1;
3255         while ((buffer[_offset] < 0x20) && (_offset < length))
3256                 _offset++;/*less than 0x20 value skip! */
3257         *offset = _offset;
3258         *type = AV_ID3V2_ISO_8859;
3259 }
3260
3261 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer, bool extract_artwork)
3262 {
3263         int extendedHeaderLen = 0;
3264         int frameLen = 0;
3265         int curPos = MP3_TAGv2_HEADER_LEN;
3266         int encOffset = 0;
3267         unsigned int encType = 0;
3268         char **charset_array = NULL;
3269         AvID3TagList tag_id = AV_ID3TAG_MAX;
3270
3271         if (pInfo->tagV2Info.tagLen <= 0)
3272                 return false;
3273
3274         make_characterset_array(&charset_array);
3275         init_content_info(pInfo);
3276
3277         debug_msg(RELEASE, "ID3tag v224--------------------------------------------------------------");
3278         if (buffer[5] & 0x40) {
3279                 /* if extended header exists, skip it*/
3280                 extendedHeaderLen = buffer[10] << 21 | buffer[11] << 14 | buffer[12] << 7 | buffer[13];
3281                 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d", extendedHeaderLen);
3282                 if (extendedHeaderLen > pInfo->tagV2Info.tagLen - MP3_TAGv2_HEADER_LEN) {
3283                         debug_error(DEBUG, "extended header too long.");
3284                 } else {
3285                         curPos += extendedHeaderLen;
3286                 }
3287         }
3288
3289         while (curPos + MP3_TAGv2_23_TXT_HEADER_LEN < pInfo->tagV2Info.tagLen) {
3290                 if (!g_ascii_isalnum(buffer[curPos]) || !g_ascii_isalnum(buffer[curPos + 1]) ||
3291                         !g_ascii_isalnum(buffer[curPos + 2]) || !g_ascii_isalnum(buffer[curPos + 3]))
3292                         break;
3293
3294                 tag_id = __get_tag_info_v223(&buffer[curPos]);
3295                 frameLen = buffer[curPos + 4] << 21 | buffer[curPos + 5] << 14 | buffer[curPos + 6] << 7 | buffer[curPos + 7];
3296                 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
3297                 if (curPos + frameLen > pInfo->tagV2Info.tagLen)
3298                         break;
3299
3300                 if (frameLen <= 0)
3301                         continue;
3302
3303                 if (tag_id == AV_ID3TAG_MAX || pInfo->tagInfo[tag_id].value)
3304                         goto NEXT;
3305
3306                 __get_v224_encoding_info(buffer + curPos, frameLen, &encOffset, &encType);
3307                 if (frameLen <= encOffset) {
3308                         debug_warning(DEBUG, "warning: invalid frame length %d %d", frameLen, encOffset);
3309                         goto NEXT;
3310                 }
3311
3312                 curPos += encOffset;
3313                 frameLen -= encOffset;
3314                 encOffset = 0;
3315
3316                 if (encType != AV_ID3V2_UTF16 && encType != AV_ID3V2_UTF16_BE) {
3317                         if (tag_id != AV_ID3TAG_COMMENT && tag_id != AV_ID3TAG_UNSYNCLYRICS && tag_id != AV_ID3TAG_SYNCLYRICS) {
3318                                 debug_msg(RELEASE, "get the new text encoding type");
3319                                 encType = buffer[curPos - 1];
3320                         }
3321                 }
3322
3323                 if (encType > AV_ID3V2_MAX) {
3324                         debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%u], TAG ID[%d]", encType, tag_id);
3325                         goto NEXT;
3326                 }
3327
3328                 switch (tag_id) {
3329                 case AV_ID3TAG_COMMENT:
3330                         /* fall through */
3331                 case AV_ID3TAG_UNSYNCLYRICS:
3332                         if (frameLen <= 3) {
3333                                 debug_msg(RELEASE, "Description info too small to parse frameLen(%d)", frameLen);
3334                                 break;
3335                         }
3336                         frameLen -= 3;
3337                         encOffset = 3;
3338
3339                         encType = __id3tag_get_text_encoding_v224(&buffer[curPos], &frameLen, encType, &encOffset);
3340                         debug_msg(RELEASE, "encOffset(%d) encType(%u), frameLen(%d)", encOffset, encType, frameLen);
3341                         curPos += encOffset;
3342                         pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
3343                         break;
3344
3345                 case AV_ID3TAG_SYNCLYRICS:
3346                         if (frameLen <= 5) {
3347                                 debug_msg(RELEASE, "Synchronised lyrics too small to parse frameLen(%d)", frameLen);
3348                                 break;
3349                         }
3350                         frameLen -= 5;
3351                         encOffset = 5;
3352
3353                         encType = __id3tag_get_text_encoding_v224(&buffer[curPos], &frameLen, encType, &encOffset);
3354                         debug_msg(RELEASE, "encOffset(%d) encType(%u), frameLen(%d)", encOffset, encType, frameLen);
3355                         curPos += encOffset;
3356                         __id3tag_parse_SYLT(pInfo, buffer, frameLen, charset_array[encType], encType, curPos);
3357                         break;
3358
3359                 case AV_ID3TAG_PICTURE:
3360                         if (extract_artwork)
3361                                 _mm_file_id3tag_parse_APIC(pInfo, &buffer[curPos], frameLen, charset_array[encType]);
3362                         break;
3363
3364                 default:
3365                         pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
3366                         break;
3367                 }
3368
3369                 if (pInfo->tagInfo[tag_id].value)
3370                         debug_msg(RELEASE, "[%d] returned = (%s)", tag_id, pInfo->tagInfo[tag_id].value);
3371 NEXT:
3372                 curPos += frameLen;
3373                 encOffset = 0;
3374                 encType = 0;
3375         }
3376
3377         release_characterset_array(charset_array);
3378
3379         return true;
3380 }
3381
3382
3383 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3384 {
3385         int genre_id = 0;
3386
3387         /* for Genre Info */
3388         if (pInfo->tagInfo[AV_ID3TAG_GENRE].value) {
3389                 /* Check integer */
3390                 if (!__get_genre_num(pInfo->tagInfo[AV_ID3TAG_GENRE].value, &genre_id)) {
3391                         debug_msg(RELEASE, "genre information is not integer [%s]", pInfo->tagInfo[AV_ID3TAG_GENRE].value);
3392                         return;
3393                 }
3394
3395                 /* If integer, check genre code. */
3396                 /* If out of range, set UNKNOWN */
3397                 if (genre_id < 0 || genre_id >= GENRE_COUNT)
3398                         genre_id = GENRE_COUNT - 1;
3399
3400                 debug_msg(RELEASE, "genre information is integer [%d]", genre_id);
3401
3402                 g_free(pInfo->tagInfo[AV_ID3TAG_GENRE].value);
3403                 pInfo->tagInfo[AV_ID3TAG_GENRE].value = g_strdup(MpegAudio_Genre[genre_id]);
3404         } else {
3405                 /* No genre in ID3V2.. So check V1 */
3406                 if (pInfo->bV1tagFound == true) {
3407                         debug_msg(RELEASE, "Genre: %d", pInfo->genre);
3408
3409                         /* If out of range, set UNKNOWN */
3410                         if (pInfo->genre > GENRE_COUNT - 1)
3411                                 pInfo->genre = GENRE_COUNT - 1;
3412
3413                         pInfo->tagInfo[AV_ID3TAG_GENRE].value = g_strdup(MpegAudio_Genre[pInfo->genre]);
3414                 } else {
3415                         debug_msg(RELEASE, "Genre was not Found.");
3416                 }
3417         }
3418 }
3419
3420 static void __free_synclyrics(gpointer data)
3421 {
3422         AvSynclyricsInfo *info = (AvSynclyricsInfo *) data;
3423
3424         if (!info)
3425                 return;
3426
3427         mmfile_free(info->lyric_info);
3428         mmfile_free(info);
3429 }
3430
3431
3432 void mm_file_free_synclyrics_list(GList *synclyrics_list)
3433 {
3434         if (!synclyrics_list)
3435                 return;
3436
3437         g_list_free_full(synclyrics_list, __free_synclyrics);
3438 }