Fix coverity issue
[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         unsigned int encSize = 0;
1344         int id3_meta = 0;
1345 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
1346         int iTunes_meta = 0;
1347 #endif
1348
1349         /* meta box */
1350         readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
1351         if (readed != 4) {
1352                 debug_error(DEBUG, "read meta box version");
1353                 goto exception;
1354         }
1355
1356         /* hdlr box */
1357         readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1358         if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1359                 debug_error(DEBUG, "read hdlr box header");
1360                 goto exception;
1361         }
1362
1363         if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
1364                 debug_warning(DEBUG, "meta type is not hdlr");
1365                 goto exception;
1366         }
1367
1368         hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
1369         hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
1370
1371         readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
1372         if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
1373                 debug_error(DEBUG, "read hdlr box");
1374                 goto exception;
1375         }
1376
1377         hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
1378
1379         /**
1380          * check tag type (ID3v2 or iTunes)
1381          */
1382         if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
1383                 debug_msg(RELEASE, "ID3v2 tag detected.");
1384
1385                 id3_meta = 1;
1386 #ifdef ENABLE_ITUNES_META
1387                 iTunes_meta = 0;
1388 #endif
1389         } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
1390                                 mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
1391
1392                 debug_msg(RELEASE, "Apple iTunes tag detected by mdir.");
1393
1394 #ifdef ENABLE_ITUNES_META
1395                 iTunes_meta = 1;
1396 #endif
1397         } else {
1398                 debug_warning(DEBUG, "unknown meta type. 4CC:[%c%c%c%c]", ((char *)&hdlrBox.handler_type)[0],
1399                                         ((char *)&hdlrBox.handler_type)[1],
1400                                         ((char *)&hdlrBox.handler_type)[2],
1401                                         ((char *)&hdlrBox.handler_type)[3]);
1402                 /*goto exception; */
1403         }
1404
1405 #ifdef ENABLE_ITUNES_META
1406         if (!id3_meta && !iTunes_meta) {
1407                 /*Check ilst.
1408                 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
1409                 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
1410                 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
1411
1412                 const char *ilst_box = "ilst";
1413                 int buf_size = strlen(ilst_box);
1414
1415                 unsigned char read_buf[buf_size + 1];
1416                 memset(read_buf, 0x00, buf_size + 1);
1417
1418                 /* skip hdlr box */
1419                 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR);       /*+4 is hdlr size field */
1420
1421                 readed = mmfile_read(fp, read_buf, buf_size);   /* to find 'ilst' */
1422                 if (readed != buf_size) {
1423                         debug_error(DEBUG, "read fail [%d]", readed);
1424                         goto exception;
1425                 }
1426
1427                 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
1428                         debug_msg(RELEASE, "Apple iTunes tag detected by ilst.");
1429                         iTunes_meta = 1;
1430                 }
1431         }
1432 #endif
1433
1434 #ifdef ENABLE_ITUNES_META
1435         if (iTunes_meta) {
1436                 /**
1437                  * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
1438                  *
1439                  *  4cc   : 4byte
1440                  *        : 4byte       size
1441                  * 'data' : 4byte
1442                  *        : 4byte       type
1443                  *        : 4byte       unknown
1444                  */
1445 #define _ITUNES_READ_BUF_SZ             20
1446 #define _ITUNES_TRACK_NUM_SZ    4
1447 #define _ITUNES_GENRE_NUM_SZ    4
1448 #define _ITUNES_COVER_TYPE_JPEG 13
1449 #define _ITUNES_COVER_TYPE_PNG          14
1450
1451                 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
1452                 int i = 0;
1453                 int cover_sz = 0, cover_type = 0, cover_found = 0;
1454                 /* int track_found = 0; */ /* , track_num = 0; */
1455                 /* int genre_found = 0; */ /* , genre_index = 0; */
1456                 /* int artist_found = 0; */ /* , artist_sz = 0; */
1457                 int limit = basic_header->size - hdlrBoxHeader.size;
1458                 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
1459
1460                 /* 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++) { */
1461                 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
1462                         readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
1463                         if (readed != _ITUNES_READ_BUF_SZ)
1464                                 goto exception;
1465
1466                         /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
1467                         but ffmpeg does not support strange cover image.
1468                         only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
1469 #if 0
1470                         /**
1471                          * Artist : Added 2010.10.28
1472                          */
1473                         if (artist_found == 0 &&
1474                             read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
1475                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1476
1477                                 artist_found = 1;
1478                                 artist_offset = mmfile_tell(fp);
1479                                 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
1480
1481                                 debug_msg(RELEASE, "----------------------------------- artist found, offset=[%lld], size=[%d]", artist_offset, artist_sz);
1482                         }
1483
1484                         /**
1485                          * Track number
1486                          */
1487                         if (track_found == 0 &&
1488                             read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
1489                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1490
1491                                 track_found = 1;
1492                                 track_offset = mmfile_tell(fp);
1493
1494                                 debug_msg(RELEASE, "----------------------------------- Track found, offset=[%lld]", track_offset);
1495                         }
1496
1497                         /**
1498                          * Genre : Added 2010.10.27
1499                          */
1500                         /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
1501                         if (genre_found == 0 &&
1502                             read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
1503                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1504
1505                                 genre_found = 1;
1506                                 genre_offset = mmfile_tell(fp);
1507
1508                                 debug_msg(RELEASE, "----------------------------------- genre found, offset=[%lld]", genre_offset);
1509                         }
1510 #endif
1511
1512                         /**
1513                          * Cover image
1514                          */
1515
1516                         if (cover_found == 0 &&
1517                             read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
1518                             read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1519
1520                                 cover_found = 1;
1521                                 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
1522                                 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
1523
1524                                 cover_offset = mmfile_tell(fp);
1525
1526                                 debug_msg(RELEASE, "----------------------------------- cover_found found,  offset=[%lld]", cover_offset);
1527                         }
1528
1529                         mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR);  /*FIXME: poor search*/
1530                 } /*loop*/
1531
1532                 /*ffmpeg extract artist, tracknum, except cover image. see mov_read_udta_string()*/
1533 #if 0
1534                 if (artist_found) {
1535                         if (artist_sz > 0) {
1536                                 mmfile_seek(fp, artist_offset, SEEK_SET);
1537
1538                                 if (formatContext->artist) {
1539                                         debug_msg(RELEASE, "----------------------------------- previous artist was [%s] ", formatContext->artist);
1540                                         free(formatContext->artist);
1541                                 }
1542
1543                                 debug_msg(RELEASE, "----------------------------------- new artist will be allocated with size (len+1) [%d] ", artist_sz + 1);
1544                                 formatContext->artist = g_malloc0(artist_sz + 1);
1545
1546                                 if (formatContext->artist) {
1547                                         readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1548                                         formatContext->artist[artist_sz] = '\0';
1549
1550                                         debug_msg(RELEASE, "----------------------------------- new artist is [%s] ", formatContext->artist);
1551
1552                                         if (readed != artist_sz) {
1553                                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d", readed, artist_sz);
1554                                                 mmfile_free(formatContext->artist);
1555                                         }
1556                                 }
1557                         }
1558                 }
1559
1560                 if (track_found) {
1561                         mmfile_seek(fp, track_offset, SEEK_SET);
1562                         readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1563                         if (readed != _ITUNES_TRACK_NUM_SZ) {
1564                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d", readed, _ITUNES_TRACK_NUM_SZ);
1565                         } else {
1566                                 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1567                                 if (!formatContext->tagTrackNum) {
1568                                         memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1569                                         snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1570                                         formatContext->tagTrackNum = g_strdup((const char *)read_buf);
1571                                 }
1572                         }
1573                 }
1574
1575                 if (genre_found) {
1576                         mmfile_seek(fp, genre_offset, SEEK_SET);
1577                         readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1578                         if (readed != _ITUNES_GENRE_NUM_SZ) {
1579                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d", readed, _ITUNES_GENRE_NUM_SZ);
1580                         } else {
1581                                 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1582                                 debug_msg(RELEASE, "genre index=[%d] ", genre_index);
1583
1584                                 if (genre_index > 0 && genre_index < GENRE_COUNT)       {
1585                                         if (!formatContext->genre) {
1586                                                 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1587                                                 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1588                                                 debug_msg(RELEASE, "genre string=[%s] ", read_buf);
1589                                                 formatContext->genre = g_strdup((const char *)read_buf);
1590                                         }
1591                                 }
1592                         }
1593                 }
1594 #endif
1595
1596                 /*
1597                         1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1598                         Music Cover Art Image Profile
1599                         - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1600                         - RGB (screen standard)
1601                         - Minimum size of 600 x 600 pixels
1602                         - Images must be at least 72 dpi
1603
1604                         2)I found below info from google.
1605                         cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1606
1607                         3)So, FIXME when cover image format is tif!
1608                 */
1609                 if (cover_found) {
1610                         if (cover_sz > 0) {
1611                                 mmfile_seek(fp, cover_offset, SEEK_SET);
1612
1613                                 formatContext->artwork = g_malloc0(cover_sz);
1614                                 formatContext->artworkSize = cover_sz;
1615                                 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1616                                         formatContext->artworkMime = g_strdup("image/jpeg");
1617                                 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1618                                         formatContext->artworkMime = g_strdup("image/png");
1619                                         /*} else if (cover_type == _ITUNES_COVER_TYPE_TIF) {
1620                                                 formatContext->artworkMime = g_strdup("image/tif");*/
1621                                 } else {
1622                                         debug_warning(DEBUG, "Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1623                                         formatContext->artworkMime = g_strdup("image/jpeg");
1624                                 }
1625
1626                                 if (formatContext->artwork) {
1627                                         readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1628                                         if (readed != cover_sz) {
1629                                                 debug_error(DEBUG, "failed to read. ret = %d, in = %d", readed, cover_sz);
1630                                                 mmfile_free(formatContext->artwork);
1631                                                 formatContext->artworkSize = 0;
1632                                                 mmfile_free(formatContext->artworkMime);
1633                                         }
1634                                 }
1635                         }
1636                 }
1637
1638                 /*reset seek position*/
1639                 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1640
1641                 return MMFILE_UTIL_SUCCESS;
1642
1643         } else
1644 #endif
1645                 if (id3_meta) {
1646                         /**
1647                          * ID3v2
1648                          */
1649                         /* skip hdlr box name */
1650                         mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1651
1652                         /* id3 tag box */
1653                         readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1654                         if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1655                                 debug_error(DEBUG, "read id3v2 box header");
1656                                 goto exception;
1657                         }
1658
1659                         id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1660                         id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1661
1662                         if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1663                                 debug_warning(DEBUG, "meta type is not id3v2");
1664                                 goto exception;
1665                         }
1666
1667                         readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1668                         if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1669                                 debug_error(DEBUG, "read id3v2 box");
1670                                 goto exception;
1671                         }
1672
1673                         id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1674
1675                         id3v2Box.id3v2Data = g_malloc0(id3v2Len);
1676
1677                         readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1678                         if (readed != id3v2Len) {
1679                                 debug_error(DEBUG, "read id3tag data error");
1680                                 goto exception;
1681                         }
1682
1683                         /* check id3v2 */
1684                         if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1685                                 debug_error(DEBUG, "it is not id3tag");
1686                                 goto exception;
1687                         }
1688
1689                         if (id3v2Box.id3v2Data[3] == 0xFF ||  id3v2Box.id3v2Data[4] == 0xFF ||
1690                             id3v2Box.id3v2Data[6] >= 0x80 ||  id3v2Box.id3v2Data[7] >= 0x80 ||
1691                             id3v2Box.id3v2Data[8] >= 0x80 ||  id3v2Box.id3v2Data[9] >= 0x80) {
1692                                 debug_error(DEBUG, "it is not valid id3tag");
1693                                 goto exception;
1694                         }
1695
1696                         tagVersion = id3v2Box.id3v2Data[3];
1697                         if (tagVersion > 4) {
1698                                 debug_error(DEBUG, "tag version is too high");
1699                                 goto exception;
1700                         }
1701
1702                         encSize = mmfile_io_le_uint32((unsigned int)&id3v2Box.id3v2Data[6]);
1703                         tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1704                         tagInfo.tagV2Info.tagLen += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
1705                         tagInfo.tagV2Info.tagVersion = tagVersion;
1706                         tagInfo.fileLen = id3v2Len;
1707
1708                         /* set id3v2 data to formatContext */
1709                         switch (tagVersion) {
1710                         case 2:
1711                                 versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data, formatContext->extract_artwork);
1712                                 break;
1713                         case 3:
1714                                 versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data, formatContext->extract_artwork);
1715                                 break;
1716                         case 4:
1717                                 versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data, formatContext->extract_artwork);
1718                                 break;
1719                         case 1:
1720                         default:
1721                                 debug_error(DEBUG, "tag vesion is not support");
1722                                 versionCheck = false;
1723                                 break;
1724                         }
1725
1726                         if (versionCheck == false) {
1727                                 debug_error(DEBUG, "tag parsing is fail");
1728                                 goto exception;
1729                         }
1730
1731                         formatContext->title = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_TITLE].value);
1732                         formatContext->artist = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_ARTIST].value);
1733                         formatContext->copyright = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_COPYRIGHT].value);
1734                         formatContext->comment = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_COMMENT].value);
1735                         formatContext->album = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_ALBUM].value);
1736                         formatContext->album_artist = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_ALBUM_ARTIST].value);
1737                         formatContext->year = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_YEAR].value);
1738                         formatContext->genre = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_GENRE].value);
1739                         formatContext->tagTrackNum = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_TRACKNUM].value);
1740                         formatContext->composer = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_COMPOSER].value);
1741                         formatContext->classification = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_CONTENT_GROUP].value);
1742                         formatContext->conductor = g_strdup((const char *)tagInfo.tagInfo[AV_ID3TAG_CONDUCTOR].value);
1743
1744                         if (tagInfo.imageInfo.pImageBuf && tagInfo.imageInfo.imageLen > 0) {
1745                                 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1746                                 formatContext->artwork = g_memdup2(tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1747                         }
1748
1749                         mm_file_free_AvFileContentInfo(&tagInfo);
1750                         mmfile_free(id3v2Box.id3v2Data);
1751
1752                         /*reset seek position*/
1753                         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1754
1755                         return MMFILE_UTIL_SUCCESS;
1756
1757                 }
1758
1759
1760 exception:
1761         mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1762         mmfile_free(id3v2Box.id3v2Data);
1763         mm_file_free_AvFileContentInfo(&tagInfo);
1764
1765         return MMFILE_UTIL_FAIL;
1766 }
1767
1768 int mm_file_get_int_value_from_xml_string(const char* xml_str, const char* param_name, int* value)
1769 {
1770         char *value_start, *value_end, *endptr;
1771         const short value_length_max = 12;
1772         char init_view_ret[value_length_max];
1773         int value_length = 0;
1774
1775         if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1776                 debug_error(DEBUG, "error: incorrect or non-existing parameter");
1777                 return MMFILE_UTIL_FAIL;
1778         }
1779
1780         value_start = strstr(xml_str, param_name) + strlen(param_name);
1781         while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1782                 value_start++;
1783
1784         value_end = strchr(value_start, '<');
1785         if (!value_end) {
1786                 debug_error(DEBUG, "error: incorrect XML");
1787                 return MMFILE_UTIL_FAIL;
1788         }
1789
1790         value_length = value_end - value_start;
1791         while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1792                 value_length--;
1793
1794         int i = 0;
1795         if (value_start[i] == '+' || value_start[i] == '-')
1796                         i++;
1797         while (i < value_length) {
1798                 if (value_start[i] < '0' || value_start[i] > '9') {
1799                         debug_error(DEBUG, "error: incorrect value, integer was expected");
1800                         return MMFILE_UTIL_FAIL;
1801                 }
1802                 i++;
1803         }
1804
1805         if (value_length >= value_length_max || value_length < 1) {
1806                 debug_error(DEBUG, "error: empty XML value or incorrect range");
1807                 return MMFILE_UTIL_FAIL;
1808         }
1809
1810         memset(init_view_ret, 0x00, value_length_max);
1811         if (g_strlcpy(init_view_ret, value_start, value_length_max) >= value_length_max) {
1812                 debug_error(DEBUG, "error: truncation occurred");
1813                 return MMFILE_UTIL_FAIL;
1814         }
1815
1816
1817         *value = strtol(init_view_ret, &endptr, 10);
1818         if (endptr == init_view_ret) {
1819                 debug_error(DEBUG, "error: no digits were found");
1820                 return MMFILE_UTIL_FAIL;
1821         }
1822
1823         return MMFILE_UTIL_SUCCESS;
1824 }
1825
1826 int mm_file_get_string_value_from_xml_string(const char* xml_str, const char* param_name, char** value)
1827 {
1828         char *value_start, *value_end;
1829         const short value_length_max = 256;
1830         int value_length = 0;
1831
1832         if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1833                 debug_error(DEBUG, "error: incorrect or non-existing parameter");
1834                 return MMFILE_UTIL_FAIL;
1835         }
1836
1837         value_start = strstr(xml_str, param_name) + strlen(param_name);
1838         while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1839                 value_start++;
1840
1841         value_end = strchr(value_start, '<');
1842         if (!value_end) {
1843                 debug_error(DEBUG, "error: incorrect XML");
1844                 return MMFILE_UTIL_FAIL;
1845         }
1846
1847         value_length = value_end - value_start;
1848         while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1849                 value_length--;
1850
1851         if (value_length >= value_length_max || value_length < 1) {
1852                 debug_error(DEBUG, "error: empty XML value or incorrect range");
1853                 return MMFILE_UTIL_FAIL;
1854         }
1855
1856         *value = (char*)calloc(value_length, sizeof(char));
1857         if (*value == NULL) {
1858                 debug_error(DEBUG, "error: calloc failed");
1859                 return MMFILE_UTIL_FAIL;
1860         }
1861         strncpy(*value, value_start, value_length);
1862
1863         return MMFILE_UTIL_SUCCESS;
1864 }
1865
1866 int mm_file_get_bool_value_from_xml_string(const char* xml_str, const char* param_name, bool* value)
1867 {
1868         char *value_start = NULL;
1869         char *value_end = NULL;
1870         int value_length = 0;
1871
1872         if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1873                 debug_error(DEBUG, "error: incorrect or non-existing parameter");
1874                 return MMFILE_UTIL_FAIL;
1875         }
1876
1877         value_start = strstr(xml_str, param_name) + strlen(param_name);
1878         while ((value_start != NULL) && ((value_start[0] == ' ') || (value_start[0] == '\t')))
1879                 value_start++;
1880
1881         value_end = strchr(value_start, '<');
1882         if (value_end == NULL) {
1883                 debug_error(DEBUG, "error: incorrect XML.");
1884                 return MMFILE_UTIL_FAIL;
1885         }
1886
1887         value_length = value_end - value_start;
1888         while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1889                 value_length--;
1890
1891         if (value_length < 1) {
1892                 debug_error(DEBUG, "error: empty XML value or incorrect range");
1893                 return MMFILE_UTIL_FAIL;
1894         }
1895
1896         *value = strstr(value_start, "true") ? true : false;
1897
1898         return MMFILE_UTIL_SUCCESS;
1899 }
1900
1901 int ParseSpatialVideoMetadataFromXMLString(const char *xmlStr, MMFileFormatContext *formatContext)
1902 {
1903         const char is_spherical_str[] = "<GSpherical:Spherical>";
1904         const char is_stitched_str[] = "<GSpherical:Stitched>";
1905         const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
1906         const char projection_type_str[] = "<GSpherical:ProjectionType>";
1907         const char stereo_mode_str[] = "<GSpherical:StereoMode>";
1908         const char source_count_str[] = "<GSpherical:SourceCount>";
1909         const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
1910         const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
1911         const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
1912         const char timestamp_str[] = "<GSpherical:Timestamp>";
1913         const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
1914         const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
1915         const char cropped_area_image_width_str[] = "<GSpherical:CroppedAreaImageWidthPixels>";
1916         const char cropped_area_image_height_str[] = "<GSpherical:CroppedAreaImageHeightPixels>";
1917         const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
1918         const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
1919
1920         mm_file_get_bool_value_from_xml_string(xmlStr, is_spherical_str, (bool*)&formatContext->isSpherical);
1921         mm_file_get_bool_value_from_xml_string(xmlStr, is_stitched_str, (bool*)&formatContext->isStitched);
1922
1923         debug_msg(RELEASE, "isSpherical = %d", formatContext->isSpherical);
1924         debug_msg(RELEASE, "isStitched = %d", formatContext->isStitched);
1925
1926         if (formatContext->isSpherical && formatContext->isStitched) {
1927                 mm_file_get_string_value_from_xml_string(xmlStr, stitching_software_str, &formatContext->stitchingSoftware);
1928                 mm_file_get_string_value_from_xml_string(xmlStr, projection_type_str, &formatContext->projectionType);
1929                 mm_file_get_string_value_from_xml_string(xmlStr, stereo_mode_str, &formatContext->stereoMode);
1930                 mm_file_get_int_value_from_xml_string(xmlStr, source_count_str, &formatContext->sourceCount);
1931                 mm_file_get_int_value_from_xml_string(xmlStr, init_view_heading_str, &formatContext->initViewHeading);
1932                 mm_file_get_int_value_from_xml_string(xmlStr, init_view_pitch_str, &formatContext->initViewPitch);
1933                 mm_file_get_int_value_from_xml_string(xmlStr, init_view_roll_str, &formatContext->initViewRoll);
1934                 mm_file_get_int_value_from_xml_string(xmlStr, timestamp_str, &formatContext->timestamp);
1935                 mm_file_get_int_value_from_xml_string(xmlStr, full_pano_width_str, &formatContext->fullPanoWidth);
1936                 mm_file_get_int_value_from_xml_string(xmlStr, full_pano_height_str, &formatContext->fullPanoHeight);
1937                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_width_str, &formatContext->croppedAreaImageWidth);
1938                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_height_str, &formatContext->croppedAreaImageHeight);
1939                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_left_str, &formatContext->croppedAreaLeft);
1940                 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_top_str, &formatContext->croppedAreaTop);
1941
1942                 debug_msg(RELEASE, "stitchingSoftware = %s", formatContext->stitchingSoftware);
1943                 debug_msg(RELEASE, "projectionType = %s", formatContext->projectionType);
1944                 debug_msg(RELEASE, "stereoMode = %s", formatContext->stereoMode);
1945                 debug_msg(RELEASE, "sourceCount %d", formatContext->sourceCount);
1946                 debug_msg(RELEASE, "initViewHeading = %d", formatContext->initViewHeading);
1947                 debug_msg(RELEASE, "initViewPitch = %d", formatContext->initViewPitch);
1948                 debug_msg(RELEASE, "initViewRoll = %d", formatContext->initViewRoll);
1949                 debug_msg(RELEASE, "timestamp = %d", formatContext->timestamp);
1950                 debug_msg(RELEASE, "fullPanoWidthPixels = %d", formatContext->fullPanoWidth);
1951                 debug_msg(RELEASE, "fullPanoHeightPixels = %d", formatContext->fullPanoHeight);
1952                 debug_msg(RELEASE, "croppedAreaImageWidth = %d", formatContext->croppedAreaImageWidth);
1953                 debug_msg(RELEASE, "croppedAreaImageHeight = %d", formatContext->croppedAreaImageHeight);
1954                 debug_msg(RELEASE, "croppedAreaLeft = %d", formatContext->croppedAreaLeft);
1955                 debug_msg(RELEASE, "croppedAreaTop = %d", formatContext->croppedAreaTop);
1956         }
1957
1958         return MMFILE_UTIL_SUCCESS;
1959 }
1960
1961 #define BIG_CONTENT_BOX_SIZE_LEN 8
1962
1963 int MMFileUtilGetMetaDataFromMKV(MMFileFormatContext *formatContext)
1964 {
1965         MMFileIOHandle *fp = NULL;
1966         int probe_size = 10000;
1967         unsigned char *buffer = NULL;
1968         int ret = 0;
1969         int i;
1970         long long file_size = 0;
1971
1972         MMFILE_WEBM_PROJ_V2_BOX v2box = { 0, };
1973         MMFILE_WEBM_EQUI_PROJ_V2_BOX equi = { 0, };
1974         MMFILE_WEBM_CBMP_PROJ_V2_BOX cbmp = { 0, };
1975         MMFILE_WEBM_POSE_ELEMENT_V2_BOX pose = { 0, };
1976
1977         ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1978         if (ret == MMFILE_UTIL_FAIL) {
1979                 debug_error(DEBUG, "error: mmfile_open");
1980                 goto exit;
1981         }
1982
1983         file_size = mmfile_seek(fp, 0, SEEK_END);
1984         if (file_size == MMFILE_UTIL_FAIL) {
1985                 debug_error(DEBUG, "mmfile operation failed");
1986                 goto exit;
1987         }
1988
1989         probe_size = (file_size > probe_size) ? probe_size : file_size;
1990         buffer = (unsigned char *)malloc(probe_size * sizeof(unsigned char));
1991         if (!buffer) {
1992                 debug_error(DEBUG, "malloc failed");
1993                 goto exit;
1994         }
1995
1996         ret = mmfile_seek(fp, 0, SEEK_SET);
1997         if (ret == MMFILE_UTIL_FAIL) {
1998                 debug_error(DEBUG, "mmfile operation failed");
1999                 goto exit;
2000         }
2001
2002         ret = mmfile_read(fp, buffer, probe_size * sizeof(unsigned char));
2003         if (ret == MMFILE_UTIL_FAIL) {
2004                 debug_error(DEBUG, "mmfile operation failed");
2005                 goto exit;
2006         }
2007
2008         /* FIXME (m.alieksieie): It's better to use some EBML parser here*/
2009         for (i = 0; i + 3 < probe_size; ++i) {
2010                 if (*(unsigned int *)(buffer + i) == FOURCC('e', 'q', 'u', 'i') ||
2011                                 *(unsigned int *)(buffer + i) == FOURCC('c', 'b', 'm', 'p')) {
2012                         debug_msg(DEBUG, "projection data found at offset %d bytes", i);
2013                         break;
2014                 }
2015         }
2016
2017         if (i + 3 == probe_size) {
2018                 debug_msg(DEBUG, "projection info wasn't found");
2019                 ret = MMFILE_UTIL_SUCCESS;
2020                 goto exit;
2021         }
2022
2023         if ((i - (int)sizeof(MMFILE_WEBM_PROJ_V2_BOX)) < 0) {
2024                 debug_error(DEBUG, "error: invalid supposed projection info location");
2025                 ret = MMFILE_UTIL_FAIL;
2026                 goto exit;
2027         }
2028
2029         ret = mmfile_seek(fp, i - sizeof(MMFILE_WEBM_PROJ_V2_BOX), SEEK_SET);
2030         if (ret == MMFILE_UTIL_FAIL) {
2031                 debug_error(DEBUG, "error: failed to seek to the supposed projection info location");
2032                 goto exit;
2033         }
2034
2035         ret = mmfile_read(fp, (unsigned char *)&v2box, sizeof(MMFILE_WEBM_PROJ_V2_BOX));
2036         if (ret == MMFILE_UTIL_FAIL) {
2037                 debug_error(DEBUG, "mmfile operation failed");
2038                 goto exit;
2039         }
2040
2041         if (v2box.proj_type_box_value == PROJECTION_TYPE_EQUI) {
2042                 debug_msg(DEBUG, "Equirectangular projection is used");
2043
2044                 ret = mmfile_read(fp, (unsigned char *)&equi, sizeof(MMFILE_WEBM_EQUI_PROJ_V2_BOX));
2045                 if (ret == MMFILE_UTIL_FAIL) {
2046                         debug_error(DEBUG, "error: failed to read equirectangular element");
2047                         goto exit;
2048                 }
2049                 if (strncmp((char *)equi.proj_priv_box_name, "equi", 4) == 0) {
2050                         formatContext->equiBoundsTopV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_top);
2051                         formatContext->equiBoundsBottomV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_bottom);
2052                         formatContext->equiBoundsLeftV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_left);
2053                         formatContext->equiBoundsRightV2 = mmfile_io_be_uint32(equi.equi_projection_bounds_right);
2054                 } else {
2055                         debug_error(DEBUG, "error: failed to read equirectangular element");
2056                         ret = MMFILE_UTIL_SUCCESS;
2057                         goto exit;
2058                 }
2059         }
2060         if (v2box.proj_type_box_value == PROJECTION_TYPE_CBMP) {
2061                 debug_msg(DEBUG, "Cubemap projection is used");
2062
2063                 ret = mmfile_read(fp, (unsigned char *)&cbmp, sizeof(MMFILE_WEBM_CBMP_PROJ_V2_BOX));
2064                 if (ret == MMFILE_UTIL_FAIL) {
2065                         debug_error(DEBUG, "error: failed to read cubemap element");
2066                         goto exit;
2067                 }
2068                 if (strncmp((char *)cbmp.proj_priv_box_name, "cbmp", 4) == 0) {
2069                         formatContext->cbmpLayoutV2 = mmfile_io_be_uint32(cbmp.cbmp_projection_layout);
2070                         formatContext->cbmpPaddingV2 = mmfile_io_be_uint32(cbmp.cbmp_projection_padding);
2071                 } else {
2072                         debug_error(DEBUG, "error: failed to read cubemap element");
2073                         ret = MMFILE_UTIL_FAIL;
2074                         goto exit;
2075                 }
2076         }
2077
2078         ret = mmfile_read(fp, (unsigned char *)&pose, sizeof(MMFILE_WEBM_POSE_ELEMENT_V2_BOX));
2079         if (ret == MMFILE_UTIL_FAIL) {
2080                 debug_error(DEBUG, "error: failed to read pose info");
2081                 goto exit;
2082         }
2083
2084         if (pose.pose_yaw_element_id == POSE_YAW_ELEMENT_ID) {
2085                 formatContext->poseYawV2 = (uint)mmfile_io_be_float32(pose.pose_yaw_element_value);
2086         } else {
2087                 debug_error(DEBUG, "error: failed to pose yaw element");
2088                 ret = MMFILE_UTIL_FAIL;
2089                 goto exit;
2090         }
2091         if (pose.pose_pitch_element_id == POSE_PITCH_ELEMENT_ID) {
2092                 formatContext->posePitchV2 = (uint)mmfile_io_be_float32(pose.pose_pitch_element_value);
2093         } else {
2094                 debug_error(DEBUG, "error: failed to pose pitch element");
2095                 ret = MMFILE_UTIL_FAIL;
2096                 goto exit;
2097         }
2098         if (pose.pose_roll_element_id == POSE_ROLL_ELEMENT_ID) {
2099                 formatContext->poseRollV2 = (uint)mmfile_io_be_float32(pose.pose_roll_element_value);
2100         } else {
2101                 debug_error(DEBUG, "error: failed to pose roll element");
2102                 ret = MMFILE_UTIL_FAIL;
2103                 goto exit;
2104         }
2105
2106 exit:
2107         mmfile_close(fp);
2108
2109         if (buffer)
2110                 free(buffer);
2111
2112         return ret;
2113 }
2114
2115 int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
2116 {
2117         MMFileIOHandle *fp = NULL;
2118         int ret = 0;
2119         int readed;
2120         unsigned long long chunk_size = 0;
2121         long long moov_end = 0;
2122         MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
2123         int junk_counter = 0;
2124
2125         ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
2126         if (ret == MMFILE_UTIL_FAIL) {
2127                 debug_error(DEBUG, "error: mmfile_open");
2128                 goto exit;
2129         }
2130
2131         basic_header.start_offset = mmfile_tell(fp);
2132
2133         if (g_junk_counter_limit == 0)
2134                 g_junk_counter_limit = mmfile_get_int_from_ini(MMFILE_INI_JUNKCNTLIMIT, MMFILE_DEFAULT_JUNKCNTLIMIT);
2135
2136         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)) {
2137                 basic_header.size = mmfile_io_be_uint32(basic_header.size);
2138                 basic_header.type = mmfile_io_le_uint32(basic_header.type);
2139
2140                 if (basic_header.size == 0) {
2141                         debug_warning(DEBUG, "header is invalid.");
2142                         basic_header.size = readed;
2143                         basic_header.type = 0;
2144                         chunk_size = basic_header.size;
2145
2146                         if ((moov_end != 0) && (moov_end < basic_header.start_offset)) {
2147                                 debug_msg(DEBUG, "found junk data but moov data already was extracted, so junk counter will be increase: %d", junk_counter);
2148                                 junk_counter++;
2149
2150                                 /* stop the loop for junk case. */
2151                                 if ((g_junk_counter_limit > 0) && (junk_counter > g_junk_counter_limit)) {
2152                                         debug_msg(DEBUG, "stop the loop by junk-data checker");
2153                                         ret = MMFILE_UTIL_FAIL;
2154                                         continue;
2155                                 }
2156                         }
2157                 } else if (basic_header.size == 1) {
2158                         int i = 0;
2159                         unsigned char temp[BIG_CONTENT_BOX_SIZE_LEN] = {0, };
2160                         unsigned long long size = 0;
2161
2162                         mmfile_read(fp, (unsigned char *)&temp, BIG_CONTENT_BOX_SIZE_LEN);
2163
2164                         for (i = 0; i < BIG_CONTENT_BOX_SIZE_LEN; i++)
2165                                 size |= (unsigned long long)temp[i] << (BIG_CONTENT_BOX_SIZE_LEN - 1 - i) * BIG_CONTENT_BOX_SIZE_LEN;
2166                         chunk_size = size;
2167                         junk_counter = 0;
2168                 } else {
2169                         chunk_size = basic_header.size;
2170                         junk_counter = 0;
2171                 }
2172
2173                 switch (basic_header.type) {
2174                         case FOURCC('m', 'o', 'o', 'v'): {
2175                                         debug_msg(RELEASE, "MPEG4: [moov] SIZE: [%lld]Byte", chunk_size);
2176                                         moov_end = basic_header.start_offset + chunk_size;
2177                                         break;
2178                                 }
2179                         case FOURCC('u', 'd', 't', 'a'): {
2180                                         debug_msg(RELEASE, "MPEG4: [udat] SIZE: [%lld]Byte", chunk_size);
2181                                         break;
2182                                 }
2183                                 /*/////////////////////////////////////////////////////////////// */
2184                                 /*                  Extracting Tag Data                        // */
2185                                 /*/////////////////////////////////////////////////////////////// */
2186                         case FOURCC('t', 'i', 't', 'l'): {
2187                                         debug_msg(RELEASE, "MPEG4: [titl] SIZE: [%lld]Byte", chunk_size);
2188                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
2189                                         break;
2190                                 }
2191                         case FOURCC('d', 's', 'c', 'p'): {
2192                                         debug_msg(RELEASE, "MPEG4: [dscp] SIZE: [%lld]Byte", chunk_size);
2193                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
2194                                         break;
2195                                 }
2196                         case FOURCC('c', 'p', 'r', 't'): {
2197                                         debug_msg(RELEASE, "MPEG4: [cprt] SIZE: [%lld]Byte", chunk_size);
2198                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
2199                                         break;
2200                                 }
2201                         case FOURCC('p', 'e', 'r', 'f'): {
2202                                         debug_msg(RELEASE, "MPEG4: [perf] SIZE: [%lld]Byte", chunk_size);
2203                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
2204                                         break;
2205                                 }
2206                         case FOURCC('a', 'u', 't', 'h'): {
2207                                         debug_msg(RELEASE, "MPEG4: [auth] SIZE: [%lld]Byte", chunk_size);
2208                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
2209                                         break;
2210                                 }
2211                         case FOURCC('g', 'n', 'r', 'e'): {
2212                                         debug_msg(RELEASE, "MPEG4: [gnre] SIZE: [%lld]Byte", chunk_size);
2213                                         GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
2214                                         break;
2215                                 }
2216                         case FOURCC('a', 'l', 'b', 'm'): {
2217                                         debug_msg(RELEASE, "MPEG4: [albm] SIZE: [%lld]Byte", chunk_size);
2218                                         GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
2219                                         break;
2220                                 }
2221                         case FOURCC('y', 'r', 'r', 'c'): {
2222                                         debug_msg(RELEASE, "MPEG4: [yrrc] SIZE: [%lld]Byte", chunk_size);
2223                                         GetYearFromYearTagBox(formatContext, fp, &basic_header);
2224                                         break;
2225                                 }
2226                         case FOURCC('r', 't', 'n', 'g'): {
2227                                         debug_msg(RELEASE, "MPEG4: [rtng] SIZE: [%lld]Byte", chunk_size);
2228                                         GetRatingFromRatingTagBox(formatContext, fp, &basic_header);  /* not use */
2229                                         break;
2230                                 }
2231                         case FOURCC('c', 'l', 's', 'f'): {
2232                                         debug_msg(RELEASE, "MPEG4: [clsf] SIZE: [%lld]Byte", chunk_size);
2233                                         GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
2234                                         break;
2235                                 }
2236                         case FOURCC('k', 'y', 'w', 'd'): {
2237                                         debug_msg(RELEASE, "MPEG4: [kywd] SIZE: [%lld]Byte", chunk_size);
2238                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2239                                         break;
2240                                 }
2241                         case FOURCC('l', 'o', 'c', 'i'): {
2242                                         debug_msg(RELEASE, "MPEG4: [loci] SIZE: [%lld]Byte", chunk_size);
2243                                         GetLocationFromLociTagBox(formatContext, fp, &basic_header);
2244                                         break;
2245                                 }
2246                                 /* Check smta in user data field (moov) to be compatible with android */
2247                         case FOURCC('s', 'm', 't', 'a'): {
2248                                         debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte", chunk_size);
2249                                         GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
2250                                         break;
2251                                 }
2252                                 /* Check cdis in user data field (moov) to be compatible with android */
2253                         case FOURCC('c', 'd', 'i', 's'): {
2254                                         debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte", chunk_size);
2255                                         GetValueFromCDISTagBox(formatContext, fp, &basic_header);
2256                                         break;
2257                                 }
2258                                 /*/////////////////////////////////////////////////////////////// */
2259                                 /*                  Extracting ID3 Tag Data                    // */
2260                                 /*/////////////////////////////////////////////////////////////// */
2261                         case FOURCC('m', 'e', 't', 'a'): {
2262                                         debug_msg(RELEASE, "MPEG4: [meta] SIZE: [%lld]Byte", chunk_size);
2263                                         GetTagFromMetaBox(formatContext, fp, &basic_header);
2264                                         break;
2265                                 }
2266
2267                         case FOURCC('t', 'r', 'a', 'k'): {
2268                                         debug_msg(RELEASE, "MPEG4: [trak] SIZE: [%lld]Byte", chunk_size);
2269                                         break;
2270                                 }
2271                         case FOURCC('u', 'u', 'i', 'd'): {
2272                                         unsigned long uuid[4] = {0, };
2273
2274                                         debug_msg(RELEASE, "MPEG4: [uuid] SIZE: [%lld]Byte", chunk_size);
2275
2276                                         mmfile_read(fp, (unsigned char *)uuid, sizeof(uuid));
2277
2278                                         if (mmfile_io_be_uint32(uuid[0]) == 0xffcc8263
2279                                                 && mmfile_io_be_uint32(uuid[1]) == 0xf8554a93
2280                                                 && mmfile_io_be_uint32(uuid[2]) == 0x8814587a
2281                                                 && mmfile_io_be_uint32(uuid[3]) == 0x02521fdd) {
2282                                                 char *str = NULL;
2283                                                 str = (char *)malloc(basic_header.size);
2284
2285                                                 if (str != NULL) {
2286                                                         memset(str, 0, basic_header.size);
2287                                                         mmfile_read(fp, (unsigned char *)str, basic_header.size);
2288 #if 0
2289 /* The block is superseded */
2290                                                         if (strstr(str, "<GSpherical:Spherical>true</GSpherical:Spherical>"))
2291                                                                 formatContext->is_360 = 1;
2292                                                         else
2293                                                                 formatContext->is_360 = 0;
2294 /* Image can be stitched even if it is not spherical */
2295                                                         if (formatContext->is_360 == 1) {
2296                                                                 if (strstr(str, "<GSpherical:Stitched>true</GSpherical:Stitched>"))
2297                                                                         formatContext->stitched = MMFILE_360_STITCHED;
2298                                                                 else
2299                                                                         formatContext->stitched = MMFILE_360_NON_STITCHED;
2300                                                         } else {
2301 /* Image can be stitched or non-stitched. Usage of some 3rd value is superfluous */
2302                                                                 formatContext->stitched = MMFILE_360_NONE;
2303                                                         }
2304 #endif
2305
2306                                                         debug_msg(RELEASE, "Extracting tags from UUID XML string %s", str);
2307
2308                                                         ParseSpatialVideoMetadataFromXMLString(str, formatContext);
2309                                                 }
2310                                         }
2311                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2312
2313                                         break;
2314                                 }
2315                         case FOURCC('m', 'd', 'i', 'a'): {
2316                                         debug_msg(RELEASE, "MPEG4: [mdia] SIZE: [%lld]Byte", chunk_size);
2317                                         break;
2318                                 }
2319                         case FOURCC('m', 'i', 'n', 'f'): {
2320                                         debug_msg(RELEASE, "MPEG4: [minf] SIZE: [%lld]Byte", chunk_size);
2321                                         break;
2322                                 }
2323                         case FOURCC('s', 't', 'b', 'l'): {
2324                                         debug_msg(RELEASE, "MPEG4: [stbl] SIZE: [%lld]Byte", chunk_size);
2325                                         break;
2326                                 }
2327                         case FOURCC('s', 't', 's', 'd'): {
2328                                         debug_msg(RELEASE, "MPEG4: [stsd] SIZE: [%lld]Byte", chunk_size);
2329                                         break;
2330                                 }
2331                         case FOURCC('m', 'p', '4', 'a'): {
2332                                         debug_msg(RELEASE, "MPEG4: [mp4a] SIZE: [%lld]Byte", chunk_size);
2333                                         GetSA3DInfoFromMP4ATagBox(formatContext, fp, &basic_header);
2334                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2335                                         break;
2336                                 }
2337                         case FOURCC('a', 'v', 'c', '1'): {
2338                                         debug_msg(RELEASE, "MPEG4: [avc1] SIZE: [%lld]Byte (offset: %lld)", chunk_size, basic_header.start_offset);
2339                                         GetVideoV2MetadataFromAvc1TagBox(formatContext, fp, &basic_header);
2340                                         break;
2341                                 }
2342                         default: {
2343                                         debug_msg(RELEASE, "4CC: Not Support [%c%c%c%c]. So skip it. Size [%lld Byte]",
2344                                                                 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
2345                                                                 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3], chunk_size);
2346                                         ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2347                                         break;
2348                                 }
2349                 }
2350
2351                 if (ret == MMFILE_UTIL_FAIL) {
2352                         debug_error(DEBUG, "mmfile operation is error");
2353                         ret = -1;
2354                         goto exit;
2355                 }
2356
2357                 long long new_pos = mmfile_tell(fp);
2358
2359                 if ((moov_end == 0) && (new_pos <= basic_header.start_offset)) {
2360                         debug_error(DEBUG, "Wrong position");
2361                         ret = MMFILE_UTIL_FAIL;
2362                         continue;
2363                 }
2364                 basic_header.start_offset = new_pos;
2365
2366         }
2367
2368 exit:
2369         mmfile_close(fp);
2370         return ret;
2371 }
2372
2373 static bool __get_genre_num(const char *buffer, int *si)
2374 {
2375         int len = strlen(buffer);
2376         char *tmp_genre = NULL;
2377
2378         /* Genre format: (###), ### */
2379         if (len > 6 || len == 0)
2380                 return false;
2381
2382         /* Check first c */
2383         if (len == 1) {
2384                 if (!g_ascii_isdigit(buffer[0]))
2385                         return false;
2386         } else {
2387                 if (!g_ascii_isdigit(buffer[1]))
2388                         return false;
2389         }
2390
2391         /* Remove bind () if exist */
2392         tmp_genre = g_strdup(buffer);
2393         if (g_str_has_prefix(tmp_genre, "(") && g_str_has_suffix(tmp_genre, ")"))
2394                 tmp_genre[0] = '0';
2395
2396         *si = atoi(tmp_genre);
2397         g_free(tmp_genre);
2398
2399         return true;
2400 }
2401
2402 static bool make_characterset_array(char ***charset_array)
2403 {
2404         char *locale = MMFileUtilGetLocale();
2405
2406         *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
2407
2408         if (*charset_array == NULL) {
2409                 debug_error(DEBUG, "calloc failed ");
2410                 if (locale != NULL)
2411                         free(locale);
2412                 return false;
2413         }
2414
2415         if (locale != NULL) {
2416                 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
2417         } else {
2418                 debug_error(DEBUG, "get locale failed");
2419                 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
2420         }
2421
2422         (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
2423         (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
2424         (*charset_array)[AV_ID3V2_UTF8] = strdup(MMFILE_CODESET_UTF8);
2425
2426         return true;
2427 }
2428
2429 static bool release_characterset_array(char **charset_array)
2430 {
2431         int i = 0;
2432
2433         for (i = 0; i < AV_ID3V2_MAX; i++) {
2434                 if (charset_array[i] != NULL) {
2435                         free(charset_array[i]);
2436                         charset_array[i] = NULL;
2437                 }
2438         }
2439
2440         if (charset_array != NULL) {
2441                 free(charset_array);
2442                 charset_array = NULL;
2443         }
2444
2445         return true;
2446 }
2447
2448 static void init_content_info(AvFileContentInfo *pInfo)
2449 {
2450         int i=0;
2451
2452         for(i = 0; i < AV_ID3TAG_MAX; i++)
2453                 pInfo->tagInfo[i].value = NULL;
2454
2455         pInfo->imageInfo.bURLInfo = false;
2456         pInfo->imageInfo.pImageBuf = NULL;
2457         pInfo->imageInfo.imageLen = 0;
2458 }
2459
2460 static void __id3tag_skip_newline(unsigned char *pTagVal, int *nTagLen, int *offset)
2461 {
2462         /* skip newline in text encoding of ID3 tag frame */
2463         while ((NEWLINE_OF_UTF16(pTagVal + *offset) || NEWLINE_OF_UTF16_R(pTagVal + *offset)) && *nTagLen > 4) {
2464                 *nTagLen -= 4;
2465                 *offset += 4;
2466         }
2467 }
2468
2469 static int __id3tag_get_text_encoding_v222(unsigned char *pTagVal, int offset)
2470 {
2471         if (pTagVal[offset - 1] == 0x00)
2472                 return AV_ID3V2_ISO_8859;
2473
2474         return AV_ID3V2_UTF16;
2475 }
2476
2477 static int __id3tag_get_text_encoding_v223(unsigned char *pTagVal, int *npTagLen, int nTextEnc, int *offset)
2478 {
2479         if ((IS_ENCODEDBY_UTF16(pTagVal + *offset) || IS_ENCODEDBY_UTF16_R(pTagVal + *offset)) && *npTagLen > 2) {
2480                 __id3tag_skip_newline(pTagVal, npTagLen, offset);
2481
2482                 if (IS_ENCODEDBY_UTF16(pTagVal + *offset) && (*npTagLen > 2)) {
2483                         *npTagLen -= 2;
2484                         *offset += 2;
2485                         return AV_ID3V2_UTF16;
2486                 } else if (IS_ENCODEDBY_UTF16_R(pTagVal + *offset) && (*npTagLen > 2)) {
2487                         *npTagLen -= 2;
2488                         *offset += 2;
2489                         return AV_ID3V2_UTF16_BE;
2490                 } else if (IS_ENCODEDBY_UTF16(pTagVal + *offset + 1) && (*npTagLen > 3)) {
2491                         *npTagLen -= 3;
2492                         *offset += 3;
2493                         return AV_ID3V2_UTF16;
2494                 } else if (IS_ENCODEDBY_UTF16_R(pTagVal + *offset + 1)  && (*npTagLen > 3)) {
2495                         *npTagLen -= 3;
2496                         *offset += 3;
2497                         return AV_ID3V2_UTF16_BE;
2498                 } else {
2499                         debug_msg(RELEASE, "id3tag never get here!!");
2500                         return nTextEnc;        /* default bypass */
2501                 }
2502         } else {
2503                 while ((pTagVal[*offset] < 0x20) && (*offset < *npTagLen)) { /* text string encoded by ISO-8859-1 */
2504                         (*npTagLen)--;
2505                         (*offset)++;
2506                 }
2507                 return AV_ID3V2_ISO_8859;
2508         }
2509 }
2510
2511 static int __id3tag_get_text_encoding_v224(unsigned char *pTagVal, int *npTagLen, int nTextEnc, int *offset)
2512 {
2513         if (nTextEnc == AV_ID3V2_UTF16 || nTextEnc == AV_ID3V2_UTF16_BE) {
2514                 __id3tag_skip_newline(pTagVal, npTagLen, offset);
2515
2516                 if ((IS_ENCODEDBY_UTF16(pTagVal + *offset) || IS_ENCODEDBY_UTF16_R(pTagVal + *offset)) && *npTagLen > 2) {
2517                         *npTagLen -= 2;
2518                         *offset += 2;
2519                         return AV_ID3V2_UTF16;
2520                 } else {
2521                         debug_msg(RELEASE, "id3tag never get here!!");
2522                         return nTextEnc;        /* default bypass */
2523                 }
2524         } else if (nTextEnc == AV_ID3V2_UTF8) {
2525                 while (pTagVal[*offset] < 0x20 && (*offset < *npTagLen)) { /* text string encoded by UTF-8 */
2526                         (*npTagLen)--;
2527                         (*offset)++;
2528                 }
2529                 return AV_ID3V2_UTF8;
2530         } else {
2531                 while (pTagVal[*offset] < 0x20 && (*offset < *npTagLen)) { /* text string encoded by ISO-8859-1 */
2532                         (*npTagLen)--;
2533                         (*offset)++;
2534                 }
2535                 return AV_ID3V2_ISO_8859;
2536         }
2537 }
2538
2539 static void __id3tag_parse_SYLT(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet, int textEncodingType, int offset)
2540 {
2541         int idx = 0;
2542         int copy_len = 0;
2543         int copy_start_pos = offset;
2544         AvSynclyricsInfo *synclyrics_info = NULL;
2545         GList *synclyrics_info_list = NULL;
2546
2547         if (nTagLen < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2548                 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)", nTagLen);
2549                 return;
2550         }
2551
2552         if ((textEncodingType == AV_ID3V2_UTF16) || (textEncodingType == AV_ID3V2_UTF16_BE)) {
2553                 debug_warning(DEBUG, "[%d] not implemented", textEncodingType);
2554                 return;
2555         }
2556
2557         for (idx = 0; idx < nTagLen; idx++) {
2558                 if (pTagVal[offset + idx] == 0x00) {
2559                         synclyrics_info = g_new0(AvSynclyricsInfo, 1);
2560                         if (textEncodingType == AV_ID3V2_UTF8)
2561                                 synclyrics_info->lyric_info = g_memdup2(pTagVal + copy_start_pos, copy_len + 1);
2562                         else
2563                                 synclyrics_info->lyric_info = mmfile_convert_to_utf8((const char *)&pTagVal[copy_start_pos], copy_len, pCharSet);
2564
2565                         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];
2566                         idx += 4;
2567                         copy_start_pos = offset + idx + 1;
2568                         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);
2569                         copy_len = 0;
2570                         synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
2571                 }
2572                 copy_len++;
2573         }
2574
2575         pInfo->pSyncLyrics = synclyrics_info_list;
2576 }
2577
2578 static bool __id3tag_parse_PIC_format(AvFileContentInfo *pInfo, unsigned char *pTagVal, int *offset)
2579 {
2580         unsigned int idx = 0;
2581
2582         /* get the mime type of Attached PICture, it is text string */
2583
2584         if (pTagVal[*offset] == '\0') {
2585                 debug_msg(RELEASE, "The picture format of PIC is not included");
2586                 return false;
2587         }
2588
2589         /* init ext variable */
2590         memset(pInfo->imageInfo.imageExt, 0, sizeof(pInfo->imageInfo.imageExt));
2591         /* get ext */
2592         while ((idx < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && (pTagVal[idx] != '\0')) {
2593                 pInfo->imageInfo.imageExt[idx] = pTagVal[idx];
2594                 idx++;
2595         }
2596
2597         *offset += idx;
2598
2599         return true;
2600 }
2601
2602 static bool __id3tag_parse_APIC_mimetype(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, int *offset)
2603 {
2604         unsigned int idx = 0;
2605         const char *MIME_PRFIX = "image/";
2606
2607         /* get the mime type of Attached PICture, it is text string */
2608
2609         if (pTagVal[*offset] == '\0') {
2610                 pInfo->imageInfo.imgMimetypeLen = 0;
2611                 debug_msg(RELEASE, "The MIME type of APIC is not included");
2612                 return false;
2613         }
2614
2615         /* init mimetype variable */
2616         memset(pInfo->imageInfo.imageMIMEType, 0, sizeof(pInfo->imageInfo.imageMIMEType));
2617         /* get mimetype */
2618         while ((idx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && (pTagVal[idx] != '\0')) {
2619                 pInfo->imageInfo.imageMIMEType[idx] = pTagVal[idx];
2620                 idx++;
2621         }
2622         pInfo->imageInfo.imgMimetypeLen = idx;
2623
2624         *offset += idx;
2625
2626         if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2627                 pInfo->imageInfo.imgMimetypeLen = 0;
2628                 debug_error(DEBUG, "MIME type(%s) is not image", pInfo->imageInfo.imageMIMEType);
2629                 return false;
2630         }
2631
2632         if ((pTagVal[*offset] != '\0') || (nTagLen <= *offset)) {
2633                 debug_msg(RELEASE, "pTagVal[offset](%d) mimetype is not NULL terminated! realCpyFrameNum - offset(%d)",
2634                                         pTagVal[*offset], nTagLen - *offset);
2635                 return true;
2636         }
2637
2638         (*offset)++;/* end of MIME('\0', 1byte) */
2639         debug_msg(RELEASE, "after scaning Mime type offset(%d) value!", *offset);
2640
2641         return true;
2642 }
2643
2644 static void __id3tag_parse_APIC_pictype(AvFileContentInfo *pInfo, unsigned char *pTagVal, int *offset)
2645 {
2646         /* get the picture type of Attached PICture, it is 1byte(0xff) */
2647
2648         if (pTagVal[*offset] < MP3_ID3V2_PICTURE_TYPE_MAX)
2649                 pInfo->imageInfo.pictureType = pTagVal[*offset];
2650         else
2651                 debug_msg(RELEASE, "APIC image has invalid picture type(0x%x)", pTagVal[*offset]);
2652
2653         (*offset)++;/* PictureType(1byte) */
2654         debug_msg(RELEASE, "after scaning PictureType(%d) offset(%d) value!", pInfo->imageInfo.pictureType, *offset);
2655 }
2656
2657 static void __id3tag_parse_APIC_desc(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet, int *offset)
2658 {
2659         /* get the description of Attached PICture, it is text string */
2660
2661         int idx = 0;
2662         unsigned int tag_len = 0;
2663         char *tmp_desc = NULL;
2664
2665         if (pTagVal[*offset] == 0x0) {
2666                 debug_msg(RELEASE, "The description of APIC is not included!!!");
2667                 return;
2668         }
2669
2670         while (1) {
2671                 if (pTagVal[*offset + idx] == '\0') {
2672                         if (nTagLen < (*offset + idx)) {
2673                                 debug_error(DEBUG, "End of APIC Tag %d %d %d", nTagLen, *offset, idx);
2674                                 break;
2675                         }
2676                         /* check end of image description */
2677                         if ((pTagVal[*offset + idx + 1] == gTagJPEGHeader[0]) ||
2678                                 (pTagVal[*offset + idx + 1] == gTagPNGHeader[0])) {
2679                                 debug_msg(RELEASE, "length of description (%d)", idx);
2680                                 break;
2681                         }
2682                 }
2683                 idx++;
2684         }
2685
2686         tag_len = idx + 1;      /* length of description + '\0' */
2687
2688         tmp_desc = g_memdup2(pTagVal + *offset, tag_len);
2689
2690         /* convert description */
2691         pInfo->imageInfo.imageDescription = mmfile_convert_to_utf8(tmp_desc, tag_len, pCharSet);
2692         mmfile_free(tmp_desc);
2693         debug_msg(RELEASE, "new_desc %s", pInfo->imageInfo.imageDescription);
2694
2695         *offset += idx;
2696         if ((pTagVal[*offset] != '\0') || (nTagLen <= *offset)) {
2697                 debug_msg(RELEASE, "pTagVal[offset](%d) description is not NULL terminated! realCpyFrameNum - offset(%d)",
2698                                         pTagVal[*offset], nTagLen - *offset);
2699                 return;
2700         }
2701         (*offset)++; /* end of desceription(1byte) */
2702 }
2703
2704 static void __id3tag_parse_APIC_picture(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, int *offset)
2705 {
2706         /* get the picture of Attached PICture, it is binary data */
2707
2708         /* some content has useless '\0' in front of picture data */
2709         while (pTagVal[*offset] == '\0') {
2710                 (*offset)++;
2711         }
2712
2713         debug_msg(RELEASE, "after scaning APIC description offset(%d) value!", *offset);
2714
2715         if (nTagLen <= *offset) {
2716                 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - offset(%d)", nTagLen, *offset);
2717                 return;
2718         }
2719
2720         pInfo->imageInfo.imageLen = nTagLen - *offset;
2721         pInfo->imageInfo.pImageBuf = g_memdup2(pTagVal + *offset, pInfo->imageInfo.imageLen);
2722
2723         /* if mimetype is "-->", image date has an URL */
2724         if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2725                 pInfo->imageInfo.bURLInfo = true;
2726 }
2727
2728 static bool _mm_file_id3tag_parse_PIC(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet)
2729 {
2730         /* current position to read pTagVal */
2731         int offset = 0;
2732
2733         debug_fenter(RELEASE);
2734
2735         if (!__id3tag_parse_PIC_format(pInfo, pTagVal, &offset)) {
2736                 debug_msg(RELEASE, "PIC is not valid");
2737                 return false;
2738         }
2739
2740         __id3tag_parse_APIC_pictype(pInfo, pTagVal, &offset);
2741         __id3tag_parse_APIC_desc(pInfo, pTagVal, nTagLen, pCharSet, &offset);
2742         __id3tag_parse_APIC_picture(pInfo, pTagVal, nTagLen, &offset);
2743
2744         debug_fleave(RELEASE);
2745
2746         return true;
2747 }
2748
2749 static bool _mm_file_id3tag_parse_APIC(AvFileContentInfo *pInfo, unsigned char *pTagVal, int nTagLen, const char *pCharSet)
2750 {
2751         int offset = 0;
2752
2753         debug_fenter(RELEASE);
2754
2755         if (!__id3tag_parse_APIC_mimetype(pInfo, pTagVal, nTagLen, &offset)) {
2756                 debug_msg(RELEASE, "APIC is not valid");
2757                 return false;
2758         }
2759
2760         __id3tag_parse_APIC_pictype(pInfo, pTagVal, &offset);
2761         __id3tag_parse_APIC_desc(pInfo, pTagVal, nTagLen, pCharSet, &offset);
2762         __id3tag_parse_APIC_picture(pInfo, pTagVal, nTagLen, &offset);
2763
2764         debug_fleave(RELEASE);
2765
2766         return true;
2767 }
2768
2769 static char * __id3tag_get_v110(const char *buf, ssize_t len, const char *locale)
2770 {
2771         char *tmp_str = NULL;
2772
2773         mm_file_retv_if_fails(buf, NULL);
2774         mm_file_retv_if_fails(locale, NULL);
2775
2776         tmp_str = mmfile_convert_to_utf8(buf, len, locale);
2777
2778         /* ID3v1 tag need check length or space. */
2779         if (tmp_str && (strlen(tmp_str) == 0 || g_ascii_isspace(tmp_str[0])))
2780                 mmfile_free(tmp_str);
2781
2782         return tmp_str;
2783 }
2784
2785 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo, unsigned char *buffer)
2786 {
2787         const char *locale = MMFileUtilGetLocale();
2788
2789         debug_msg(RELEASE, "ID3tag v110--------------------------------------------------------------");
2790
2791         if (!pInfo->tagInfo[AV_ID3TAG_TITLE].value) {
2792                 pInfo->tagInfo[AV_ID3TAG_TITLE].value = __id3tag_get_v110((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, locale);
2793
2794                 debug_msg(RELEASE, "pInfo->pTitle returned =(%s)", pInfo->tagInfo[AV_ID3TAG_TITLE].value);
2795         }
2796
2797         if (!pInfo->tagInfo[AV_ID3TAG_ARTIST].value) {
2798                 pInfo->tagInfo[AV_ID3TAG_ARTIST].value = __id3tag_get_v110((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, locale);
2799
2800                 debug_msg(RELEASE, "pInfo->pArtist returned =(%s)", pInfo->tagInfo[AV_ID3TAG_ARTIST].value);
2801         }
2802
2803         if (!pInfo->tagInfo[AV_ID3TAG_ALBUM].value) {
2804                 pInfo->tagInfo[AV_ID3TAG_ALBUM].value = __id3tag_get_v110((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, locale);
2805
2806                 debug_msg(RELEASE, "pInfo->pAlbum returned =(%s)", pInfo->tagInfo[AV_ID3TAG_ALBUM].value);
2807         }
2808
2809         if (!pInfo->tagInfo[AV_ID3TAG_YEAR].value) {
2810                 pInfo->tagInfo[AV_ID3TAG_YEAR].value = __id3tag_get_v110((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, locale);
2811
2812                 debug_msg(RELEASE, "pInfo->pYear returned =(%s)", pInfo->tagInfo[AV_ID3TAG_YEAR].value);
2813         }
2814
2815         if (!pInfo->tagInfo[AV_ID3TAG_COMMENT].value) {
2816                 pInfo->tagInfo[AV_ID3TAG_COMMENT].value = __id3tag_get_v110((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, locale);
2817
2818                 debug_msg(RELEASE, "pInfo->pComment returned =(%s)", pInfo->tagInfo[AV_ID3TAG_COMMENT].value);
2819         }
2820
2821         if (!pInfo->tagInfo[AV_ID3TAG_TRACKNUM].value) {
2822                 pInfo->tagInfo[AV_ID3TAG_TRACKNUM].value = g_malloc0(ID3TAG_V110_TRACK_NUM_DIGIT);
2823                 pInfo->tagInfo[AV_ID3TAG_TRACKNUM].value[ID3TAG_V110_TRACK_NUM_DIGIT - 1] = 0;
2824                 snprintf(pInfo->tagInfo[AV_ID3TAG_TRACKNUM].value, ID3TAG_V110_TRACK_NUM_DIGIT, "%04d", (int)buffer[126]);
2825
2826                 debug_msg(RELEASE, "pInfo->pTrackNum returned =(%s)", pInfo->tagInfo[AV_ID3TAG_TRACKNUM].value);
2827         }
2828
2829         /*ID3V2 genre is stored in pInfo->tagInfo[AV_ID3TAG_GENRE].value */
2830         /*pInfo->genre is used when ID3V2 genre is invalid, or empty. */
2831         pInfo->genre = buffer[127];
2832         debug_msg(RELEASE, "pInfo->genre returned genre number (%d)", pInfo->genre);
2833
2834         return true;
2835 }
2836
2837 static AvID3TagList __get_tag_info_v222(const unsigned char *tag)
2838 {
2839         unsigned int n = 0;
2840         int i = 0;
2841
2842         while (i < 2) {
2843                 n  += tag[i++] - 'A' + 1;
2844                 n  <<= 5;
2845         }
2846         n  += tag[2];   //num, char mixted
2847
2848         for (i = 0; i < ID3TAG_NUM_V22; i++) {
2849                 if (n == tag_info_v22[i].int_name) {
2850                         return tag_info_v22[i].tag;
2851                 }
2852         }
2853
2854         debug_msg(RELEASE, "(%s) This Frame ID currently not Supports!!", tag);
2855
2856         return AV_ID3TAG_MAX;
2857 }
2858
2859 static AvID3TagList __get_tag_info_v223(const unsigned char *tag)
2860 {
2861         unsigned int n = 0;
2862         int i = 0;
2863
2864         while (i < 3) {
2865                 n  += tag[i++] - 'A' + 1;
2866                 n  <<= 5;
2867         }
2868         n  += tag[3];   //num, char mixted
2869
2870         for (i = 0; i < ID3TAG_NUM_V23; i++) {
2871                 if (n == tag_info_v23[i].int_name) {
2872                         return tag_info_v23[i].tag;
2873                 }
2874         }
2875
2876         debug_msg(RELEASE, "(%s) This Frame ID currently not Supports!!", tag);
2877
2878         return AV_ID3TAG_MAX;
2879 }
2880
2881
2882 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer, bool extract_artwork)
2883 {
2884         int curPos = MP3_TAGv2_HEADER_LEN;
2885         int frameLen = 0;
2886         int encOffset = 0;
2887         int encType = 0;
2888         char **charset_array = NULL;
2889         AvID3TagList tag_id = AV_ID3TAG_MAX;
2890
2891         if (pInfo->tagV2Info.tagLen <= 0)
2892                 return false;
2893
2894         make_characterset_array(&charset_array);
2895         init_content_info(pInfo);
2896
2897         debug_msg(RELEASE, "ID3tag v222--------------------------------------------------------------");
2898
2899         while (curPos + MP3_TAGv2_22_TXT_HEADER_LEN < pInfo->tagV2Info.tagLen) {
2900                 if (!g_ascii_isalnum(buffer[curPos]) || !g_ascii_isalnum(buffer[curPos + 1]) || !g_ascii_isalnum(buffer[curPos + 2]))
2901                         break;
2902
2903                 tag_id = __get_tag_info_v222(&buffer[curPos]);
2904                 frameLen = buffer[curPos + 3] << 16 | buffer[curPos + 4] << 8 | buffer[curPos + 5];
2905                 curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
2906                 if (curPos + frameLen > pInfo->tagV2Info.tagLen)
2907                         break;
2908
2909                 if (frameLen <= 0)
2910                         continue;
2911
2912                 if (tag_id == AV_ID3TAG_MAX || pInfo->tagInfo[tag_id].value)
2913                         goto NEXT;
2914
2915                 if (buffer[curPos] == 0x00) {
2916                         encOffset = 1;
2917                         encType = AV_ID3V2_ISO_8859;
2918                 } else if (buffer[curPos] == 0x01) {
2919                         encOffset = 1;
2920                         encType = AV_ID3V2_UTF16;
2921                 }
2922
2923                 /*in order to deliver valid string to MP */
2924                 while ((buffer[curPos + encOffset] < 0x20) && (encOffset < frameLen))
2925                         encOffset++;
2926
2927                 if (frameLen == encOffset) {
2928                         debug_warning(DEBUG, "warning: invalid frame length %d %d", frameLen, encOffset);
2929                         goto NEXT;
2930                 }
2931
2932                 curPos += encOffset;
2933                 frameLen -= encOffset;
2934
2935                 switch (tag_id) {
2936                 case AV_ID3TAG_COMMENT:
2937                         /*
2938                         https://id3.org/id3v2-00
2939                         Comment                   "COM"
2940                         Frame size                $xx xx xx
2941                         Text encoding             $xx
2942                         Language                  $xx xx xx
2943                         Short content description <textstring> $00 (00)
2944                         The actual text           <textstring>
2945                         */
2946                         if (frameLen <= 4) {
2947                                 debug_msg(RELEASE, "Too small to parse frameLen(%d)", frameLen);
2948                                 break;
2949                         }
2950
2951                         if (buffer[curPos + 4] > 0x20 && (buffer[curPos + 3] == 0x00 || buffer[curPos + 3] == 0x01)) {
2952                                 encType = __id3tag_get_text_encoding_v222(&buffer[curPos], 4);
2953                                 /*skip language data! */
2954                                 curPos += 4;
2955                                 frameLen -= 4;
2956                                 pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
2957                         } else {
2958                                 debug_msg(RELEASE, "Failed to get tag: frameLen(%d)", frameLen);
2959                         }
2960
2961                         break;
2962
2963                 case AV_ID3TAG_PICTURE:
2964                         if (extract_artwork)
2965                                 _mm_file_id3tag_parse_PIC(pInfo, &buffer[curPos], frameLen, charset_array[encType]);
2966                         break;
2967
2968                 default:
2969                         pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
2970                         break;
2971                 }
2972
2973                 if (pInfo->tagInfo[tag_id].value)
2974                         debug_msg(RELEASE, "[%d] returned = (%s)", tag_id, pInfo->tagInfo[tag_id].value);
2975 NEXT:
2976                 curPos += frameLen;
2977                 encOffset = 0;
2978                 encType = 0;
2979         }
2980
2981         release_characterset_array(charset_array);
2982
2983         return true;
2984 }
2985
2986 static void __get_v223_encoding_info(const unsigned char *buffer,
2987                                                                         int length,
2988                                                                         int *offset,
2989                                                                         unsigned int *type)
2990 {
2991         int _offset = 0;
2992
2993         if (!buffer || !offset || !type)
2994                 return;
2995
2996         if (IS_ENCODEDBY_UTF16(buffer)) {
2997                 *offset = 2;
2998                 *type = AV_ID3V2_UTF16;
2999                 return;
3000         }
3001         if (IS_ENCODEDBY_UTF16_R(buffer)) {
3002                 *offset = 2;
3003                 *type = AV_ID3V2_UTF16_BE;
3004                 return;
3005         }
3006         if (IS_ENCODEDBY_UTF16(buffer + 1)) {
3007                 *offset = 3;
3008                 *type = AV_ID3V2_UTF16;
3009                 return;
3010         }
3011         if (IS_ENCODEDBY_UTF16_R(buffer + 1)) {
3012                 *offset = 3;
3013                 *type = AV_ID3V2_UTF16_BE;
3014                 return;
3015         }
3016
3017         if (buffer[0] == 0x00) {
3018                 *offset = 1;
3019         } else {
3020                 while ((buffer[_offset] < 0x20) && (_offset < length))
3021                         _offset++;
3022                 *offset = _offset;
3023         }
3024         *type = AV_ID3V2_ISO_8859;
3025 }
3026
3027 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer, bool extract_artwork)
3028 {
3029         int extendedHeaderLen = 0;
3030         int frameLen = 0;
3031         int curPos = MP3_TAGv2_HEADER_LEN;
3032         int encOffset = 0;
3033         unsigned int encType = 0;
3034         char **charset_array = NULL;
3035         AvID3TagList tag_id = AV_ID3TAG_MAX;
3036         char *lang_info = NULL;
3037
3038         if (pInfo->tagV2Info.tagLen <= 0)
3039                 return false;
3040
3041         make_characterset_array(&charset_array);
3042         init_content_info(pInfo);
3043
3044         debug_msg(RELEASE, "ID3tag v223--------------------------------------------------------------");
3045         if (buffer[5] & 0x40) {
3046                 /* if extended header exists, skip it*/
3047                 extendedHeaderLen = buffer[10] << 21 | buffer[11] << 14 | buffer[12] << 7 | buffer[13];
3048                 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d", extendedHeaderLen);
3049                 if (extendedHeaderLen > pInfo->tagV2Info.tagLen - MP3_TAGv2_HEADER_LEN) {
3050                         debug_error(DEBUG, "extended header too long.");
3051                 } else {
3052                         curPos += extendedHeaderLen;
3053                         curPos += 4;
3054                 }
3055         }
3056
3057         while (curPos + MP3_TAGv2_23_TXT_HEADER_LEN < pInfo->tagV2Info.tagLen) {
3058                 if (!g_ascii_isalnum(buffer[curPos]) || !g_ascii_isalnum(buffer[curPos + 1]) ||
3059                         !g_ascii_isalnum(buffer[curPos + 2]) || !g_ascii_isalnum(buffer[curPos + 3]))
3060                         break;
3061
3062                 tag_id = __get_tag_info_v223(&buffer[curPos]);
3063                 frameLen = buffer[curPos + 4] << 24 | buffer[curPos + 5] << 16 | buffer[curPos + 6] << 8 | buffer[curPos + 7];
3064                 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
3065                 if (curPos + frameLen > pInfo->tagV2Info.tagLen)
3066                         break;
3067
3068                 if (frameLen <= 0)
3069                         continue;
3070
3071                 if (tag_id == AV_ID3TAG_MAX || pInfo->tagInfo[tag_id].value)
3072                         goto NEXT;
3073
3074                 __get_v223_encoding_info(buffer + curPos, frameLen, &encOffset, &encType);
3075                 if (frameLen <= encOffset) {
3076                         debug_warning(DEBUG, "warning: invalid frame length %d %d", frameLen, encOffset);
3077                         goto NEXT;
3078                 }
3079
3080                 curPos += encOffset;
3081                 frameLen -= encOffset;
3082                 encOffset = 0;
3083
3084                 if (encType != AV_ID3V2_UTF16 && encType != AV_ID3V2_UTF16_BE) {
3085                         if (tag_id != AV_ID3TAG_COMMENT && tag_id != AV_ID3TAG_UNSYNCLYRICS && tag_id != AV_ID3TAG_SYNCLYRICS) {
3086                                 debug_msg(RELEASE, "get the new text encoding type");
3087                                 encType = buffer[curPos - 1];
3088                         }
3089                 }
3090
3091                 if (encType > AV_ID3V2_MAX) {
3092                         debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%u], TAG ID[%d]", encType, tag_id);
3093                         goto NEXT;
3094                 }
3095
3096                 switch (tag_id) {
3097                 case AV_ID3TAG_COMMENT:
3098                         if (frameLen <= 3) {
3099                                 debug_msg(RELEASE, "Description info too small to parse frameLen(%d)", frameLen);
3100                                 break;
3101                         }
3102                         frameLen -= 3;
3103                         encOffset = 3;
3104
3105                         if (buffer[curPos] != 0x00 && buffer[curPos] != 0xFF && buffer[curPos] != 0xFE) {
3106                                 debug_msg(RELEASE, "failed to get Comment: frameLen(%d)", frameLen);
3107                         }
3108
3109                         encType = __id3tag_get_text_encoding_v223(&buffer[curPos], &frameLen, encType, &encOffset);
3110                         debug_msg(RELEASE, "encOffset(%d) encType(%u), frameLen(%d)", encOffset, encType, frameLen);
3111                         curPos += encOffset;
3112                         pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
3113                         break;
3114
3115                 case AV_ID3TAG_SYNCLYRICS:
3116                         if (frameLen <= 5) {
3117                                 debug_msg(RELEASE, "Synchronised lyrics too small to parse frameLen(%d)", frameLen);
3118                                 break;
3119                         }
3120                         frameLen -= 5;
3121                         encOffset = 5;
3122
3123                         if (buffer[curPos] != 0x00 && buffer[curPos] != 0xFF && buffer[curPos] != 0xFE) {
3124                                 debug_msg(RELEASE, "failed to get Synchronised lyrics Info curPos(%d), frameLen(%d)", curPos, frameLen);
3125                         }
3126                         encType = __id3tag_get_text_encoding_v223(&buffer[curPos], &frameLen, encType, &encOffset);
3127                         debug_msg(RELEASE, "encOffset(%d) encType(%u), frameLen(%d)", encOffset, encType, frameLen);
3128                         curPos += encOffset;
3129                         __id3tag_parse_SYLT(pInfo, buffer, frameLen, charset_array[encType], encType, curPos);
3130                         break;
3131
3132                 case AV_ID3TAG_UNSYNCLYRICS:
3133                         lang_info = strndup((const char *)&buffer[curPos], 3);
3134
3135                         if (frameLen <= 3) {
3136                                 debug_msg(RELEASE, "Unsynchronised lyrics too small to parse frameLen(%d)", frameLen);
3137                                 mmfile_free(lang_info);
3138                                 break;
3139                         }
3140                         frameLen -= 3;
3141                         encOffset = 3;
3142
3143                         if (buffer[curPos] != 0x00 && buffer[curPos] != 0xFF && buffer[curPos] != 0xFE) {
3144                                 debug_msg(RELEASE, "failed to get Unsynchronised lyrics Info curPos(%d), frameLen(%d)", curPos, frameLen);
3145                         }
3146                         encType = __id3tag_get_text_encoding_v223(&buffer[curPos], &frameLen, encType, &encOffset);
3147
3148                         char *char_set = NULL;
3149
3150                         debug_msg(RELEASE, "encOffset(%d) encType(%u), frameLen(%d)", encOffset, encType, frameLen);
3151
3152                         if (encType == AV_ID3V2_ISO_8859) {
3153                                 if (lang_info != NULL && !g_ascii_strcasecmp(lang_info, "KOR")) {
3154                                         char_set = strdup("EUC-KR");
3155                                 } else {
3156                                         char_set = mmfile_get_charset((const char *)&buffer[curPos]);
3157                                 }
3158                                 mmfile_free(lang_info);
3159                         }
3160
3161                         curPos += encOffset;
3162
3163                         if (!char_set) {
3164                                 pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
3165                         } else {
3166                                 pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, char_set);
3167                                 mmfile_free(char_set);
3168                         }
3169                         mmfile_free(lang_info);
3170                         break;
3171
3172                 case AV_ID3TAG_PICTURE:
3173                         if (extract_artwork)
3174                                 _mm_file_id3tag_parse_APIC(pInfo, &buffer[curPos], frameLen, charset_array[encType]);
3175                         break;
3176
3177                 default:
3178                         pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
3179                         break;
3180                 }
3181
3182                 if (pInfo->tagInfo[tag_id].value)
3183                         debug_msg(RELEASE, "[%d] returned = (%s)", tag_id, pInfo->tagInfo[tag_id].value);
3184 NEXT:
3185                 curPos += frameLen;
3186                 encOffset = 0;
3187                 encType = 0;
3188         }
3189
3190         release_characterset_array(charset_array);
3191
3192         return true;
3193 }
3194
3195 static void __get_v224_encoding_info(const unsigned char *buffer,
3196                                                                         int length,
3197                                                                         int *offset,
3198                                                                         unsigned int *type)
3199 {
3200         int _offset = 0;
3201
3202         if (!buffer || !offset || !type)
3203                 return;
3204
3205         /*in case of UTF 16 encoding */
3206         /*buffer+(position-length) data should '0x01' but in order to expansion, we don't accurately check the value. */
3207         if (IS_ENCODEDBY_UTF16(buffer)) {
3208                 *offset = 2;
3209                 *type = AV_ID3V2_UTF16;
3210                 return;
3211         }
3212
3213         if (IS_ENCODEDBY_UTF16_R(buffer)) {
3214                 *offset = 2;
3215                 *type = AV_ID3V2_UTF16_BE;
3216                 return;
3217         }
3218
3219         if (IS_ENCODEDBY_UTF16(buffer + 1)) {
3220                 *offset = 3;
3221                 *type = AV_ID3V2_UTF16;
3222                 return;
3223         }
3224         if (IS_ENCODEDBY_UTF16_R(buffer + 1)) {
3225                 *offset = 3;
3226                 *type = AV_ID3V2_UTF16_BE;
3227                 return;
3228         }
3229
3230         /*in case of UTF-16 BE encoding */
3231         if (buffer[0] == 0x02) {
3232                 _offset = 1;
3233                 while ((buffer[_offset] == '\0') && (_offset < length))
3234                         _offset++;/*null skip! */
3235                 *offset = _offset;
3236                 *type = AV_ID3V2_UTF16_BE;
3237                 return;
3238         }
3239
3240         /*in case of UTF8 encoding */
3241         if (buffer[0] == 0x03) {
3242                 _offset = 1;
3243                 while ((buffer[_offset] == '\0') && (_offset < length))
3244                         _offset++;/*null skip! */
3245                 *offset = _offset;
3246                 *type = AV_ID3V2_UTF8;
3247                 return;
3248         }
3249         /*in case of ISO-8859-1 encoding */
3250         /*buffer+(position-length) data should 0x00 but in order to expansion, we don't accurately check the value. */
3251         _offset = 1;
3252         while ((buffer[_offset] < 0x20) && (_offset < length))
3253                 _offset++;/*less than 0x20 value skip! */
3254         *offset = _offset;
3255         *type = AV_ID3V2_ISO_8859;
3256 }
3257
3258 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer, bool extract_artwork)
3259 {
3260         int extendedHeaderLen = 0;
3261         int frameLen = 0;
3262         int curPos = MP3_TAGv2_HEADER_LEN;
3263         int encOffset = 0;
3264         unsigned int encType = 0;
3265         char **charset_array = NULL;
3266         AvID3TagList tag_id = AV_ID3TAG_MAX;
3267
3268         if (pInfo->tagV2Info.tagLen <= 0)
3269                 return false;
3270
3271         make_characterset_array(&charset_array);
3272         init_content_info(pInfo);
3273
3274         debug_msg(RELEASE, "ID3tag v224--------------------------------------------------------------");
3275         if (buffer[5] & 0x40) {
3276                 /* if extended header exists, skip it*/
3277                 extendedHeaderLen = buffer[10] << 21 | buffer[11] << 14 | buffer[12] << 7 | buffer[13];
3278                 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d", extendedHeaderLen);
3279                 if (extendedHeaderLen > pInfo->tagV2Info.tagLen - MP3_TAGv2_HEADER_LEN) {
3280                         debug_error(DEBUG, "extended header too long.");
3281                 } else {
3282                         curPos += extendedHeaderLen;
3283                 }
3284         }
3285
3286         while (curPos + MP3_TAGv2_23_TXT_HEADER_LEN < pInfo->tagV2Info.tagLen) {
3287                 if (!g_ascii_isalnum(buffer[curPos]) || !g_ascii_isalnum(buffer[curPos + 1]) ||
3288                         !g_ascii_isalnum(buffer[curPos + 2]) || !g_ascii_isalnum(buffer[curPos + 3]))
3289                         break;
3290
3291                 tag_id = __get_tag_info_v223(&buffer[curPos]);
3292                 frameLen = buffer[curPos + 4] << 21 | buffer[curPos + 5] << 14 | buffer[curPos + 6] << 7 | buffer[curPos + 7];
3293                 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
3294                 if (curPos + frameLen > pInfo->tagV2Info.tagLen)
3295                         break;
3296
3297                 if (frameLen <= 0)
3298                         continue;
3299
3300                 if (tag_id == AV_ID3TAG_MAX || pInfo->tagInfo[tag_id].value)
3301                         goto NEXT;
3302
3303                 __get_v224_encoding_info(buffer + curPos, frameLen, &encOffset, &encType);
3304                 if (frameLen <= encOffset) {
3305                         debug_warning(DEBUG, "warning: invalid frame length %d %d", frameLen, encOffset);
3306                         goto NEXT;
3307                 }
3308
3309                 curPos += encOffset;
3310                 frameLen -= encOffset;
3311                 encOffset = 0;
3312
3313                 if (encType != AV_ID3V2_UTF16 && encType != AV_ID3V2_UTF16_BE) {
3314                         if (tag_id != AV_ID3TAG_COMMENT && tag_id != AV_ID3TAG_UNSYNCLYRICS && tag_id != AV_ID3TAG_SYNCLYRICS) {
3315                                 debug_msg(RELEASE, "get the new text encoding type");
3316                                 encType = buffer[curPos - 1];
3317                         }
3318                 }
3319
3320                 if (encType > AV_ID3V2_MAX) {
3321                         debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%u], TAG ID[%d]", encType, tag_id);
3322                         goto NEXT;
3323                 }
3324
3325                 switch (tag_id) {
3326                 case AV_ID3TAG_COMMENT:
3327                         /* fall through */
3328                 case AV_ID3TAG_UNSYNCLYRICS:
3329                         if (frameLen <= 3) {
3330                                 debug_msg(RELEASE, "Description info too small to parse frameLen(%d)", frameLen);
3331                                 break;
3332                         }
3333                         frameLen -= 3;
3334                         encOffset = 3;
3335
3336                         encType = __id3tag_get_text_encoding_v224(&buffer[curPos], &frameLen, encType, &encOffset);
3337                         debug_msg(RELEASE, "encOffset(%d) encType(%u), frameLen(%d)", encOffset, encType, frameLen);
3338                         curPos += encOffset;
3339                         pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
3340                         break;
3341
3342                 case AV_ID3TAG_SYNCLYRICS:
3343                         if (frameLen <= 5) {
3344                                 debug_msg(RELEASE, "Synchronised lyrics too small to parse frameLen(%d)", frameLen);
3345                                 break;
3346                         }
3347                         frameLen -= 5;
3348                         encOffset = 5;
3349
3350                         encType = __id3tag_get_text_encoding_v224(&buffer[curPos], &frameLen, encType, &encOffset);
3351                         debug_msg(RELEASE, "encOffset(%d) encType(%u), frameLen(%d)", encOffset, encType, frameLen);
3352                         curPos += encOffset;
3353                         __id3tag_parse_SYLT(pInfo, buffer, frameLen, charset_array[encType], encType, curPos);
3354                         break;
3355
3356                 case AV_ID3TAG_PICTURE:
3357                         if (extract_artwork)
3358                                 _mm_file_id3tag_parse_APIC(pInfo, &buffer[curPos], frameLen, charset_array[encType]);
3359                         break;
3360
3361                 default:
3362                         pInfo->tagInfo[tag_id].value = mmfile_convert_to_utf8((const char *)&buffer[curPos], frameLen, charset_array[encType]);
3363                         break;
3364                 }
3365
3366                 if (pInfo->tagInfo[tag_id].value)
3367                         debug_msg(RELEASE, "[%d] returned = (%s)", tag_id, pInfo->tagInfo[tag_id].value);
3368 NEXT:
3369                 curPos += frameLen;
3370                 encOffset = 0;
3371                 encType = 0;
3372         }
3373
3374         release_characterset_array(charset_array);
3375
3376         return true;
3377 }
3378
3379
3380 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3381 {
3382         int genre_id = 0;
3383
3384         /* for Genre Info */
3385         if (pInfo->tagInfo[AV_ID3TAG_GENRE].value) {
3386                 /* Check integer */
3387                 if (!__get_genre_num(pInfo->tagInfo[AV_ID3TAG_GENRE].value, &genre_id)) {
3388                         debug_log(RELEASE, "genre information is not integer [%s]", pInfo->tagInfo[AV_ID3TAG_GENRE].value);
3389                         return;
3390                 }
3391
3392                 /* If integer, check genre code. */
3393                 /* If out of range, set UNKNOWN */
3394                 if (genre_id < 0 || genre_id >= GENRE_COUNT)
3395                         genre_id = GENRE_COUNT - 1;
3396
3397                 debug_msg(RELEASE, "genre information is integer [%d]", genre_id);
3398
3399                 g_free(pInfo->tagInfo[AV_ID3TAG_GENRE].value);
3400                 pInfo->tagInfo[AV_ID3TAG_GENRE].value = g_strdup(MpegAudio_Genre[genre_id]);
3401         } else {
3402                 /* No genre in ID3V2.. So check V1 */
3403                 if (pInfo->bV1tagFound == true) {
3404                         debug_msg(RELEASE, "Genre: %d", pInfo->genre);
3405
3406                         /* If out of range, set UNKNOWN */
3407                         if (pInfo->genre > GENRE_COUNT - 1)
3408                                 pInfo->genre = GENRE_COUNT - 1;
3409
3410                         pInfo->tagInfo[AV_ID3TAG_GENRE].value = g_strdup(MpegAudio_Genre[pInfo->genre]);
3411                 } else {
3412                         debug_msg(RELEASE, "Genre was not Found.");
3413                 }
3414         }
3415 }
3416
3417 static void __free_synclyrics(gpointer data)
3418 {
3419         AvSynclyricsInfo *info = (AvSynclyricsInfo *) data;
3420
3421         if (!info)
3422                 return;
3423
3424         mmfile_free(info->lyric_info);
3425         mmfile_free(info);
3426 }
3427
3428
3429 void mm_file_free_synclyrics_list(GList *synclyrics_list)
3430 {
3431         if (!synclyrics_list)
3432                 return;
3433
3434         g_list_free_full(synclyrics_list, __free_synclyrics);
3435 }