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