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