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