4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Haejeong Kim <backto.kim@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
28 #include <iniparser.h>
32 #include "mm_file_debug.h"
33 #include "mm_file_utils.h"
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
39 typedef struct _mmfilemp4basicboxheader {
42 long long start_offset; /*huge file*/
43 } MMFILE_MP4_BASIC_BOX_HEADER;
45 typedef struct _mmfilemp4ftpybox {
46 unsigned int major_brand;
47 unsigned short major_version;
48 unsigned short minor_version;
49 unsigned int *compatiable_brands;
53 eMMFILE_3GP_TAG_TITLE = 0x01,
54 eMMFILE_3GP_TAG_CAPTION = 0x02,
55 eMMFILE_3GP_TAG_COPYRIGHT = 0x03,
56 eMMFILE_3GP_TAG_PERFORMER = 0x04,
57 eMMFILE_3GP_TAG_AUTHOR = 0x05,
58 eMMFILE_3GP_TAG_GENRE = 0x06,
59 } eMMFILE_3GP_TEXT_TAG;
61 typedef struct _mmfile3gptagtextbox {
62 unsigned char version;
63 unsigned char flag[3];
64 unsigned char language[2];
66 } MMFILE_3GP_TEXT_TAGBOX;
68 typedef struct _mmfile3gptagyearbox {
69 unsigned char version;
70 unsigned char flag[3];
72 } MMFILE_3GP_YEAR_TAGBOX;
74 typedef struct _mmfile3gptagalbumbox {
75 unsigned char version;
76 unsigned char flag[3];
77 unsigned char language[2];
78 unsigned char *albumtile;
79 unsigned char trackNumber;
80 } MMFILE_3GP_ALBUM_TAGBOX;
82 typedef struct _mmfile3gpratingbox {
83 unsigned char version;
84 unsigned char flag[3];
85 unsigned int ratingEntity;
86 unsigned int ratingCriteria;
87 unsigned char language[2];
88 unsigned char *ratingInfo;
89 } MMFILE_3GP_RATING_TAGBOX;
91 typedef struct _mmfile3gpclsfbox {
92 unsigned char version;
93 unsigned char flag[3];
94 unsigned int classificationEntity;
95 unsigned int classificationTable;
96 unsigned char language[2];
97 unsigned char *classificationInfo;
98 } MMFILE_3GP_CLASSIFICATION_TAGBOX;
100 typedef struct _mmfile3gphdlrbox {
101 unsigned int version;
102 unsigned int pre_defined;
103 unsigned int handler_type;
104 unsigned int reserved[3];
105 unsigned char *boxname;
106 } MMFILE_3GP_HANDLER_BOX;
108 typedef struct _mmfileidv2box {
109 unsigned char version;
110 unsigned char flag[3];
111 unsigned char language[2];
112 unsigned char *id3v2Data;
113 } MMFILE_3GP_ID3V2_BOX;
115 typedef struct _mmfilelocibox {
116 unsigned char version;
117 unsigned char flag[3];
118 unsigned char language[2];
124 unsigned char *astronomical_body;
125 unsigned char *additional_notes;
126 } MMFILE_3GP_LOCATION_TAGBOX;
128 typedef struct _mmfilesmtabox {
131 unsigned char saut[4];
133 } MMFILE_M4A_SMTA_TAGBOX;
135 typedef struct _mmfilesa3dbox {
137 uint8_t ambisonic_type;
138 uint32_t ambisonic_order;
139 uint8_t ambisonic_channel_ordering;
140 uint8_t ambisonic_normalization;
141 uint32_t num_channels;
142 uint32_t channel_map[49]; /* Up to 6th order */
143 } __attribute__((aligned(1), packed)) MMFILE_MP4A_SA3D_TAGBOX;
146 PROJECTION_TYPE_RECT = 0, /* Rectangular, Google's RFC value */
147 PROJECTION_TYPE_EQUI = 1, /* Equirectangular, Google's RFC value */
148 PROJECTION_TYPE_CBMP = 2, /* Cubemap, Google's RFC value */
149 PROJECTION_TYPE_MESH = 3, /* Mesh, Google's RFC value, unsupported */
150 PROJECTION_TYPE_UNKNOWN = INVALID_UINT_VALUE,
151 } SPHERICAL_VIDEO2_PROJECTION_TYPE;
153 #define MMFILE_MP4_BASIC_BOX_HEADER_LEN 8
154 #define MMFILE_MP4_MOVIE_HEADER_BOX_LEN 96
155 #define MMFILE_MP4_HDLR_BOX_LEN 24
156 #define MMFILE_MP4_STSZ_BOX_LEN 20
157 #define MMFILE_MP4_MP4VBOX_LEN 80
158 #define MMFILE_MP4_MP4ABOX_LEN 28
159 #define MMFILE_3GP_TEXT_TAGBOX_LEN 6
160 #define MMFILE_3GP_YEAR_TAGBOX_LEN 6
161 #define MMFILE_3GP_ALBUM_TAGBOX_LEN 6
162 #define MMFILE_3GP_RATING_TAGBOX_LEN 14
163 #define MMFILE_3GP_CLASS_TAGBOX_LEN 14
164 #define MMFILE_3GP_HANDLER_BOX_LEN 24
165 #define MMFILE_3GP_ID3V2_BOX_LEN 6
166 #define MMFILE_SYNC_LYRIC_INFO_MIN_LEN 5
169 #define FOURCC(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
171 /*#define MIN(a, b) (((a) < (b)) ? (a):(b))*/
173 #define GENRE_COUNT 149
175 static const char *MpegAudio_Genre[GENRE_COUNT] = {"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal",
176 "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial",
177 "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
178 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
179 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
180 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
181 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
182 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
183 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
184 "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic",
185 "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove",
186 "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
187 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore",
188 "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian", "Heavy Metal", "Black Metal", "Crossover",
189 "Contemporary", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "Synthpop", "Unknown"
192 static unsigned char gTagJPEGHeader[] = {0xff, 0xd8, 0xff };
193 static unsigned char gTagPNGHeader[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
195 static int GetJunkCounterLimit(void);
197 static int GetStringFromTextTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header, eMMFILE_3GP_TEXT_TAG eTag)
199 int ret = MMFILE_UTIL_FAIL; /*fail*/
200 MMFILE_3GP_TEXT_TAGBOX texttag = {0, };
203 char *temp_text = NULL;
205 if (!formatContext || !fp || !basic_header) {
206 debug_error(DEBUG, "invalid param\n");
207 return MMFILE_UTIL_FAIL;
210 textBytes = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_TEXT_TAGBOX_LEN;
212 readed = mmfile_read(fp, (unsigned char *)&texttag, MMFILE_3GP_TEXT_TAGBOX_LEN);
213 if (readed != MMFILE_3GP_TEXT_TAGBOX_LEN) {
214 debug_error(DEBUG, "read text tag header fail\n");
215 ret = MMFILE_UTIL_FAIL;
219 if (textBytes <= 1) { /* there exist only 00(null) */
220 debug_error(DEBUG, "Text is NULL\n");
224 texttag.text = mmfile_malloc(textBytes);
226 debug_error(DEBUG, "malloc fail for text box\n");
227 ret = MMFILE_UTIL_FAIL;
231 readed = mmfile_read(fp, (unsigned char *)texttag.text, textBytes);
232 if (readed != textBytes) {
233 debug_error(DEBUG, "read text fail\n");
234 ret = MMFILE_UTIL_FAIL;
239 if ((texttag.text[0] == 0xFE) && (texttag.text[1] == 0xFF)) {
240 /* this char is UTF-16 */
241 unsigned int bytes_written = 0;
242 temp_text = mmfile_string_convert((const char *)&texttag.text[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
244 temp_text = mmfile_strdup((const char *)texttag.text);
248 case eMMFILE_3GP_TAG_TITLE: {
249 if (!formatContext->title) {
250 formatContext->title = g_strdup(temp_text);
254 case eMMFILE_3GP_TAG_CAPTION: {
255 if (!formatContext->description) {
256 formatContext->description = g_strdup(temp_text);
260 case eMMFILE_3GP_TAG_COPYRIGHT: {
261 if (!formatContext->copyright) {
262 formatContext->copyright = g_strdup(temp_text);
266 case eMMFILE_3GP_TAG_PERFORMER: {
267 if (!formatContext->artist) {
268 formatContext->artist = g_strdup(temp_text);
272 case eMMFILE_3GP_TAG_AUTHOR: {
273 if (!formatContext->author) {
274 formatContext->author = g_strdup(temp_text);
278 case eMMFILE_3GP_TAG_GENRE: {
279 if (!formatContext->genre) {
280 formatContext->genre = g_strdup(temp_text);
285 debug_warning(DEBUG, "Not supported Text Tag type[%d]\n", eTag);
290 mmfile_free(texttag.text);
292 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
296 return MMFILE_UTIL_SUCCESS;
299 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
301 mmfile_free(texttag.text);
306 static int GetYearFromYearTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
308 #define MAX_YEAR_BUFFER 10
310 MMFILE_3GP_YEAR_TAGBOX yearbox = {0, };
311 char temp_year[MAX_YEAR_BUFFER] = {0, };
313 if (!formatContext || !fp || !basic_header) {
314 debug_error(DEBUG, "invalid param\n");
315 return MMFILE_UTIL_FAIL;
318 readed = mmfile_read(fp, (unsigned char *)&yearbox, MMFILE_3GP_YEAR_TAGBOX_LEN);
319 if (readed != MMFILE_3GP_YEAR_TAGBOX_LEN) {
320 debug_error(DEBUG, "read yeartag header fail\n");
324 if (!formatContext->year) {
325 yearbox.year = mmfile_io_be_int16(yearbox.year);
326 snprintf(temp_year, MAX_YEAR_BUFFER, "%d", yearbox.year);
327 temp_year[MAX_YEAR_BUFFER - 1] = '\0';
328 formatContext->year = mmfile_strdup((const char *)temp_year);
331 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
332 return MMFILE_UTIL_SUCCESS;
335 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
337 return MMFILE_UTIL_FAIL;
340 static int GetAlbumFromAlbumTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
342 int albumTitleLen = 0;
343 char *temp_text = NULL;
346 MMFILE_3GP_ALBUM_TAGBOX albumbox = {0, };
348 if (!formatContext || !fp || !basic_header) {
349 debug_error(DEBUG, "invalid param\n");
350 return MMFILE_UTIL_FAIL;
353 readed = mmfile_read(fp, (unsigned char *)&albumbox, MMFILE_3GP_ALBUM_TAGBOX_LEN);
354 if (readed != MMFILE_3GP_ALBUM_TAGBOX_LEN) {
355 debug_error(DEBUG, "read albumtag header fail\n");
359 albumTitleLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ALBUM_TAGBOX_LEN - 1; /* 1: track number */
360 if (albumTitleLen > 1) { /* there exist only 00(null) */
361 debug_msg(RELEASE, "albumTitleLen=%d\n", albumTitleLen);
363 albumbox.albumtile = mmfile_malloc(albumTitleLen + 1); /* 1: for null char */
364 if (!albumbox.albumtile) {
365 debug_error(DEBUG, "malloc fail for album title text\n");
369 readed = mmfile_read(fp, (unsigned char *)albumbox.albumtile, albumTitleLen);
370 if (readed != albumTitleLen) {
371 debug_error(DEBUG, "read album title fail\n");
375 if (albumbox.albumtile[albumTitleLen - 1] == '\0') { /* there exist track number */
379 readed = mmfile_read(fp, (unsigned char *)&(albumbox.albumtile[albumTitleLen]), 1);
381 debug_error(DEBUG, "read album title fail\n");
384 albumbox.albumtile[albumTitleLen] = '\0';
388 if ((albumbox.albumtile[0] == 0xFE) && (albumbox.albumtile[1] == 0xFF)) {
389 /* this char is UTF-16 */
390 unsigned int bytes_written = 0;
391 temp_text = mmfile_string_convert((const char *)&albumbox.albumtile[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
393 temp_text = mmfile_strdup((const char *)albumbox.albumtile);
396 if (!formatContext->album)
397 formatContext->album = temp_text;
401 debug_msg(RELEASE, "formatContext->album=%s, strlen=%d\n", formatContext->album, strlen(formatContext->album));
405 readed = mmfile_read(fp, (unsigned char *)&albumbox.trackNumber, 1);
407 debug_error(DEBUG, "read track number fail\n");
411 if (formatContext->tagTrackNum == 0) {
412 char tracknum[10] = {0, };
413 snprintf(tracknum, 10, "%d", albumbox.trackNumber);
415 formatContext->tagTrackNum = mmfile_strdup((const char *)tracknum);
419 mmfile_free(albumbox.albumtile);
420 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
422 return MMFILE_UTIL_SUCCESS;
425 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
426 mmfile_free(albumbox.albumtile);
428 return MMFILE_UTIL_FAIL;
431 static int GetRatingFromRatingTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
434 int ratinginfoLen = 0;
435 char *temp_text = NULL;
437 MMFILE_3GP_RATING_TAGBOX ratingTag = {0, };
439 if (!formatContext || !fp || !basic_header) {
440 debug_error(DEBUG, "invalid param\n");
441 return MMFILE_UTIL_FAIL;
444 readed = mmfile_read(fp, (unsigned char *)&ratingTag, MMFILE_3GP_RATING_TAGBOX_LEN);
445 if (readed != MMFILE_3GP_RATING_TAGBOX_LEN) {
446 debug_error(DEBUG, "read rating tag header fail\n");
450 ratinginfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_RATING_TAGBOX_LEN;
452 if (ratinginfoLen == 1) {
453 debug_error(DEBUG, "Rating Text is NULL\n");
457 ratingTag.ratingInfo = mmfile_malloc(ratinginfoLen);
458 if (!ratingTag.ratingInfo) {
459 debug_error(DEBUG, "rating info error\n");
463 readed = mmfile_read(fp, (unsigned char *)ratingTag.ratingInfo, ratinginfoLen);
464 if (readed != ratinginfoLen) {
465 debug_error(DEBUG, "read rating info string fail\n");
470 if ((ratingTag.ratingInfo[0] == 0xFE) && (ratingTag.ratingInfo[1] == 0xFF)) {
471 /* this char is UTF-16 */
472 unsigned int bytes_written = 0;
473 temp_text = mmfile_string_convert((const char *)&ratingTag.ratingInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
475 temp_text = mmfile_strdup((const char *)ratingTag.ratingInfo);
478 if (!formatContext->rating) {
479 formatContext->rating = temp_text;
481 mmfile_free(temp_text);
484 mmfile_free(ratingTag.ratingInfo);
485 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
487 return MMFILE_UTIL_SUCCESS;
490 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
491 mmfile_free(ratingTag.ratingInfo);
493 return MMFILE_UTIL_FAIL;
497 static int GetClassficationFromClsfTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
499 int classinfoLen = 0;
501 char *temp_text = NULL;
502 MMFILE_3GP_CLASSIFICATION_TAGBOX classTag = {0, };
504 if (!formatContext || !fp || !basic_header) {
505 debug_error(DEBUG, "invalid param\n");
506 return MMFILE_UTIL_FAIL;
509 readed = mmfile_read(fp, (unsigned char *)&classTag, MMFILE_3GP_CLASS_TAGBOX_LEN);
510 if (readed != MMFILE_3GP_CLASS_TAGBOX_LEN) {
511 debug_error(DEBUG, "read classification tag header fail\n");
516 classinfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_CLASS_TAGBOX_LEN;
517 if (classinfoLen == 1) {
518 debug_error(DEBUG, "Classification Text is NULL\n");
522 classTag.classificationInfo = mmfile_malloc(classinfoLen);
523 if (!classTag.classificationInfo) {
524 debug_error(DEBUG, "class info error\n");
528 readed = mmfile_read(fp, (unsigned char *)classTag.classificationInfo, classinfoLen);
529 if (readed != classinfoLen) {
530 debug_error(DEBUG, "read class info string fail\n");
535 if ((classTag.classificationInfo[0] == 0xFE) && (classTag.classificationInfo[1] == 0xFF)) {
536 /* this char is UTF-16 */
537 unsigned int bytes_written = 0;
538 temp_text = mmfile_string_convert((const char *)&classTag.classificationInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
540 temp_text = mmfile_strdup((const char *)classTag.classificationInfo);
543 if (!formatContext->classification) {
544 formatContext->classification = temp_text;
546 mmfile_free(temp_text);
549 mmfile_free(classTag.classificationInfo);
550 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
552 return MMFILE_UTIL_SUCCESS;
555 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
556 mmfile_free(classTag.classificationInfo);
558 return MMFILE_UTIL_FAIL;
562 * The Location Information box
563 * --------------------+-------------------+-----------------------------------+------
564 * Field Type Details Value
565 * --------------------+-------------------+-----------------------------------+------
566 * BoxHeader.Size Unsigned int(32)
567 * BoxHeader.Type Unsigned int(32) 'loci'
568 * BoxHeader.Version Unsigned int(8) 0
569 * BoxHeader.Flags Bit(24) 0
571 * Language Unsigned int(5)[3] Packed ISO-639-2/T language code
572 * Name String Text of place name
573 * Role Unsigned int(8) Non-negative value indicating role
575 * Longitude Unsigned int(32) Fixed-point value of the longitude
576 * Latitude Unsigned int(32) Fixed-point value of the latitude
577 * Altitude Unsigned int(32) Fixed-point value of the Altitude
578 * Astronomical_body String Text of astronomical body
579 * Additional_notes String Text of additional location-related
581 * --------------------+-------------------+-----------------------------------+------
583 static int _get_char_position(unsigned char *src, char ch, int max)
586 for (i = 0; i < max; i++) {
587 if (*(src + i) == ch)
594 static int GetLocationFromLociTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
597 MMFILE_3GP_LOCATION_TAGBOX lociTag = {0, };
600 unsigned char *buffer = NULL;
601 unsigned char *p = NULL;
603 unsigned int bytes_written = 0;
604 unsigned int name_sz = 0;
605 unsigned int astro_sz = 0;
607 int ilong, ilati, ialti;
608 float flong, flati, falti;
611 if (!formatContext || !fp || !basic_header) {
612 debug_error(DEBUG, "invalid param\n");
613 return MMFILE_UTIL_FAIL;
616 readed = mmfile_read(fp, (unsigned char *)&lociTag, 6); /*6 = version + flag + pad + language */
618 debug_error(DEBUG, "read location tag header fail\n");
622 /*buffer len = name + role + ... + additional notes length */
623 bufferLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - 6;
625 debug_error(DEBUG, "too small buffer\n");
629 buffer = mmfile_malloc(bufferLen);
631 debug_error(DEBUG, "buffer malloc error\n");
635 readed = mmfile_read(fp, (unsigned char *)buffer, bufferLen);
636 if (readed != bufferLen) {
637 debug_error(DEBUG, "read location tag fail\n");
643 pos = _get_char_position(p, '\0', readed - (1 + 4 + 4 + 4 + 2));
645 if (p[0] == 0xFE && p[1] == 0xFF) {
646 lociTag.name = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
648 lociTag.name = (unsigned char *)mmfile_strdup((const char *)p);
660 debug_msg(RELEASE, "long: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 0), *(p + 1), *(p + 2), *(p + 3));
661 debug_msg(RELEASE, "lati: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 4), *(p + 5), *(p + 6), *(p + 7));
662 debug_msg(RELEASE, "alti: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 8), *(p + 9), *(p + 10), *(p + 11));
664 ilong = mmfile_io_be_uint32(*(unsigned int *)p);
665 ilati = mmfile_io_be_uint32(*(unsigned int *)(p + 4));
666 ialti = mmfile_io_be_uint32(*(unsigned int *)(p + 8));
668 flong = (float)ilong / (1 << 16);
669 flati = (float)ilati / (1 << 16);
670 falti = (float)ialti / (1 << 16);
673 lociTag.longitude = flong;
675 lociTag.latitude = flati;
677 lociTag.altitude = falti;
681 /*astronomical body*/
682 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + 1));
684 if (p[0] == 0xFE && p[1] == 0xFF) {
685 lociTag.astronomical_body = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
687 lociTag.astronomical_body = (unsigned char *)mmfile_strdup((const char *)p);
696 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + astro_sz));
698 if (p[0] == 0xFE && p[1] == 0xFF) {
699 lociTag.additional_notes = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
701 lociTag.additional_notes = (unsigned char *)mmfile_strdup((const char *)p);
707 debug_msg(RELEASE, "** Location Information **\n");
708 debug_msg(RELEASE, "Name : %s\n", lociTag.name);
709 debug_msg(RELEASE, "Role : %d (0: shooting, 1: real, 2: fictional, other: reserved)\n", lociTag.role);
710 debug_msg(RELEASE, "Longitude : %16.16f\n", lociTag.longitude);
711 debug_msg(RELEASE, "Latitude : %16.16f\n", lociTag.latitude);
712 debug_msg(RELEASE, "Altitude : %16.16f\n", lociTag.altitude);
713 debug_msg(RELEASE, "Astronomical body: %s\n", lociTag.astronomical_body);
714 debug_msg(RELEASE, "Additional notes : %s\n", lociTag.additional_notes);
716 formatContext->longitude = lociTag.longitude;
717 formatContext->latitude = lociTag.latitude;
718 formatContext->altitude = lociTag.altitude;
721 mmfile_free(lociTag.name);
722 mmfile_free(lociTag.astronomical_body);
723 mmfile_free(lociTag.additional_notes);
725 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
726 return MMFILE_UTIL_SUCCESS;
729 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
731 mmfile_free(lociTag.name);
732 mmfile_free(lociTag.astronomical_body);
733 mmfile_free(lociTag.additional_notes);
735 return MMFILE_UTIL_FAIL;
738 static int GetSAUTInfoFromSMTATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
740 MMFILE_M4A_SMTA_TAGBOX smtaTag = {0, };
743 if (!formatContext || !fp || !basic_header) {
744 debug_error(DEBUG, "invalid param\n");
745 return MMFILE_UTIL_FAIL;
748 readed = mmfile_read(fp, (unsigned char *)&smtaTag, sizeof(MMFILE_M4A_SMTA_TAGBOX));
749 if (readed != sizeof(MMFILE_M4A_SMTA_TAGBOX)) {
750 debug_error(DEBUG, "read smta tag header fail\n");
754 smtaTag.length = mmfile_io_be_uint32(smtaTag.length);
755 smtaTag.value = mmfile_io_be_uint32(smtaTag.value);
757 debug_msg(RELEASE, "Len : 0x%x", smtaTag.length);
758 debug_msg(RELEASE, "Saut : 0x%x 0x%x 0x%x 0x%x", smtaTag.saut[0], smtaTag.saut[1], smtaTag.saut[2], smtaTag.saut[3]);
759 debug_msg(RELEASE, "Value : 0x%x", smtaTag.value);
761 if (smtaTag.saut[0] == 's'
762 && smtaTag.saut[1] == 'a'
763 && smtaTag.saut[2] == 'u'
764 && smtaTag.saut[3] == 't') {
765 if (smtaTag.value == 0x01) {
766 debug_msg(RELEASE, "This has saut tag and valid value");
767 formatContext->smta = 1;
769 debug_error(DEBUG, "This has saut tag and but invalid value");
773 debug_error(DEBUG, "This hasn't saut tag and valid value");
777 return MMFILE_UTIL_SUCCESS;
780 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
782 return MMFILE_UTIL_FAIL;
785 static int GetSA3DInfoFromMP4ATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
787 if (!formatContext || !fp || !basic_header) {
788 debug_error(DEBUG, "invalid param\n");
789 return MMFILE_UTIL_FAIL;
792 unsigned char *buffer;
794 bool is_SA3D_present = false;
796 MMFILE_MP4A_SA3D_TAGBOX sa3dTag = {0, };
798 formatContext->ambisonicType = MMFILE_AMBISONIC_TYPE_UNKNOWN;
799 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_UNKNOWN;
800 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_UNKNOWN;
802 mmfile_seek(fp, basic_header->start_offset, SEEK_SET);
804 buffer = calloc(basic_header->size + 1, sizeof(unsigned char));
806 debug_error(DEBUG, "calloc failed ");
810 readed = mmfile_read(fp, buffer, basic_header->size);
811 if (readed != (int)basic_header->size) {
812 debug_error(DEBUG, "read mp4a box failed\n");
816 for (i = 0; i + 3 < basic_header->size; ++i)
817 if (buffer[i] == 'S' && buffer[i + 1] == 'A' && buffer[i + 2] == '3' && buffer[i + 3] == 'D') {
818 debug_warning(DEBUG, "SA3D data found at offset %d bytes\n", i);
819 is_SA3D_present = true;
823 if (!is_SA3D_present) {
824 debug_warning(DEBUG, "No SA3D box found");
828 mmfile_seek(fp, basic_header->start_offset + i + 4, SEEK_SET);
830 readed = mmfile_read(fp, (unsigned char *)&sa3dTag, sizeof(MMFILE_MP4A_SA3D_TAGBOX));
831 if (readed != sizeof(MMFILE_MP4A_SA3D_TAGBOX)) {
832 debug_error(DEBUG, "read SA3D tag header fail\n");
836 sa3dTag.ambisonic_order = mmfile_io_be_uint32(sa3dTag.ambisonic_order);
837 sa3dTag.num_channels = mmfile_io_be_uint32(sa3dTag.num_channels);
838 for (i = 0; i < sa3dTag.num_channels; ++i)
839 sa3dTag.channel_map[i] = mmfile_io_be_uint32(sa3dTag.channel_map[i]);
841 debug_msg(RELEASE, "sa3dTag.version = %d", sa3dTag.version);
842 debug_msg(RELEASE, "sa3dTag.ambisonic_type = %d", sa3dTag.ambisonic_type);
843 debug_msg(RELEASE, "sa3dTag.ambisonic_order = %d", sa3dTag.ambisonic_order);
844 debug_msg(RELEASE, "sa3dTag.ambisonic_channel_ordering = %d", sa3dTag.ambisonic_channel_ordering);
845 debug_msg(RELEASE, "sa3dTag.ambisonic_normalization = %d", sa3dTag.ambisonic_normalization);
846 debug_msg(RELEASE, "sa3dTag.num_channels = %d", sa3dTag.num_channels);
847 for (i = 0; i < sa3dTag.num_channels; ++i)
848 debug_msg(RELEASE, "sa3dTag.channel_map[%d] = %d", i, sa3dTag.channel_map[i]);
850 if (sa3dTag.version != RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
851 debug_error(DEBUG, "SA3D tag box version is unsupported\n");
854 if (sa3dTag.ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
855 formatContext->ambisonicType = MMFILE_AMBISONIC_TYPE_PERIPHONIC;
857 switch (sa3dTag.ambisonic_order) {
858 case MMFILE_AMBISONIC_ORDER_FOA: {
859 if (sa3dTag.num_channels == 4) {
860 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_FOA;
862 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
863 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
864 (sa3dTag.channel_map[0] == 0) &&
865 (sa3dTag.channel_map[1] == 1) &&
866 (sa3dTag.channel_map[2] == 2) &&
867 (sa3dTag.channel_map[3] == 3))
868 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
870 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
871 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
872 (sa3dTag.channel_map[0] == 0) &&
873 (sa3dTag.channel_map[1] == 3) &&
874 (sa3dTag.channel_map[2] == 1) &&
875 (sa3dTag.channel_map[3] == 2))
876 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
878 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
884 case MMFILE_AMBISONIC_ORDER_SOA: {
885 if (sa3dTag.num_channels == 9) {
886 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_SOA;
888 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
889 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
890 (sa3dTag.channel_map[0] == 0) &&
891 (sa3dTag.channel_map[1] == 1) &&
892 (sa3dTag.channel_map[2] == 2) &&
893 (sa3dTag.channel_map[3] == 3) &&
894 (sa3dTag.channel_map[4] == 4) &&
895 (sa3dTag.channel_map[5] == 5) &&
896 (sa3dTag.channel_map[6] == 6) &&
897 (sa3dTag.channel_map[7] == 7) &&
898 (sa3dTag.channel_map[8] == 8))
899 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
901 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
902 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
903 (sa3dTag.channel_map[0] == 0) &&
904 (sa3dTag.channel_map[1] == 3) &&
905 (sa3dTag.channel_map[2] == 1) &&
906 (sa3dTag.channel_map[3] == 2) &&
907 (sa3dTag.channel_map[4] == 6) &&
908 (sa3dTag.channel_map[5] == 7) &&
909 (sa3dTag.channel_map[6] == 5) &&
910 (sa3dTag.channel_map[7] == 8) &&
911 (sa3dTag.channel_map[8] == 4))
912 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
914 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
921 case MMFILE_AMBISONIC_ORDER_TOA: {
922 if (sa3dTag.num_channels == 16) {
923 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_TOA;
925 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
926 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
927 (sa3dTag.channel_map[0] == 0) &&
928 (sa3dTag.channel_map[1] == 1) &&
929 (sa3dTag.channel_map[2] == 2) &&
930 (sa3dTag.channel_map[3] == 3) &&
931 (sa3dTag.channel_map[4] == 4) &&
932 (sa3dTag.channel_map[5] == 5) &&
933 (sa3dTag.channel_map[6] == 6) &&
934 (sa3dTag.channel_map[7] == 7) &&
935 (sa3dTag.channel_map[8] == 8) &&
936 (sa3dTag.channel_map[9] == 9) &&
937 (sa3dTag.channel_map[10] == 10) &&
938 (sa3dTag.channel_map[11] == 11) &&
939 (sa3dTag.channel_map[12] == 12) &&
940 (sa3dTag.channel_map[13] == 13) &&
941 (sa3dTag.channel_map[14] == 14) &&
942 (sa3dTag.channel_map[15] == 15))
943 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
945 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
946 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
947 (sa3dTag.channel_map[0] == 0) &&
948 (sa3dTag.channel_map[1] == 3) &&
949 (sa3dTag.channel_map[2] == 1) &&
950 (sa3dTag.channel_map[3] == 2) &&
951 (sa3dTag.channel_map[4] == 6) &&
952 (sa3dTag.channel_map[5] == 7) &&
953 (sa3dTag.channel_map[6] == 5) &&
954 (sa3dTag.channel_map[7] == 8) &&
955 (sa3dTag.channel_map[8] == 4) &&
956 (sa3dTag.channel_map[9] == 12) &&
957 (sa3dTag.channel_map[10] == 13) &&
958 (sa3dTag.channel_map[11] == 11) &&
959 (sa3dTag.channel_map[12] == 14) &&
960 (sa3dTag.channel_map[13] == 10) &&
961 (sa3dTag.channel_map[14] == 15) &&
962 (sa3dTag.channel_map[15] == 9))
963 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
965 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
973 debug_warning(DEBUG, "Ambisonic order or format is not supported: ambix or amb formats up to 3rd order were expected.\n");
979 debug_msg(RELEASE, "formatContext->ambisonic_type = %d", formatContext->ambisonicType);
980 debug_msg(RELEASE, "formatContext->ambisonic_order = %d", formatContext->ambisonicOrder);
981 debug_msg(RELEASE, "formatContext->ambisonic_format = %d", formatContext->ambisonicFormat);
984 return MMFILE_UTIL_SUCCESS;
987 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
989 return MMFILE_UTIL_FAIL;
992 static int ParseSt3dData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset)
994 uint8_t stereo_mode = INVALID_UINT8_VALUE;
995 unsigned int readed = 0;
997 mmfile_seek(fp, start_offset, SEEK_SET);
999 readed = mmfile_read(fp, (unsigned char *)&stereo_mode, sizeof(uint8_t));
1000 if (readed != sizeof(uint8_t)) {
1001 debug_error(DEBUG, "read st3d tag header fail\n");
1002 return MMFILE_UTIL_FAIL;
1005 formatContext->stereoModeV2 = stereo_mode;
1007 return MMFILE_UTIL_SUCCESS;
1010 static int ParseSvhdData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset, unsigned int box_size)
1012 unsigned int readed = 0;
1014 formatContext->metadataSourceV2 = (char *)calloc(1, box_size);
1015 if (!formatContext->metadataSourceV2) {
1016 debug_error(DEBUG, "Calloc failed");
1017 return MMFILE_UTIL_FAIL;
1020 mmfile_seek(fp, start_offset, SEEK_SET);
1021 readed = mmfile_read(fp, (unsigned char *)formatContext->metadataSourceV2, box_size);
1022 if (readed != box_size) {
1023 debug_error(DEBUG, "read svhd tag header fail\n");
1024 if (formatContext->metadataSourceV2)
1025 free(formatContext->metadataSourceV2);
1026 return MMFILE_UTIL_FAIL;
1029 return MMFILE_UTIL_SUCCESS;
1032 static int ParseProjData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset)
1034 unsigned int readed = 0;
1035 typedef struct proj_box_data_s {
1039 } __attribute__((aligned(1), packed)) proj_box_data;
1041 typedef struct prhd_box_data_s {
1042 uint32_t projection_pose_yaw;
1043 uint32_t projection_pose_pitch;
1044 uint32_t projection_pose_roll;
1047 typedef struct equi_box_data_s {
1048 uint32_t projection_bounds_top;
1049 uint32_t projection_bounds_bottom;
1050 uint32_t projection_bounds_left;
1051 uint32_t projection_bounds_right;
1054 typedef struct cbmp_box_data_s {
1060 proj_box_data proj_data;
1061 proj_data.proj_type = INVALID_UINT_VALUE;
1063 prhd_box_data prhd_data;
1064 prhd_data.projection_pose_yaw = INVALID_UINT_VALUE;
1065 prhd_data.projection_pose_pitch = INVALID_UINT_VALUE;
1066 prhd_data.projection_pose_roll = INVALID_UINT_VALUE;
1068 equi_box_data equi_data;
1069 equi_data.projection_bounds_top = INVALID_UINT_VALUE;
1070 equi_data.projection_bounds_bottom = INVALID_UINT_VALUE;
1071 equi_data.projection_bounds_left = INVALID_UINT_VALUE;
1072 equi_data.projection_bounds_right = INVALID_UINT_VALUE;
1074 cbmp_box_data cbmp_data;
1075 cbmp_data.layout = INVALID_UINT_VALUE;
1076 cbmp_data.padding = INVALID_UINT_VALUE;
1078 mmfile_seek(fp, start_offset, SEEK_SET);
1080 readed = mmfile_read(fp, (unsigned char *)&proj_data, sizeof(proj_box_data));
1081 if (readed != sizeof(proj_box_data)) {
1082 debug_error(DEBUG, "read of proj box failed\n");
1083 return MMFILE_UTIL_FAIL;
1086 formatContext->projTypeV2 = mmfile_io_be_uint32(proj_data.proj_type);
1088 debug_error(DEBUG, "formatContext->projTypeV2 = %d\n", formatContext->projTypeV2);
1089 debug_error(DEBUG, "proj_data.version = %d\n", proj_data.version);
1090 debug_error(DEBUG, "proj_data.flags = %d\n", ((uint32_t)proj_data.flags[0] << 16) +
1091 ((uint32_t)proj_data.flags[1] << 8) + (uint32_t)proj_data.flags[2]);
1093 mmfile_seek(fp, sizeof(proj_box_data), SEEK_CUR);
1094 readed = mmfile_read(fp, (unsigned char *)&prhd_data, sizeof(prhd_box_data));
1095 if (readed != sizeof(prhd_box_data)) {
1096 debug_error(DEBUG, "read of prhd box failed\n");
1097 return MMFILE_UTIL_FAIL;
1100 formatContext->poseYawV2 = mmfile_io_be_uint32(prhd_data.projection_pose_yaw);
1101 formatContext->posePitchV2 = mmfile_io_be_uint32(prhd_data.projection_pose_pitch);
1102 formatContext->poseRollV2 = mmfile_io_be_uint32(prhd_data.projection_pose_roll);
1104 debug_error(DEBUG, "formatContext->poseYawV2 = %d\n", formatContext->poseYawV2);
1105 debug_error(DEBUG, "formatContext->posePitchV2 = %d\n", formatContext->posePitchV2);
1106 debug_error(DEBUG, "formatContext->poseRollV2 = %d\n", formatContext->poseRollV2);
1108 if (formatContext->projTypeV2 == PROJECTION_TYPE_EQUI) {
1109 debug_msg(RELEASE, "Projection type is Equirectangular");
1110 mmfile_seek(fp, 8, SEEK_CUR); /* 8 = 4 (for size) + 4 (fourcc) */
1111 readed = mmfile_read(fp, (unsigned char *)&equi_data, sizeof(equi_box_data));
1112 if (readed != sizeof(equi_box_data)) {
1113 debug_error(DEBUG, "read of equi box failed\n");
1114 return MMFILE_UTIL_FAIL;
1117 formatContext->equiBoundsTopV2 = mmfile_io_be_uint32(equi_data.projection_bounds_top);
1118 formatContext->equiBoundsBottomV2 = mmfile_io_be_uint32(equi_data.projection_bounds_bottom);
1119 formatContext->equiBoundsLeftV2 = mmfile_io_be_uint32(equi_data.projection_bounds_left);
1120 formatContext->equiBoundsRightV2 = mmfile_io_be_uint32(equi_data.projection_bounds_right);
1122 debug_error(DEBUG, "formatContext->equiBoundsTopV2 = %d\n", formatContext->equiBoundsTopV2);
1123 debug_error(DEBUG, "formatContext->equiBoundsBottomV2 = %d\n", formatContext->equiBoundsBottomV2);
1124 debug_error(DEBUG, "formatContext->equiBoundsLeftV2 = %d\n", formatContext->equiBoundsLeftV2);
1125 debug_error(DEBUG, "formatContext->equiBoundsRightV2 = %d\n", formatContext->equiBoundsRightV2);
1127 } else if (formatContext->projTypeV2 == PROJECTION_TYPE_CBMP) {
1128 debug_msg(RELEASE, "Projection type is Cubemap");
1129 mmfile_seek(fp, 8, SEEK_CUR); /* 8 = 4 (for size) + 4 (fourcc) */
1130 readed = mmfile_read(fp, (unsigned char *)&cbmp_data, sizeof(cbmp_box_data));
1131 if (readed != sizeof(cbmp_box_data)) {
1132 debug_error(DEBUG, "read of cbmp box failed\n");
1133 return MMFILE_UTIL_FAIL;
1136 formatContext->cbmpLayoutV2 = mmfile_io_be_uint32(cbmp_data.layout);
1137 formatContext->cbmpPaddingV2 = mmfile_io_be_uint32(cbmp_data.padding);
1139 debug_error(DEBUG, "formatContext->cbmpLayoutV2 = %d\n", formatContext->cbmpLayoutV2);
1140 debug_error(DEBUG, "formatContext->cbmpPaddingV2 = %d\n", formatContext->cbmpPaddingV2);
1143 debug_msg(RELEASE, "Projection type is %d (unknown)", proj_data.proj_type);
1144 return MMFILE_UTIL_FAIL;
1147 return MMFILE_UTIL_SUCCESS;
1150 static int GetVideoV2MetadataFromAvc1TagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1152 if (!formatContext || !fp || !basic_header) {
1153 debug_error(DEBUG, "invalid param\n");
1154 return MMFILE_UTIL_FAIL;
1157 unsigned char *buffer;
1161 formatContext->stereoModeV2 = INVALID_UINT_VALUE;
1162 formatContext->metadataSourceV2 = NULL;
1163 formatContext->projTypeV2 = INVALID_UINT_VALUE;
1164 formatContext->poseYawV2 = INVALID_UINT_VALUE;
1165 formatContext->posePitchV2 = INVALID_UINT_VALUE;
1166 formatContext->poseRollV2 = INVALID_UINT_VALUE;
1167 formatContext->cbmpLayoutV2 = INVALID_UINT_VALUE;
1168 formatContext->cbmpPaddingV2 = INVALID_UINT_VALUE;
1169 formatContext->equiBoundsTopV2 = INVALID_UINT_VALUE;
1170 formatContext->equiBoundsBottomV2 = INVALID_UINT_VALUE;
1171 formatContext->equiBoundsLeftV2 = INVALID_UINT_VALUE;
1172 formatContext->equiBoundsRightV2 = INVALID_UINT_VALUE;
1174 mmfile_seek(fp, basic_header->start_offset, SEEK_SET);
1176 buffer = calloc(basic_header->size + 1, sizeof(unsigned char));
1178 debug_error(DEBUG, "calloc failed ");
1182 readed = mmfile_read(fp, buffer, basic_header->size);
1183 if (readed != (int)basic_header->size) {
1184 debug_error(DEBUG, "read st3d box failed\n");
1188 for (i = 0; i + 3 < basic_header->size; ++i) {
1189 if ((buffer[i] == 's' && buffer[i + 1] == 't' && buffer[i + 2] == '3' && buffer[i + 3] == 'd') && (formatContext->stereoModeV2 == INVALID_UINT_VALUE)) {
1190 debug_warning(DEBUG, "st3d data found at offset %lld\n", basic_header->start_offset + i);
1191 ParseSt3dData(formatContext, fp, basic_header->start_offset + i + 4);
1192 debug_msg(RELEASE, "formatContext->stereoModeV2 = %d", formatContext->stereoModeV2);
1194 if (buffer[i] == 's' && buffer[i + 1] == 'v' && buffer[i + 2] == '3' && buffer[i + 3] == 'd') {
1195 debug_warning(DEBUG, "sv3d data found at offset %lld\n", basic_header->start_offset + i);
1196 formatContext->isSpherical = true;
1198 if (buffer[i] == 's' && buffer[i + 1] == 'v' && buffer[i + 2] == 'h' && buffer[i + 3] == 'd') {
1199 debug_warning(DEBUG, "svhd data found at offset %lld\n", basic_header->start_offset + i);
1200 ParseSvhdData(formatContext, fp, basic_header->start_offset + i + 4, mmfile_io_be_uint32(*((uint32_t*)(buffer - 4 + i))));
1201 debug_msg(RELEASE, "formatContext->metadataSourceV2 = %s (length = %d)", formatContext->metadataSourceV2, strlen(formatContext->metadataSourceV2));
1203 if (buffer[i] == 'p' && buffer[i + 1] == 'r' && buffer[i + 2] == 'o' && buffer[i + 3] == 'j') {
1204 debug_warning(DEBUG, "proj data found at offset %lld\n", basic_header->start_offset + i);
1205 ParseProjData(formatContext, fp, basic_header->start_offset + i + 4);
1209 return MMFILE_UTIL_SUCCESS;
1212 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1214 return MMFILE_UTIL_FAIL;
1217 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1219 unsigned int value = 0;
1222 if (!formatContext || !fp || !basic_header) {
1223 debug_error(DEBUG, "invalid param\n");
1224 return MMFILE_UTIL_FAIL;
1227 readed = mmfile_read(fp, (unsigned char *)&value, sizeof(unsigned int));
1228 if (readed != sizeof(unsigned int)) {
1229 debug_error(DEBUG, "read cdis tag header fail\n");
1233 value = mmfile_io_be_uint32(value);
1235 debug_msg(RELEASE, "Value : 0x%x", value);
1237 if (value == 0x01) {
1238 debug_msg(RELEASE, "This has cdis tag and valid value");
1239 formatContext->cdis = 1;
1241 debug_error(DEBUG, "This has cdis tag and but invalid value");
1245 return MMFILE_UTIL_SUCCESS;
1248 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1250 return MMFILE_UTIL_FAIL;
1253 static int GetTagFromMetaBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1256 MMFILE_MP4_BASIC_BOX_HEADER hdlrBoxHeader = {0, };
1257 MMFILE_MP4_BASIC_BOX_HEADER id3v2BoxHeader = {0, };
1258 MMFILE_3GP_ID3V2_BOX id3v2Box = {0, };
1259 AvFileContentInfo tagInfo = {0, };
1260 unsigned char tagVersion = 0;
1261 bool versionCheck = false;
1263 unsigned int meta_version = 0;
1264 MMFILE_3GP_HANDLER_BOX hdlrBox = {0, };
1265 unsigned int encSize = 0;
1267 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
1268 int iTunes_meta = 0;
1272 readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
1274 debug_error(DEBUG, "read meta box version\n");
1279 readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1280 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1281 debug_error(DEBUG, "read hdlr box header\n");
1285 if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
1286 debug_warning(DEBUG, "meta type is not hdlr\n");
1290 hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
1291 hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
1293 readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
1294 if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
1295 debug_error(DEBUG, "read hdlr box\n");
1299 hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
1302 * check tag type (ID3v2 or iTunes)
1304 if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
1305 debug_msg(RELEASE, "ID3v2 tag detected.\n");
1308 #ifdef ENABLE_ITUNES_META
1311 } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
1312 mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
1314 debug_msg(RELEASE, "Apple iTunes tag detected by mdir.\n");
1316 #ifdef ENABLE_ITUNES_META
1320 debug_warning(DEBUG, "unknown meta type. 4CC:[%c%c%c%c]\n", ((char *)&hdlrBox.handler_type)[0],
1321 ((char *)&hdlrBox.handler_type)[1],
1322 ((char *)&hdlrBox.handler_type)[2],
1323 ((char *)&hdlrBox.handler_type)[3]);
1324 /*goto exception; */
1327 #ifdef ENABLE_ITUNES_META
1328 if (!id3_meta && !iTunes_meta) {
1330 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
1331 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
1332 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
1334 const char *ilst_box = "ilst";
1335 int buf_size = strlen(ilst_box);
1337 unsigned char read_buf[buf_size + 1];
1338 memset(read_buf, 0x00, buf_size + 1);
1341 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR); /*+4 is hdlr size field */
1343 readed = mmfile_read(fp, read_buf, buf_size); /* to find 'ilst' */
1344 if (readed != buf_size) {
1345 debug_error(DEBUG, "read fail [%d]\n", readed);
1349 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
1350 debug_msg(RELEASE, "Apple iTunes tag detected by ilst.\n");
1356 #ifdef ENABLE_ITUNES_META
1359 * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
1367 #define _ITUNES_READ_BUF_SZ 20
1368 #define _ITUNES_TRACK_NUM_SZ 4
1369 #define _ITUNES_GENRE_NUM_SZ 4
1370 #define _ITUNES_COVER_TYPE_JPEG 13
1371 #define _ITUNES_COVER_TYPE_PNG 14
1373 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
1375 int cover_sz = 0, cover_type = 0, cover_found = 0;
1376 /* int track_found = 0; */ /* , track_num = 0; */
1377 /* int genre_found = 0; */ /* , genre_index = 0; */
1378 /* int artist_found = 0; */ /* , artist_sz = 0; */
1379 int limit = basic_header->size - hdlrBoxHeader.size;
1380 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
1382 /* 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++) { */
1383 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
1384 readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
1385 if (readed != _ITUNES_READ_BUF_SZ)
1388 /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
1389 but ffmpeg does not support strange cover image.
1390 only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
1393 * Artist : Added 2010.10.28
1395 if (artist_found == 0 &&
1396 read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
1397 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1400 artist_offset = mmfile_tell(fp);
1401 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
1403 debug_msg(RELEASE, "----------------------------------- artist found, offset=[%lld], size=[%d]\n", artist_offset, artist_sz);
1409 if (track_found == 0 &&
1410 read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
1411 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1414 track_offset = mmfile_tell(fp);
1416 debug_msg(RELEASE, "----------------------------------- Track found, offset=[%lld]\n", track_offset);
1420 * Genre : Added 2010.10.27
1422 /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
1423 if (genre_found == 0 &&
1424 read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
1425 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1428 genre_offset = mmfile_tell(fp);
1430 debug_msg(RELEASE, "----------------------------------- genre found, offset=[%lld]\n", genre_offset);
1438 if (cover_found == 0 &&
1439 read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
1440 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1443 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
1444 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
1446 cover_offset = mmfile_tell(fp);
1448 debug_msg(RELEASE, "----------------------------------- cover_found found, offset=[%lld]\n", cover_offset);
1451 mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR); /*FIXME: poor search*/
1454 /*ffmpeg extract artist, tracknum, excep cover image. see mov_read_udta_string()*/
1457 if (artist_sz > 0) {
1458 mmfile_seek(fp, artist_offset, SEEK_SET);
1460 if (formatContext->artist) {
1461 debug_msg(RELEASE, "----------------------------------- previous artist was [%s] \n", formatContext->artist);
1462 free(formatContext->artist);
1465 debug_msg(RELEASE, "----------------------------------- new artist will be allocated with size (len+1) [%d] \n", artist_sz + 1);
1466 formatContext->artist = mmfile_malloc(artist_sz + 1);
1468 if (formatContext->artist) {
1469 readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1470 formatContext->artist[artist_sz] = '\0';
1472 debug_msg(RELEASE, "----------------------------------- new artist is [%s] \n", formatContext->artist);
1474 if (readed != artist_sz) {
1475 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, artist_sz);
1476 mmfile_free(formatContext->artist);
1483 mmfile_seek(fp, track_offset, SEEK_SET);
1484 readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1485 if (readed != _ITUNES_TRACK_NUM_SZ) {
1486 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, _ITUNES_TRACK_NUM_SZ);
1488 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1489 if (!formatContext->tagTrackNum) {
1490 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1491 snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1492 formatContext->tagTrackNum = mmfile_strdup((const char *)read_buf);
1498 mmfile_seek(fp, genre_offset, SEEK_SET);
1499 readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1500 if (readed != _ITUNES_GENRE_NUM_SZ) {
1501 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, _ITUNES_GENRE_NUM_SZ);
1503 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1504 debug_msg(RELEASE, "genre index=[%d] \n", genre_index);
1506 if (genre_index > 0 && genre_index < GENRE_COUNT) {
1507 if (!formatContext->genre) {
1508 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1509 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1510 debug_msg(RELEASE, "genre string=[%s] \n", read_buf);
1511 formatContext->genre = mmfile_strdup((const char *)read_buf);
1519 1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1520 Music Cover Art Image Profile
1521 - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1522 - RGB (screen standard)
1523 - Minimum size of 600 x 600 pixels
1524 - Images must be at least 72 dpi
1526 2)I found below info from google.
1527 cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1529 3)So, FIXME when cover image format is tif!
1533 mmfile_seek(fp, cover_offset, SEEK_SET);
1535 formatContext->artwork = mmfile_malloc(cover_sz);
1536 formatContext->artworkSize = cover_sz;
1537 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1538 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1539 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1540 formatContext->artworkMime = mmfile_strdup("image/png");
1541 /*} else if(cover_type == _ITUNES_COVER_TYPE_TIF) {
1542 formatContext->artworkMime = mmfile_strdup("image/tif");*/
1544 debug_warning(DEBUG, "Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1545 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1548 if (formatContext->artwork) {
1549 readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1550 if (readed != cover_sz) {
1551 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, cover_sz);
1552 mmfile_free(formatContext->artwork);
1553 formatContext->artworkSize = 0;
1554 mmfile_free(formatContext->artworkMime);
1560 /*reset seek position*/
1561 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1563 return MMFILE_UTIL_SUCCESS;
1571 /* skip hdlr box name */
1572 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1575 readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1576 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1577 debug_error(DEBUG, "read id3v2 box header\n");
1581 id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1582 id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1584 if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1585 debug_warning(DEBUG, "meta type is not id3v2\n");
1589 readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1590 if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1591 debug_error(DEBUG, "read id3v2 box\n");
1595 id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1597 id3v2Box.id3v2Data = mmfile_malloc(id3v2Len);
1598 if (!id3v2Box.id3v2Data) {
1599 debug_error(DEBUG, "malloc id3tag data error\n");
1603 readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1604 if (readed != id3v2Len) {
1605 debug_error(DEBUG, "read id3tag data error\n");
1610 if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1611 debug_error(DEBUG, "it is not id3tag\n");
1615 if (id3v2Box.id3v2Data[3] == 0xFF || id3v2Box.id3v2Data[4] == 0xFF ||
1616 id3v2Box.id3v2Data[6] >= 0x80 || id3v2Box.id3v2Data[7] >= 0x80 ||
1617 id3v2Box.id3v2Data[8] >= 0x80 || id3v2Box.id3v2Data[9] >= 0x80) {
1618 debug_error(DEBUG, "it is not valid id3tag\n");
1622 tagVersion = id3v2Box.id3v2Data[3];
1623 if (tagVersion > 4) {
1624 debug_error(DEBUG, "tag vesion is too high\n");
1628 encSize = mmfile_io_le_uint32((unsigned int)&id3v2Box.id3v2Data[6]);
1629 tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1630 tagInfo.tagV2Info.tagLen += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
1631 tagInfo.tagV2Info.tagVersion = tagVersion;
1632 tagInfo.fileLen = id3v2Len;
1634 /* set id3v2 data to formatContext */
1635 switch (tagVersion) {
1637 versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data);
1641 versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data);
1645 versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data);
1650 debug_error(DEBUG, "tag vesion is not support\n");
1651 versionCheck = false;
1656 if (versionCheck == false) {
1657 debug_error(DEBUG, "tag parsing is fail\n");
1661 if (!formatContext->title) formatContext->title = mmfile_strdup((const char *)tagInfo.pTitle);
1662 if (!formatContext->artist) formatContext->artist = mmfile_strdup((const char *)tagInfo.pArtist);
1663 if (!formatContext->author) formatContext->author = mmfile_strdup((const char *)tagInfo.pAuthor);
1664 if (!formatContext->copyright) formatContext->copyright = mmfile_strdup((const char *)tagInfo.pCopyright);
1665 if (!formatContext->comment) formatContext->comment = mmfile_strdup((const char *)tagInfo.pComment);
1666 if (!formatContext->album) formatContext->album = mmfile_strdup((const char *)tagInfo.pAlbum);
1667 if (!formatContext->album_artist) formatContext->album_artist = mmfile_strdup((const char *)tagInfo.pAlbum_Artist);
1668 if (!formatContext->year) formatContext->year = mmfile_strdup((const char *)tagInfo.pYear);
1669 if (!formatContext->genre) formatContext->genre = mmfile_strdup((const char *)tagInfo.pGenre);
1670 if (!formatContext->tagTrackNum) formatContext->tagTrackNum = mmfile_strdup((const char *)tagInfo.pTrackNum);
1671 if (!formatContext->composer) formatContext->composer = mmfile_strdup((const char *)tagInfo.pComposer);
1672 if (!formatContext->classification) formatContext->classification = mmfile_strdup((const char *)tagInfo.pContentGroup);
1673 if (!formatContext->conductor) formatContext->conductor = mmfile_strdup((const char *)tagInfo.pConductor);
1675 formatContext->artwork = mmfile_malloc(tagInfo.imageInfo.imageLen);
1676 if ((tagInfo.imageInfo.imageLen > 0) && formatContext->artwork) {
1677 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1678 memcpy(formatContext->artwork, tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1681 mm_file_free_AvFileContentInfo(&tagInfo);
1682 mmfile_free(id3v2Box.id3v2Data);
1684 /*reset seek position*/
1685 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1687 return MMFILE_UTIL_SUCCESS;
1693 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1694 mmfile_free(id3v2Box.id3v2Data);
1695 mm_file_free_AvFileContentInfo(&tagInfo);
1697 return MMFILE_UTIL_FAIL;
1700 int mm_file_get_int_value_from_xml_string(const char* xml_str, const char* param_name, int* value)
1702 char *value_start, *value_end, *endptr;
1703 const short value_length_max = 12;
1704 char init_view_ret[value_length_max];
1705 int value_length = 0;
1707 if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1708 debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
1709 return MMFILE_UTIL_FAIL;
1712 value_start = strstr(xml_str, param_name) + strlen(param_name);
1713 while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1716 value_end = strchr(value_start, '<');
1718 debug_error(DEBUG, "error: incorrect XML\n");
1719 return MMFILE_UTIL_FAIL;
1722 value_length = value_end - value_start;
1723 while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1727 if (value_start[i] == '+' || value_start[i] == '-')
1729 while (i < value_length) {
1730 if (value_start[i] < '0' || value_start[i] > '9') {
1731 debug_error(DEBUG, "error: incorrect value, integer was expected\n");
1732 return MMFILE_UTIL_FAIL;
1737 if (value_length >= value_length_max || value_length < 1) {
1738 debug_error(DEBUG, "error: empty XML value or incorrect range\n");
1739 return MMFILE_UTIL_FAIL;
1742 memset(init_view_ret, 0x00, sizeof(init_view_ret));
1743 SAFE_STRLCPY(init_view_ret, value_start, sizeof(init_view_ret));
1745 *value = strtol(init_view_ret, &endptr, 10);
1746 if (endptr == init_view_ret) {
1747 debug_error(DEBUG, "error: no digits were found\n");
1748 return MMFILE_UTIL_FAIL;
1751 return MMFILE_UTIL_SUCCESS;
1754 int mm_file_get_string_value_from_xml_string(const char* xml_str, const char* param_name, char** value)
1756 char *value_start, *value_end;
1757 const short value_length_max = 256;
1758 int value_length = 0;
1760 if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1761 debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
1762 return MMFILE_UTIL_FAIL;
1765 value_start = strstr(xml_str, param_name) + strlen(param_name);
1766 while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1769 value_end = strchr(value_start, '<');
1771 debug_error(DEBUG, "error: incorrect XML\n");
1772 return MMFILE_UTIL_FAIL;
1775 value_length = value_end - value_start;
1776 while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1779 if (value_length >= value_length_max || value_length < 1) {
1780 debug_error(DEBUG, "error: empty XML value or incorrect range\n");
1781 return MMFILE_UTIL_FAIL;
1784 *value = (char*)calloc(value_length, sizeof(char));
1785 if (*value == NULL) {
1786 debug_error(DEBUG, "error: calloc failed\n");
1787 return MMFILE_UTIL_FAIL;
1789 strncpy(*value, value_start, value_length);
1791 return MMFILE_UTIL_SUCCESS;
1794 int mm_file_get_bool_value_from_xml_string(const char* xml_str, const char* param_name, bool* value)
1796 char *value_start, *value_end;
1797 int value_length = 0;
1799 if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1800 debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
1801 return MMFILE_UTIL_FAIL;
1804 value_start = strstr(xml_str, param_name) + strlen(param_name);
1805 while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1808 value_end = strchr(value_start, '<');
1810 debug_error(DEBUG, "error: incorrect XML\n");
1811 return MMFILE_UTIL_FAIL;
1814 value_length = value_end - value_start;
1815 while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1818 if (value_length < 1) {
1819 debug_error(DEBUG, "error: empty XML value or incorrect range\n");
1820 return MMFILE_UTIL_FAIL;
1823 *value = strstr(value_start, "true") ? true : false;
1825 return MMFILE_UTIL_SUCCESS;
1828 static int g_junk_counter_limit = 0;
1829 static int GetJunkCounterLimit(void)
1831 dictionary *dict = NULL;
1834 dict = iniparser_load(MM_FILE_INI_PATH);
1836 debug_error(DEBUG, "%s load failed", MM_FILE_INI_PATH);
1840 data = iniparser_getint(dict, "mm-file-config:junk_counter_limit", 0);
1841 debug_msg(DEBUG, "mm-file-config:junk_counter_limit= %u", data);
1843 iniparser_freedict(dict);
1848 static int ParseSpatialVideoMetadataFromXMLString(const char *xmlStr, MMFileFormatContext *formatContext)
1850 const char is_spherical_str[] = "<GSpherical:Spherical>";
1851 const char is_stitched_str[] = "<GSpherical:Stitched>";
1852 const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
1853 const char projection_type_str[] = "<GSpherical:ProjectionType>";
1854 const char stereo_mode_str[] = "<GSpherical:StereoMode>";
1855 const char source_count_str[] = "<GSpherical:SourceCount>";
1856 const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
1857 const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
1858 const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
1859 const char timestamp_str[] = "<GSpherical:Timestamp>";
1860 const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
1861 const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
1862 const char cropped_area_image_width_str[] = "<GSpherical:CroppedAreaImageWidthPixels>";
1863 const char cropped_area_image_height_str[] = "<GSpherical:CroppedAreaImageHeightPixels>";
1864 const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
1865 const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
1867 mm_file_get_bool_value_from_xml_string(xmlStr, is_spherical_str, (bool*)&formatContext->isSpherical);
1868 mm_file_get_bool_value_from_xml_string(xmlStr, is_stitched_str, (bool*)&formatContext->isStitched);
1870 debug_msg(RELEASE, "isSpherical = %d", formatContext->isSpherical);
1871 debug_msg(RELEASE, "isStitched = %d", formatContext->isStitched);
1873 if (formatContext->isSpherical && formatContext->isStitched) {
1874 mm_file_get_string_value_from_xml_string(xmlStr, stitching_software_str, &formatContext->stitchingSoftware);
1875 mm_file_get_string_value_from_xml_string(xmlStr, projection_type_str, &formatContext->projectionType);
1876 mm_file_get_string_value_from_xml_string(xmlStr, stereo_mode_str, &formatContext->stereoMode);
1877 mm_file_get_int_value_from_xml_string(xmlStr, source_count_str, &formatContext->sourceCount);
1878 mm_file_get_int_value_from_xml_string(xmlStr, init_view_heading_str, &formatContext->initViewHeading);
1879 mm_file_get_int_value_from_xml_string(xmlStr, init_view_pitch_str, &formatContext->initViewPitch);
1880 mm_file_get_int_value_from_xml_string(xmlStr, init_view_roll_str, &formatContext->initViewRoll);
1881 mm_file_get_int_value_from_xml_string(xmlStr, timestamp_str, &formatContext->timestamp);
1882 mm_file_get_int_value_from_xml_string(xmlStr, full_pano_width_str, &formatContext->fullPanoWidth);
1883 mm_file_get_int_value_from_xml_string(xmlStr, full_pano_height_str, &formatContext->fullPanoHeight);
1884 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_width_str, &formatContext->croppedAreaImageWidth);
1885 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_height_str, &formatContext->croppedAreaImageHeight);
1886 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_left_str, &formatContext->croppedAreaLeft);
1887 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_top_str, &formatContext->croppedAreaTop);
1889 debug_msg(RELEASE, "stitchingSoftware = %s", formatContext->stitchingSoftware);
1890 debug_msg(RELEASE, "projectionType = %s", formatContext->projectionType);
1891 debug_msg(RELEASE, "stereoMode = %s", formatContext->stereoMode);
1892 debug_msg(RELEASE, "sourceCount %d", formatContext->sourceCount);
1893 debug_msg(RELEASE, "initViewHeading = %d", formatContext->initViewHeading);
1894 debug_msg(RELEASE, "initViewPitch = %d", formatContext->initViewPitch);
1895 debug_msg(RELEASE, "initViewRoll = %d", formatContext->initViewRoll);
1896 debug_msg(RELEASE, "timestamp = %d", formatContext->timestamp);
1897 debug_msg(RELEASE, "fullPanoWidthPixels = %d", formatContext->fullPanoWidth);
1898 debug_msg(RELEASE, "fullPanoHeightPixels = %d", formatContext->fullPanoHeight);
1899 debug_msg(RELEASE, "croppedAreaImageWidth = %d", formatContext->croppedAreaImageWidth);
1900 debug_msg(RELEASE, "croppedAreaImageHeight = %d", formatContext->croppedAreaImageHeight);
1901 debug_msg(RELEASE, "croppedAreaLeft = %d", formatContext->croppedAreaLeft);
1902 debug_msg(RELEASE, "croppedAreaTop = %d", formatContext->croppedAreaTop);
1905 return MMFILE_UTIL_SUCCESS;
1908 #define BIG_CONTENT_BOX_SIZE_LEN 8
1909 EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
1911 MMFileIOHandle *fp = NULL;
1914 unsigned long long chunk_size = 0;
1915 long long moov_end = 0;
1916 MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
1917 int junk_counter = 0;
1919 ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1920 if (ret == MMFILE_UTIL_FAIL) {
1921 debug_error(DEBUG, "error: mmfile_open\n");
1925 basic_header.start_offset = mmfile_tell(fp);
1927 if (g_junk_counter_limit == 0)
1928 g_junk_counter_limit = GetJunkCounterLimit();
1930 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)) {
1931 basic_header.size = mmfile_io_be_uint32(basic_header.size);
1932 basic_header.type = mmfile_io_le_uint32(basic_header.type);
1934 if (basic_header.size == 0) {
1935 debug_warning(DEBUG, "header is invalid.\n");
1936 basic_header.size = readed;
1937 basic_header.type = 0;
1938 chunk_size = basic_header.size;
1940 if ((moov_end != 0) && (moov_end < basic_header.start_offset)) {
1941 debug_msg(DEBUG, "found junk data but moov data already was extracted, so junk counter will be increase: %d", junk_counter);
1944 /* stop the loop for junk case. */
1945 if ((g_junk_counter_limit > 0) && (junk_counter > g_junk_counter_limit)) {
1946 debug_msg(DEBUG, "stop the loop by junk-data checker");
1947 ret = MMFILE_UTIL_FAIL;
1951 } else if (basic_header.size == 1) {
1953 unsigned char temp[BIG_CONTENT_BOX_SIZE_LEN] = {0, };
1954 unsigned long long size = 0;
1956 mmfile_read(fp, (unsigned char *)&temp, BIG_CONTENT_BOX_SIZE_LEN);
1958 for (i = 0; i < BIG_CONTENT_BOX_SIZE_LEN; i++)
1959 size |= (unsigned long long)temp[i] << (BIG_CONTENT_BOX_SIZE_LEN - 1 - i) * BIG_CONTENT_BOX_SIZE_LEN;
1963 chunk_size = basic_header.size;
1967 switch (basic_header.type) {
1968 case FOURCC('m', 'o', 'o', 'v'): {
1969 debug_msg(RELEASE, "MPEG4: [moov] SIZE: [%lld]Byte\n", chunk_size);
1970 moov_end = basic_header.start_offset + chunk_size;
1973 case FOURCC('u', 'd', 't', 'a'): {
1974 debug_msg(RELEASE, "MPEG4: [udat] SIZE: [%lld]Byte\n", chunk_size);
1977 /*/////////////////////////////////////////////////////////////// */
1978 /* Extracting Tag Data // */
1979 /*/////////////////////////////////////////////////////////////// */
1980 case FOURCC('t', 'i', 't', 'l'): {
1981 debug_msg(RELEASE, "MPEG4: [titl] SIZE: [%lld]Byte\n", chunk_size);
1982 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
1985 case FOURCC('d', 's', 'c', 'p'): {
1986 debug_msg(RELEASE, "MPEG4: [dscp] SIZE: [%lld]Byte\n", chunk_size);
1987 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
1990 case FOURCC('c', 'p', 'r', 't'): {
1991 debug_msg(RELEASE, "MPEG4: [cprt] SIZE: [%lld]Byte\n", chunk_size);
1992 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
1995 case FOURCC('p', 'e', 'r', 'f'): {
1996 debug_msg(RELEASE, "MPEG4: [perf] SIZE: [%lld]Byte\n", chunk_size);
1997 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
2000 case FOURCC('a', 'u', 't', 'h'): {
2001 debug_msg(RELEASE, "MPEG4: [auth] SIZE: [%lld]Byte\n", chunk_size);
2002 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
2005 case FOURCC('g', 'n', 'r', 'e'): {
2006 debug_msg(RELEASE, "MPEG4: [gnre] SIZE: [%lld]Byte\n", chunk_size);
2007 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
2010 case FOURCC('a', 'l', 'b', 'm'): {
2011 debug_msg(RELEASE, "MPEG4: [albm] SIZE: [%lld]Byte\n", chunk_size);
2012 GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
2015 case FOURCC('y', 'r', 'r', 'c'): {
2016 debug_msg(RELEASE, "MPEG4: [yrrc] SIZE: [%lld]Byte\n", chunk_size);
2017 GetYearFromYearTagBox(formatContext, fp, &basic_header);
2020 case FOURCC('r', 't', 'n', 'g'): {
2021 debug_msg(RELEASE, "MPEG4: [rtng] SIZE: [%lld]Byte\n", chunk_size);
2022 GetRatingFromRatingTagBox(formatContext, fp, &basic_header); /* not use */
2025 case FOURCC('c', 'l', 's', 'f'): {
2026 debug_msg(RELEASE, "MPEG4: [clsf] SIZE: [%lld]Byte\n", chunk_size);
2027 GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
2030 case FOURCC('k', 'y', 'w', 'd'): {
2031 debug_msg(RELEASE, "MPEG4: [kywd] SIZE: [%lld]Byte\n", chunk_size);
2032 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2035 case FOURCC('l', 'o', 'c', 'i'): {
2036 debug_msg(RELEASE, "MPEG4: [loci] SIZE: [%lld]Byte\n", chunk_size);
2037 GetLocationFromLociTagBox(formatContext, fp, &basic_header);
2040 /* Check smta in user data field (moov) to be compatible with android */
2041 case FOURCC('s', 'm', 't', 'a'): {
2042 debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
2043 GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
2046 /* Check cdis in user data field (moov) to be compatible with android */
2047 case FOURCC('c', 'd', 'i', 's'): {
2048 debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
2049 GetValueFromCDISTagBox(formatContext, fp, &basic_header);
2052 /*/////////////////////////////////////////////////////////////// */
2053 /* Extracting ID3 Tag Data // */
2054 /*/////////////////////////////////////////////////////////////// */
2055 case FOURCC('m', 'e', 't', 'a'): {
2056 debug_msg(RELEASE, "MPEG4: [meta] SIZE: [%lld]Byte\n", chunk_size);
2057 GetTagFromMetaBox(formatContext, fp, &basic_header);
2061 case FOURCC('t', 'r', 'a', 'k'): {
2062 debug_msg(RELEASE, "MPEG4: [trak] SIZE: [%lld]Byte\n", chunk_size);
2065 case FOURCC('u', 'u', 'i', 'd'): {
2066 unsigned long uuid[4] = {0, };
2068 debug_msg(RELEASE, "MPEG4: [uuid] SIZE: [%lld]Byte\n", chunk_size);
2070 mmfile_read(fp, (unsigned char *)uuid, sizeof(uuid));
2072 if (mmfile_io_be_uint32(uuid[0]) == 0xffcc8263
2073 && mmfile_io_be_uint32(uuid[1]) == 0xf8554a93
2074 && mmfile_io_be_uint32(uuid[2]) == 0x8814587a
2075 && mmfile_io_be_uint32(uuid[3]) == 0x02521fdd) {
2077 str = (char *)malloc(basic_header.size);
2080 memset(str, 0, basic_header.size);
2081 mmfile_read(fp, (unsigned char *)str, basic_header.size);
2083 /* The block is superseded */
2084 if (strstr(str, "<GSpherical:Spherical>true</GSpherical:Spherical>"))
2085 formatContext->is_360 = 1;
2087 formatContext->is_360 = 0;
2088 /* Image can be stitched even if it is not spherical */
2089 if (formatContext->is_360 == 1) {
2090 if (strstr(str, "<GSpherical:Stitched>true</GSpherical:Stitched>"))
2091 formatContext->stitched = MMFILE_360_STITCHED;
2093 formatContext->stitched = MMFILE_360_NON_STITCHED;
2095 /* Image can be stitched or non-stitched. Usage of some 3rd value is superfluous */
2096 formatContext->stitched = MMFILE_360_NONE;
2100 debug_msg(RELEASE, "Extracting tags from UUID XML string %s\n", str);
2102 ParseSpatialVideoMetadataFromXMLString(str, formatContext);
2105 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2109 case FOURCC('m', 'd', 'i', 'a'): {
2110 debug_msg(RELEASE, "MPEG4: [mdia] SIZE: [%lld]Byte\n", chunk_size);
2113 case FOURCC('m', 'i', 'n', 'f'): {
2114 debug_msg(RELEASE, "MPEG4: [minf] SIZE: [%lld]Byte\n", chunk_size);
2117 case FOURCC('s', 't', 'b', 'l'): {
2118 debug_msg(RELEASE, "MPEG4: [stbl] SIZE: [%lld]Byte\n", chunk_size);
2121 case FOURCC('s', 't', 's', 'd'): {
2122 debug_msg(RELEASE, "MPEG4: [stsd] SIZE: [%lld]Byte\n", chunk_size);
2125 case FOURCC('m', 'p', '4', 'a'): {
2126 debug_msg(RELEASE, "MPEG4: [mp4a] SIZE: [%lld]Byte\n", chunk_size);
2127 GetSA3DInfoFromMP4ATagBox(formatContext, fp, &basic_header);
2128 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2131 case FOURCC('a', 'v', 'c', '1'): {
2132 debug_msg(RELEASE, "MPEG4: [avc1] SIZE: [%lld]Byte (offset: %lld)\n", chunk_size, basic_header.start_offset);
2133 GetVideoV2MetadataFromAvc1TagBox(formatContext, fp, &basic_header);
2137 debug_msg(RELEASE, "4CC: Not Support [%c%c%c%c]. So skip it. Size [%lld Byte]\n",
2138 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
2139 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3], chunk_size);
2140 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2145 if (ret == MMFILE_UTIL_FAIL) {
2146 debug_error(DEBUG, "mmfile operation is error\n");
2151 long long new_pos = mmfile_tell(fp);
2153 if ((moov_end == 0) && (new_pos <= basic_header.start_offset)) {
2154 debug_error(DEBUG, "Wrong position");
2155 ret = MMFILE_UTIL_FAIL;
2158 basic_header.start_offset = new_pos;
2167 static char *get_string(const char *buf, int buf_size, int *bytes_written)
2171 char str[512] = {0, };
2174 for (i = 0; i < buf_size; i++) {
2178 if ((q - str) >= (int)sizeof(str) - 1)
2184 if (strlen(str) > 0) {
2185 *bytes_written = strlen(str);
2193 static bool is_numeric(const char *buf, int buf_size)
2198 for (idx = 0; idx < buf_size; idx++) {
2199 if (isdigit((int)buf[idx])) {
2210 char *rtrimN(char *pStr)
2213 pos = strlen(pStr) - 1;
2214 for (; pos >= 0; pos--) {
2215 if (pStr[pos] == 0x20) {
2222 return strdup(pStr);
2225 bool safe_atoi(char *buffer, int *si)
2231 const long sl = strtol(buffer, &end, 10);
2233 if (end == buffer) {
2234 debug_error(RELEASE, "not a decimal number");
2236 } else if ('\0' != *end) {
2237 debug_error(RELEASE, "extra characters at end of input: %s", end);
2239 } else if ((LONG_MIN == sl || LONG_MAX == sl) && (ERANGE == errno)) {
2240 debug_error(RELEASE, "out of range of type long");
2242 } else if (sl > INT_MAX) {
2243 debug_error(RELEASE, "greater than INT_MAX");
2245 } else if (sl < INT_MIN) {
2246 debug_error(RELEASE, "less than INT_MIN");
2254 static bool make_characterset_array(char ***charset_array)
2256 char *locale = MMFileUtilGetLocale(NULL);
2258 *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
2260 if (*charset_array == NULL) {
2261 debug_error(DEBUG, "calloc failed ");
2267 if (locale != NULL) {
2268 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
2270 debug_error(DEBUG, "get locale failed");
2271 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
2274 (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
2275 (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
2276 (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
2281 static bool release_characterset_array(char **charset_array)
2285 for (i = 0; i < AV_ID3V2_MAX; i++) {
2286 if (charset_array[i] != NULL) {
2287 free(charset_array[i]);
2288 charset_array[i] = NULL;
2292 if (charset_array != NULL) {
2293 free(charset_array);
2294 charset_array = NULL;
2300 static void init_content_info(AvFileContentInfo *pInfo)
2302 pInfo->tagV2Info.bTitleMarked = false;
2303 pInfo->tagV2Info.bArtistMarked = false;
2304 pInfo->tagV2Info.bAlbumMarked = false;
2305 pInfo->tagV2Info.bAlbum_ArtistMarked = false;
2306 pInfo->tagV2Info.bYearMarked = false;
2307 pInfo->tagV2Info.bDescriptionMarked = false;
2308 pInfo->tagV2Info.bGenreMarked = false;
2309 pInfo->tagV2Info.bTrackNumMarked = false;
2310 pInfo->tagV2Info.bEncByMarked = false;
2311 pInfo->tagV2Info.bURLMarked = false;
2312 pInfo->tagV2Info.bCopyRightMarked = false;
2313 pInfo->tagV2Info.bOriginArtistMarked = false;
2314 pInfo->tagV2Info.bComposerMarked = false;
2315 pInfo->tagV2Info.bImageMarked = false;
2317 pInfo->tagV2Info.bRecDateMarked = false;
2318 pInfo->tagV2Info.bContentGroupMarked = false;
2320 pInfo->tagV2Info.bUnsyncLyricsMarked = false;
2321 pInfo->tagV2Info.bSyncLyricsMarked = false;
2322 pInfo->tagV2Info.bConductorMarked = false;
2323 pInfo->tagV2Info.bGenreUTF16 = false;
2325 pInfo->imageInfo.bURLInfo = false;
2326 pInfo->imageInfo.pImageBuf = NULL;
2327 pInfo->imageInfo.imageLen = 0;
2331 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo, unsigned char *buffer)
2333 const char *locale = MMFileUtilGetLocale(NULL);
2334 char *pFullStr = NULL;
2336 debug_msg(RELEASE, "ID3tag v110--------------------------------------------------------------\n");
2338 if (pInfo->tagV2Info.bTitleMarked == false) {
2339 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
2340 if (pFullStr != NULL) {
2341 pInfo->pTitle = rtrimN(pFullStr);
2345 debug_msg(RELEASE, "pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2348 if (pInfo->tagV2Info.bArtistMarked == false) {
2349 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
2350 if (pFullStr != NULL) {
2351 pInfo->pArtist = rtrimN(pFullStr);
2355 debug_msg(RELEASE, "pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2358 if (pInfo->tagV2Info.bAlbumMarked == false) {
2359 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
2360 if (pFullStr != NULL) {
2361 pInfo->pAlbum = rtrimN(pFullStr);
2365 debug_msg(RELEASE, "pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2368 if (pInfo->tagV2Info.bYearMarked == false) {
2370 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
2372 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2374 if (pInfo->pYear == NULL) { /*Use same logic with ffmpeg*/
2375 pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
2376 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2380 if (pInfo->tagV2Info.bDescriptionMarked == false) {
2381 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
2382 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2384 if (pInfo->pComment == NULL) { /*Use same logic with ffmpeg*/
2385 pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
2386 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2390 if (pInfo->tagV2Info.bTrackNumMarked == false) {
2391 pInfo->pTrackNum = mmfile_malloc(5);
2392 if (pInfo->pTrackNum != NULL) {
2393 pInfo->pTrackNum[4] = 0;
2394 snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
2395 pInfo->tracknumLen = strlen(pInfo->pTrackNum);
2397 debug_msg(RELEASE, "pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2401 if (pInfo->tagV2Info.bGenreMarked == false) {
2402 pInfo->genre = buffer[127];
2403 debug_msg(RELEASE, "pInfo->genre returned genre number (%d)\n", pInfo->genre);
2410 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
2412 unsigned long taglen = 0;
2413 unsigned long needToloopv2taglen;
2414 unsigned long oneFrameLen = 0;
2415 unsigned long v2numOfFrames = 0;
2416 unsigned long curPos = 0;
2418 unsigned char *pExtContent = NULL;
2419 unsigned long purelyFramelen = 0;
2420 unsigned int encodingOffSet = 0;
2421 int inx = 0, realCpyFrameNum = 0,
2422 /*checkImgMimeTypeMax = 0, */checkImgExtMax = 0,
2423 imgstartOffset = 0, tmp = 0;
2425 int textEncodingType = 0;
2427 char **charset_array = NULL;
2429 make_characterset_array(&charset_array);
2431 init_content_info(pInfo);
2433 taglen = pInfo->tagV2Info.tagLen;
2434 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2435 curPos = MP3_TAGv2_HEADER_LEN;
2437 debug_msg(RELEASE, "ID3tag v222--------------------------------------------------------------\n");
2439 if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
2441 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
2442 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2443 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
2446 memcpy(CompTmp, &buffer[curPos], 3);
2449 oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
2450 oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
2451 | (unsigned long)buffer[5 + curPos];
2452 if (oneFrameLen > taglen - curPos)
2454 purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
2455 curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
2457 if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2458 curPos += purelyFramelen;
2460 if (buffer[curPos - purelyFramelen] == 0x00) {
2462 textEncodingType = AV_ID3V2_ISO_8859;
2463 } else if (buffer[curPos - purelyFramelen] == 0x01) {
2465 textEncodingType = AV_ID3V2_UTF16;
2468 /*in order to deliver valid string to MP */
2469 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2472 if (encodingOffSet < purelyFramelen) {
2473 realCpyFrameNum = purelyFramelen - encodingOffSet;
2474 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2476 if (pExtContent == NULL) {
2477 debug_error(DEBUG, "out of memory for pExtContent\n");
2481 memset(pExtContent, '\0', realCpyFrameNum + 3);
2483 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2485 if (realCpyFrameNum > 0) {
2486 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2487 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2488 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2489 pInfo->tagV2Info.bTitleMarked = true;
2490 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2491 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2492 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2493 pInfo->tagV2Info.bArtistMarked = true;
2494 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2495 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2496 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2497 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2498 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2499 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2500 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2501 pInfo->tagV2Info.bConductorMarked = true;
2502 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2503 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2504 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2505 pInfo->tagV2Info.bAlbumMarked = true;
2506 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2507 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2508 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2509 pInfo->tagV2Info.bYearMarked = true;
2510 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2511 /*skip language data! */
2512 if (realCpyFrameNum > 4) {
2513 realCpyFrameNum -= 4;
2516 /*pExtContent[tmp+1] value should't have encoding value */
2517 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
2518 if (pExtContent[tmp - 1] == 0x00)
2519 textEncodingType = AV_ID3V2_ISO_8859;
2521 textEncodingType = AV_ID3V2_UTF16;
2523 pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2524 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2525 pInfo->tagV2Info.bDescriptionMarked = true;
2527 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2530 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2534 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2535 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2536 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2538 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2542 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2545 ret = safe_atoi(pInfo->pGenre, &int_genre);
2547 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
2549 /*Change int to string */
2550 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2551 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2552 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
2553 int tmp_genre_len = 0;
2555 memset(tmp_genre, 0, 6);
2556 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2558 tmp_genre_len = strlen(tmp_genre);
2559 if (tmp_genre_len > 0) {
2560 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2561 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2562 if (pInfo->pGenre) {
2563 SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
2568 debug_error(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
2573 pInfo->tagV2Info.bGenreMarked = true;
2574 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2575 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2576 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2577 pInfo->tagV2Info.bTrackNumMarked = true;
2578 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2579 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2580 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2581 pInfo->tagV2Info.bEncByMarked = true;
2582 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2583 if (realCpyFrameNum > 4) {
2584 /*skip language data! */
2585 realCpyFrameNum -= 4;
2588 /*pExtContent[tmp+1] value should't have null value */
2589 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
2590 if (pExtContent[tmp - 1] == 0x00)
2591 textEncodingType = AV_ID3V2_ISO_8859;
2593 textEncodingType = AV_ID3V2_UTF16;
2595 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2596 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2597 pInfo->tagV2Info.bURLMarked = true;
2599 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2602 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2605 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2606 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2607 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2608 pInfo->tagV2Info.bCopyRightMarked = true;
2609 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2610 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2611 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2612 pInfo->tagV2Info.bOriginArtistMarked = true;
2613 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2614 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2615 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2616 pInfo->tagV2Info.bComposerMarked = true;
2617 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2618 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2619 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2620 pInfo->tagV2Info.bRecDateMarked = true;
2621 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2622 if (pExtContent[0] != 0) {
2623 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
2624 pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
2626 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
2627 pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
2631 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
2634 imgstartOffset += checkImgExtMax;
2636 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2637 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2639 imgstartOffset++;/*PictureType(1byte) */
2641 if (pExtContent[imgstartOffset] != 0x0) {
2644 int new_dis_len = 0;
2645 char *tmp_desc = NULL;
2648 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2649 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2650 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2653 /*check end of image description*/
2654 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2655 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2656 debug_msg(RELEASE, "length of description (%d)", cur_pos);
2663 dis_len = cur_pos + 1;
2665 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2667 if (tmp_desc != NULL) {
2668 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2670 /*convert description*/
2671 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2672 mmfile_free(tmp_desc);
2673 debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2674 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2677 imgstartOffset += cur_pos;
2679 pInfo->imageInfo.imgDesLen = 0;
2682 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2683 imgstartOffset++; /* endofDesceriptionType(1byte) */
2685 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2689 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2691 if (realCpyFrameNum - imgstartOffset > 0) {
2692 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2693 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2695 if (pInfo->imageInfo.pImageBuf != NULL) {
2696 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2697 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2700 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2701 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2703 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2707 /*checkImgMimeTypeMax = 0;*/
2711 pInfo->tagV2Info.bImageMarked = true;
2718 curPos += purelyFramelen;
2719 if (purelyFramelen != 0)
2720 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2723 if (pExtContent) _FREE_EX(pExtContent);
2724 memset(CompTmp, 0, 4);
2725 if (curPos < taglen) {
2726 needToloopv2taglen -= oneFrameLen;
2729 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2732 realCpyFrameNum = 0;
2733 textEncodingType = 0;
2739 release_characterset_array(charset_array);
2749 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2751 unsigned long taglen = 0;
2752 unsigned long needToloopv2taglen;
2753 unsigned long oneFrameLen = 0;
2754 unsigned long v2numOfFrames = 0;
2755 unsigned long curPos = 0;
2757 unsigned char *pExtContent = NULL;
2758 unsigned long purelyFramelen = 0;
2759 unsigned int encodingOffSet = 0;
2760 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2761 unsigned int textEncodingType = 0;
2762 char **charset_array = NULL;
2763 const char *MIME_PRFIX = "image/";
2765 make_characterset_array(&charset_array);
2767 init_content_info(pInfo);
2769 taglen = pInfo->tagV2Info.tagLen;
2770 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2771 curPos = MP3_TAGv2_HEADER_LEN;
2773 debug_msg(RELEASE, "ID3tag v223--------------------------------------------------------------\n");
2775 /* check Extended Header */
2776 if (buffer[5] & 0x40) {
2777 /* if extended header exists, skip it*/
2778 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2780 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2782 if (extendedHeaderLen > (int)(taglen - curPos)) {
2783 debug_error(DEBUG, "extended header too long.\n");
2785 curPos += extendedHeaderLen;
2790 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2792 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2793 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2794 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2797 memcpy(CompTmp, &buffer[curPos], 4);
2800 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2801 oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2802 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2804 debug_msg(RELEASE, "----------------------------------------------------------------------------------------------------\n");
2806 if (oneFrameLen > taglen - curPos)
2809 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2810 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2812 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2813 curPos += purelyFramelen;
2815 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2817 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2818 textEncodingType = AV_ID3V2_UTF16;
2819 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2821 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2822 textEncodingType = AV_ID3V2_UTF16_BE;
2823 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2825 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2826 textEncodingType = AV_ID3V2_UTF16;
2827 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2829 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2830 textEncodingType = AV_ID3V2_UTF16_BE;
2832 if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2833 debug_msg(RELEASE, "encodingOffset will be set to 1\n");
2836 debug_msg(RELEASE, "Finding encodingOffset\n");
2838 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2841 textEncodingType = AV_ID3V2_ISO_8859;
2842 debug_msg(RELEASE, "this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2845 if (pExtContent) _FREE_EX(pExtContent);
2847 if (encodingOffSet < purelyFramelen) {
2848 realCpyFrameNum = purelyFramelen - encodingOffSet;
2849 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2851 if (pExtContent == NULL) {
2852 debug_msg(DEBUG, "pExtContent malloc failed\n");
2856 memset(pExtContent, '\0', realCpyFrameNum + 3);
2858 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2859 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2860 debug_msg(RELEASE, "get the new text ecoding type\n");
2861 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2865 if (textEncodingType > AV_ID3V2_MAX) {
2866 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2870 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2871 if (realCpyFrameNum > 0) {
2872 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2873 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2874 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2875 pInfo->tagV2Info.bTitleMarked = true;
2877 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2878 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2879 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2880 pInfo->tagV2Info.bArtistMarked = true;
2881 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2882 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2883 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2884 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2885 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2886 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2887 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2888 pInfo->tagV2Info.bConductorMarked = true;
2889 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2890 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2891 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2892 pInfo->tagV2Info.bAlbumMarked = true;
2893 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2894 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2895 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2896 pInfo->tagV2Info.bYearMarked = true;
2897 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2898 if (realCpyFrameNum > 3) {
2899 realCpyFrameNum -= 3;
2902 /*pExtContent[tmp+1] value should't have encoding value */
2903 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2904 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2905 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2906 realCpyFrameNum -= 4;
2910 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2911 realCpyFrameNum -= 2;
2913 textEncodingType = AV_ID3V2_UTF16;
2914 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2915 realCpyFrameNum -= 2;
2917 textEncodingType = AV_ID3V2_UTF16_BE;
2918 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2919 realCpyFrameNum -= 3;
2921 textEncodingType = AV_ID3V2_UTF16;
2922 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2923 realCpyFrameNum -= 3;
2925 textEncodingType = AV_ID3V2_UTF16_BE;
2927 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
2930 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2934 textEncodingType = AV_ID3V2_ISO_8859;
2937 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2938 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2940 debug_msg(RELEASE, "failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2941 pInfo->commentLen = 0;
2944 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2945 pInfo->commentLen = 0;
2949 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2950 pInfo->tagV2Info.bDescriptionMarked = true;
2951 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2954 int copy_start_pos = tmp;
2955 AvSynclyricsInfo *synclyrics_info = NULL;
2956 GList *synclyrics_info_list = NULL;
2958 if (realCpyFrameNum > 5) {
2959 realCpyFrameNum -= 5;
2962 /*pExtContent[tmp+1] value should't have encoding value */
2963 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2964 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2965 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2966 realCpyFrameNum -= 4;
2970 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2971 realCpyFrameNum -= 2;
2973 textEncodingType = AV_ID3V2_UTF16;
2974 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2975 realCpyFrameNum -= 2;
2977 textEncodingType = AV_ID3V2_UTF16_BE;
2978 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2979 realCpyFrameNum -= 3;
2981 textEncodingType = AV_ID3V2_UTF16;
2982 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2983 realCpyFrameNum -= 3;
2985 textEncodingType = AV_ID3V2_UTF16_BE;
2987 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
2990 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2994 textEncodingType = AV_ID3V2_ISO_8859;
2997 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2999 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3000 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3001 pInfo->syncLyricsNum = 0;
3003 if (textEncodingType == AV_ID3V2_UTF16) {
3004 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3005 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3006 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3008 for (idx = 0; idx < realCpyFrameNum; idx++) {
3009 if (pExtContent[tmp + idx] == 0x00) {
3010 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3012 if (synclyrics_info != NULL) {
3013 if (textEncodingType == AV_ID3V2_UTF8) {
3014 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3015 if (synclyrics_info->lyric_info != NULL) {
3016 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3017 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3018 synclyrics_info->lyric_info[copy_len] = '\0';
3021 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[AV_ID3V2_ISO_8859], NULL, NULL);
3024 synclyrics_info->time_info = (unsigned long)pExtContent[tmp + idx + 1] << 24 | (unsigned long)pExtContent[tmp + idx + 2] << 16 | (unsigned long)pExtContent[tmp + idx + 3] << 8 | (unsigned long)pExtContent[tmp + idx + 4];
3026 copy_start_pos = tmp + idx + 1;
3027 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);
3029 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3034 pInfo->pSyncLyrics = synclyrics_info_list;
3035 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3039 debug_msg(RELEASE, "failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3040 pInfo->syncLyricsNum = 0;
3043 debug_msg(RELEASE, "Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3044 pInfo->syncLyricsNum = 0;
3048 //debug_msg(RELEASE, "pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
3049 debug_msg(RELEASE, "pInfo->syncLyricsNum(%d)\n", pInfo->syncLyricsNum);
3050 pInfo->tagV2Info.bSyncLyricsMarked = true;
3051 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3052 char *lang_info = strndup((char *)pExtContent, 3);
3054 if (realCpyFrameNum > 3) {
3055 realCpyFrameNum -= 3;
3058 /*find start of lyrics */
3060 if (pExtContent[tmp] == 0x00) {
3061 if (pExtContent[tmp + 1] == 0x00) {
3062 realCpyFrameNum -= 2;
3072 /*pExtContent[tmp+1] value should't have encoding value */
3073 debug_msg(RELEASE, "tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
3075 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
3076 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3077 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3078 realCpyFrameNum -= 4;
3082 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3083 realCpyFrameNum -= 2;
3085 textEncodingType = AV_ID3V2_UTF16;
3086 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3087 realCpyFrameNum -= 2;
3089 textEncodingType = AV_ID3V2_UTF16_BE;
3090 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
3091 realCpyFrameNum -= 3;
3093 textEncodingType = AV_ID3V2_UTF16;
3094 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
3095 realCpyFrameNum -= 3;
3097 textEncodingType = AV_ID3V2_UTF16_BE;
3099 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3102 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3106 textEncodingType = AV_ID3V2_ISO_8859;
3109 char *char_set = NULL;
3111 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3113 if (textEncodingType == AV_ID3V2_ISO_8859) {
3114 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
3115 char_set = strdup("EUC-KR");
3117 char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
3119 _FREE_EX(lang_info);
3122 if (char_set == NULL) {
3123 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3125 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3129 debug_msg(RELEASE, "failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3130 pInfo->unsynclyricsLen = 0;
3133 debug_msg(RELEASE, "Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3134 pInfo->unsynclyricsLen = 0;
3138 debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3139 pInfo->tagV2Info.bUnsyncLyricsMarked = true;
3140 mmfile_free(lang_info);
3141 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3142 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3143 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3145 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3149 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3152 ret = safe_atoi(pInfo->pGenre, &int_genre);
3154 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
3156 /*Change int to string */
3157 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3158 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3159 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3160 int tmp_genre_len = 0;
3162 memset(tmp_genre, 0, 6);
3163 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3165 tmp_genre_len = strlen(tmp_genre);
3166 if (tmp_genre_len > 0) {
3167 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3168 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3169 if (pInfo->pGenre) {
3170 SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
3175 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
3180 pInfo->tagV2Info.bGenreMarked = true;
3181 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3182 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3183 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3184 pInfo->tagV2Info.bTrackNumMarked = true;
3185 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3186 pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3187 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3188 pInfo->tagV2Info.bEncByMarked = true;
3189 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3190 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3191 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3192 pInfo->tagV2Info.bURLMarked = true;
3193 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3194 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3195 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3196 pInfo->tagV2Info.bCopyRightMarked = true;
3197 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3198 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3199 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3200 pInfo->tagV2Info.bOriginArtistMarked = true;
3201 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3202 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3203 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3204 pInfo->tagV2Info.bComposerMarked = true;
3205 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
3206 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3207 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3208 pInfo->tagV2Info.bRecDateMarked = true;
3209 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3210 debug_msg(DEBUG, "text encoding %d \n", textEncodingType);
3212 if (pExtContent[0] != '\0') {
3213 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3214 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3216 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3217 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3218 checkImgMimeTypeMax++;
3220 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3222 pInfo->imageInfo.imgMimetypeLen = 0;
3223 debug_msg(RELEASE, "APIC image's not included to MIME type\n");
3226 imgstartOffset += checkImgMimeTypeMax;
3228 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3229 pInfo->imageInfo.imgMimetypeLen = 0;
3230 debug_error(DEBUG, "APIC NOT VALID");
3234 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3235 imgstartOffset++;/*endofMIME(1byte) */
3236 debug_msg(RELEASE, "after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
3238 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3239 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3241 debug_msg(RELEASE, "APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
3243 imgstartOffset++;/*PictureType(1byte) */
3244 debug_msg(RELEASE, "after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
3246 if (pExtContent[imgstartOffset] != 0x0) {
3249 int new_dis_len = 0;
3250 char *tmp_desc = NULL;
3253 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3254 if (realCpyFrameNum < imgstartOffset + cur_pos) {
3255 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3258 /*check end of image description*/
3259 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
3260 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
3261 debug_msg(RELEASE, "length of description (%d)", cur_pos);
3268 dis_len = cur_pos + 1;
3270 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3271 if (tmp_desc != NULL) {
3272 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3274 /*convert description*/
3275 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3276 debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3277 mmfile_free(tmp_desc);
3279 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3282 imgstartOffset += cur_pos;
3284 pInfo->imageInfo.imgDesLen = 0;
3285 debug_msg(RELEASE, "APIC image's not included to Description!!!\n");
3288 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3289 imgstartOffset++; /* endofDesceriptionType(1byte) */
3291 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
3295 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3297 if (realCpyFrameNum - imgstartOffset > 0) {
3298 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3299 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3301 if (pInfo->imageInfo.pImageBuf != NULL) {
3302 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3303 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3306 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3307 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3309 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3311 debug_msg(RELEASE, "pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
3313 debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
3314 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
3317 debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
3318 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
3321 checkImgMimeTypeMax = 0;
3324 pInfo->tagV2Info.bImageMarked = true;
3327 debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3332 debug_msg(RELEASE, "All of the pExtContent Values are NULL\n");
3335 curPos += purelyFramelen;
3336 if (purelyFramelen != 0)
3337 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3339 debug_msg(RELEASE, "This Frame's size is Zero! purelyFramelen(%lu)\n", purelyFramelen);
3342 if (pExtContent) _FREE_EX(pExtContent);
3343 memset(CompTmp, 0, 4);
3345 if (curPos < taglen) {
3346 needToloopv2taglen -= oneFrameLen;
3349 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3352 realCpyFrameNum = 0;
3353 textEncodingType = 0;
3359 release_characterset_array(charset_array);
3369 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
3371 unsigned long taglen = 0;
3372 unsigned long needToloopv2taglen;
3373 unsigned long oneFrameLen = 0;
3374 unsigned long v2numOfFrames = 0;
3375 unsigned long curPos = 0;
3377 unsigned char *pExtContent = NULL;
3378 unsigned long purelyFramelen = 0;
3379 unsigned int encodingOffSet = 0;
3380 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
3381 unsigned int textEncodingType = 0;
3382 char **charset_array = NULL;
3383 const char *MIME_PRFIX = "image/";
3385 make_characterset_array(&charset_array);
3387 init_content_info(pInfo);
3389 taglen = pInfo->tagV2Info.tagLen;
3390 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
3391 curPos = MP3_TAGv2_HEADER_LEN;
3393 debug_msg(RELEASE, "ID3tag v224--------------------------------------------------------------\n");
3395 /* check Extended Header */
3396 if (buffer[5] & 0x40) {
3397 /* if extended header exists, skip it*/
3398 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
3400 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
3402 if (extendedHeaderLen > (int)(taglen - curPos)) {
3403 debug_error(DEBUG, "extended header too long.\n");
3405 curPos += extendedHeaderLen;
3409 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
3411 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
3412 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
3413 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
3416 memcpy(CompTmp, &buffer[curPos], 4);
3419 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
3420 oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
3421 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
3422 if (oneFrameLen > taglen - curPos)
3425 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
3426 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
3428 debug_msg(RELEASE, "-----------------------------------------------------------------------------------\n");
3430 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
3431 curPos += purelyFramelen;
3433 /*in case of UTF 16 encoding */
3434 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
3435 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
3437 textEncodingType = AV_ID3V2_UTF16;
3438 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
3440 textEncodingType = AV_ID3V2_UTF16_BE;
3441 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
3443 textEncodingType = AV_ID3V2_UTF16;
3444 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
3446 textEncodingType = AV_ID3V2_UTF16_BE;
3448 /*in case of UTF-16 BE encoding */
3449 if (buffer[curPos - purelyFramelen] == 0x02) {
3451 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
3452 encodingOffSet++;/*null skip! */
3453 textEncodingType = AV_ID3V2_UTF16_BE;
3455 /*in case of UTF8 encoding */
3456 else if (buffer[curPos - purelyFramelen] == 0x03) {
3458 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
3459 encodingOffSet++;/*null skip! */
3460 textEncodingType = AV_ID3V2_UTF8;
3462 /*in case of ISO-8859-1 encoding */
3464 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
3466 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
3467 encodingOffSet++;/*less than 0x20 value skip! */
3468 textEncodingType = AV_ID3V2_ISO_8859;
3472 if (pExtContent) _FREE_EX(pExtContent);
3474 if (encodingOffSet < purelyFramelen) {
3475 realCpyFrameNum = purelyFramelen - encodingOffSet;
3476 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
3478 if (pExtContent == NULL) {
3479 debug_error(DEBUG, "out of memoryu for id3tag parse\n");
3483 memset(pExtContent, '\0', realCpyFrameNum + 3);
3485 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
3486 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
3487 debug_msg(RELEASE, "get the new text ecoding type\n");
3488 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
3492 if (textEncodingType > AV_ID3V2_MAX) {
3493 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
3497 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
3499 if (realCpyFrameNum > 0) {
3500 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
3501 if (textEncodingType == AV_ID3V2_UTF8) {
3502 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3503 if (pInfo->pTitle) {
3504 memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
3505 pInfo->pTitle[realCpyFrameNum] = '\0';
3506 /*string copy with '\0'*/
3507 pInfo->titleLen = realCpyFrameNum;
3508 _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
3511 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
3514 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
3515 pInfo->tagV2Info.bTitleMarked = true;
3517 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
3518 if (textEncodingType == AV_ID3V2_UTF8) {
3519 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3520 if (pInfo->pArtist) {
3521 memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
3522 pInfo->pArtist[realCpyFrameNum] = '\0';
3523 /*string copy with '\0'*/
3524 pInfo->artistLen = realCpyFrameNum;
3525 _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
3528 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
3532 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
3533 pInfo->tagV2Info.bArtistMarked = true;
3534 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
3535 if (textEncodingType == AV_ID3V2_UTF8) {
3536 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3537 if (pInfo->pAlbum_Artist) {
3538 memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
3539 pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
3540 /*string copy with '\0'*/
3541 pInfo->album_artistLen = realCpyFrameNum;
3542 _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
3545 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3548 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3549 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3550 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3551 if (textEncodingType == AV_ID3V2_UTF8) {
3552 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3553 if (pInfo->pConductor) {
3554 memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
3555 pInfo->pConductor[realCpyFrameNum] = '\0';
3556 /*string copy with '\0'*/
3557 pInfo->conductorLen = realCpyFrameNum;
3558 _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
3561 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3564 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3565 pInfo->tagV2Info.bConductorMarked = true;
3566 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3567 if (textEncodingType == AV_ID3V2_UTF8) {
3568 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3569 if (pInfo->pAlbum) {
3570 memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
3571 pInfo->pAlbum[realCpyFrameNum] = '\0';
3572 /*string copy with '\0'*/
3573 pInfo->albumLen = realCpyFrameNum;
3574 _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
3577 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3580 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3581 pInfo->tagV2Info.bAlbumMarked = true;
3582 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) { /*TODO. TYER is replaced by the TDRC. but many files use TYER in v2.4 */
3583 if (textEncodingType == AV_ID3V2_UTF8) {
3584 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3586 memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
3587 pInfo->pYear[realCpyFrameNum] = '\0';
3588 /*string copy with '\0'*/
3589 pInfo->yearLen = realCpyFrameNum;
3590 _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
3593 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3596 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3597 pInfo->tagV2Info.bYearMarked = true;
3598 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3599 if (realCpyFrameNum > 3) {
3600 realCpyFrameNum -= 3;
3603 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3604 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3605 realCpyFrameNum -= 4;
3609 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3610 realCpyFrameNum -= 2;
3612 textEncodingType = AV_ID3V2_UTF16;
3614 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
3616 } else if (textEncodingType == AV_ID3V2_UTF8) {
3617 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3621 textEncodingType = AV_ID3V2_UTF8;
3623 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3627 textEncodingType = AV_ID3V2_ISO_8859;
3630 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3632 if (textEncodingType == AV_ID3V2_UTF8) {
3633 pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3634 if (pInfo->pComment) {
3635 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
3636 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
3637 pInfo->pComment[realCpyFrameNum] = '\0';
3638 /*string copy with '\0'*/
3639 pInfo->commentLen = realCpyFrameNum;
3640 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
3643 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3646 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3651 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3652 pInfo->tagV2Info.bDescriptionMarked = true;
3653 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3656 int copy_start_pos = tmp;
3657 AvSynclyricsInfo *synclyrics_info = NULL;
3658 GList *synclyrics_info_list = NULL;
3660 if (realCpyFrameNum > 5) {
3661 realCpyFrameNum -= 5;
3664 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3665 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3666 realCpyFrameNum -= 4;
3670 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3671 realCpyFrameNum -= 2;
3673 textEncodingType = AV_ID3V2_UTF16;
3675 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
3677 } else if (textEncodingType == AV_ID3V2_UTF8) {
3678 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3682 textEncodingType = AV_ID3V2_UTF8;
3684 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3688 textEncodingType = AV_ID3V2_ISO_8859;
3691 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3693 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3694 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3695 pInfo->syncLyricsNum = 0;
3697 if (textEncodingType == AV_ID3V2_UTF16) {
3698 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3699 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3700 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3702 for (idx = 0; idx < realCpyFrameNum; idx++) {
3703 if (pExtContent[tmp + idx] == 0x00) {
3704 synclyrics_info = (AvSynclyricsInfo *)mmfile_malloc(sizeof(AvSynclyricsInfo));
3705 if (synclyrics_info) {
3706 if (textEncodingType == AV_ID3V2_UTF8) {
3707 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3708 if (synclyrics_info->lyric_info) {
3709 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3710 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3711 synclyrics_info->lyric_info[copy_len] = '\0';
3714 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3717 synclyrics_info->time_info = (unsigned long)pExtContent[tmp + idx + 1] << 24 | (unsigned long)pExtContent[tmp + idx + 2] << 16 | (unsigned long)pExtContent[tmp + idx + 3] << 8 | (unsigned long)pExtContent[tmp + idx + 4];
3719 copy_start_pos = tmp + idx + 1;
3720 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);
3722 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3727 pInfo->pSyncLyrics = synclyrics_info_list;
3728 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3732 debug_msg(RELEASE, "SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3736 pInfo->tagV2Info.bSyncLyricsMarked = true;
3737 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3738 if (realCpyFrameNum > 3) {
3739 realCpyFrameNum -= 3;
3742 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3743 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3744 realCpyFrameNum -= 4;
3748 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3749 realCpyFrameNum -= 2;
3751 textEncodingType = AV_ID3V2_UTF16;
3753 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3755 } else if (textEncodingType == AV_ID3V2_UTF8) {
3756 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3760 textEncodingType = AV_ID3V2_UTF8;
3762 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3766 textEncodingType = AV_ID3V2_ISO_8859;
3769 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3771 if (textEncodingType == AV_ID3V2_UTF8) {
3772 pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3774 if (pInfo->pUnsyncLyrics != NULL) {
3775 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3776 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3777 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3778 /*string copy with '\0'*/
3779 pInfo->unsynclyricsLen = realCpyFrameNum;
3780 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3782 debug_error(DEBUG, "out of memoryu for SyncLyrics\n");
3785 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3788 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3793 debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3794 pInfo->tagV2Info.bDescriptionMarked = true;
3795 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3796 if (textEncodingType == AV_ID3V2_UTF8) {
3797 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3798 if (pInfo->pGenre) {
3799 memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3800 pInfo->pGenre[realCpyFrameNum] = '\0';
3801 /*string copy with '\0'*/
3802 pInfo->genreLen = realCpyFrameNum;
3803 _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3806 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3809 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3811 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3815 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3818 ret = safe_atoi(pInfo->pGenre, &int_genre);
3820 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
3822 /*Change int to string */
3823 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3824 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3825 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3826 int tmp_genre_len = 0;
3828 memset(tmp_genre, 0, 6);
3829 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3831 tmp_genre_len = strlen(tmp_genre);
3832 if (tmp_genre_len > 0) {
3833 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3834 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3835 if (pInfo->pGenre) {
3836 SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
3841 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
3846 pInfo->tagV2Info.bGenreMarked = true;
3847 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3848 if (textEncodingType == AV_ID3V2_UTF8) {
3849 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3850 if (pInfo->pTrackNum != NULL) {
3851 memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3852 pInfo->pTrackNum[realCpyFrameNum] = '\0';
3853 /*string copy with '\0'*/
3854 pInfo->tracknumLen = realCpyFrameNum;
3855 _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3858 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3861 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3862 pInfo->tagV2Info.bTrackNumMarked = true;
3863 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3864 if (textEncodingType == AV_ID3V2_UTF8) {
3865 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3866 if (pInfo->pEncBy != NULL) {
3867 memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3868 pInfo->pEncBy[realCpyFrameNum] = '\0';
3869 /*string copy with '\0'*/
3870 pInfo->encbyLen = realCpyFrameNum;
3871 _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3874 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3877 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3878 pInfo->tagV2Info.bEncByMarked = true;
3879 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3880 if (textEncodingType == AV_ID3V2_UTF8) {
3881 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3882 if (pInfo->pURL != NULL) {
3883 memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3884 pInfo->pURL[realCpyFrameNum] = '\0';
3885 /*string copy with '\0'*/
3886 pInfo->urlLen = realCpyFrameNum;
3887 _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3890 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3893 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3894 pInfo->tagV2Info.bURLMarked = true;
3895 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3896 if (textEncodingType == AV_ID3V2_UTF8) {
3897 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3898 if (pInfo->pCopyright != NULL) {
3899 memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3900 pInfo->pCopyright[realCpyFrameNum] = '\0';
3901 /*string copy with '\0'*/
3902 pInfo->copyrightLen = realCpyFrameNum;
3903 _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3906 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3909 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3910 pInfo->tagV2Info.bCopyRightMarked = true;
3911 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3912 if (textEncodingType == AV_ID3V2_UTF8) {
3913 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3914 if (pInfo->pOriginArtist != NULL) {
3915 memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3916 pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3917 /*string copy with '\0'*/
3918 pInfo->originartistLen = realCpyFrameNum;
3919 _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3922 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3925 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3926 pInfo->tagV2Info.bOriginArtistMarked = true;
3927 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3928 if (textEncodingType == AV_ID3V2_UTF8) {
3929 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3930 if (pInfo->pComposer != NULL) {
3931 memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3932 pInfo->pComposer[realCpyFrameNum] = '\0';
3933 /*string copy with '\0'*/
3934 pInfo->composerLen = realCpyFrameNum;
3935 _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3938 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3941 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3942 pInfo->tagV2Info.bComposerMarked = true;
3943 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) { /*TYER(year) and TRDA are replaced by the TDRC */
3944 if (textEncodingType == AV_ID3V2_UTF8) {
3945 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3946 if (pInfo->pRecDate != NULL) {
3947 memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3948 pInfo->pRecDate[realCpyFrameNum] = '\0';
3949 /*string copy with '\0'*/
3950 pInfo->recdateLen = realCpyFrameNum;
3951 _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3954 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3957 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3958 pInfo->tagV2Info.bRecDateMarked = true;
3959 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3960 if (textEncodingType == AV_ID3V2_UTF8) {
3961 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3962 if (pInfo->pContentGroup != NULL) {
3963 memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3964 pInfo->pContentGroup[realCpyFrameNum] = '\0';
3965 /*string copy with '\0'*/
3966 pInfo->contentGroupLen = realCpyFrameNum;
3967 _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3970 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3973 debug_msg(RELEASE, "pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3974 pInfo->tagV2Info.bContentGroupMarked = true;
3975 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3976 if (pExtContent[0] != '\0') {
3977 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3978 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3980 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3981 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3982 checkImgMimeTypeMax++;
3984 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3986 pInfo->imageInfo.imgMimetypeLen = 0;
3989 imgstartOffset += checkImgMimeTypeMax;
3991 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3992 pInfo->imageInfo.imgMimetypeLen = 0;
3993 debug_error(DEBUG, "APIC NOT VALID");
3997 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3998 imgstartOffset++;/*endofMIME(1byte) */
4000 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
4001 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
4003 imgstartOffset++;/*PictureType(1byte) */
4005 if (pExtContent[imgstartOffset] != 0x0) {
4008 int new_dis_len = 0;
4009 char *tmp_desc = NULL;
4012 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
4013 if (realCpyFrameNum < imgstartOffset + cur_pos) {
4014 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
4017 /*check end of image description*/
4018 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
4019 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
4020 debug_msg(RELEASE, "length of description (%d)", cur_pos);
4027 dis_len = cur_pos + 1;
4029 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
4031 if (tmp_desc != NULL) {
4032 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
4033 debug_msg(DEBUG, "tmp_desc %s\n", tmp_desc);
4035 /*convert description*/
4036 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
4037 debug_msg(DEBUG, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
4038 mmfile_free(tmp_desc);
4040 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
4043 imgstartOffset += cur_pos;
4045 pInfo->imageInfo.imgDesLen = 0;
4048 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
4049 imgstartOffset++; /* endofDesceriptionType(1byte) */
4051 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
4055 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
4057 if (realCpyFrameNum - imgstartOffset > 0) {
4058 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
4059 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
4061 if (pInfo->imageInfo.pImageBuf != NULL) {
4062 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
4063 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
4066 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
4067 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
4069 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
4074 checkImgMimeTypeMax = 0;
4077 pInfo->tagV2Info.bImageMarked = true;
4079 debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
4084 debug_msg(RELEASE, "mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
4088 curPos += purelyFramelen;
4089 if (purelyFramelen != 0)
4090 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
4093 if (pExtContent) _FREE_EX(pExtContent);
4094 memset(CompTmp, 0, 4);
4095 if (curPos < taglen) {
4096 needToloopv2taglen -= oneFrameLen;
4099 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
4103 realCpyFrameNum = 0;
4104 textEncodingType = 0;
4110 release_characterset_array(charset_array);
4120 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
4122 char *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
4123 bool bAdditionGenre = false /*, bMpegAudioFrame = false*/;
4124 int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
4125 unsigned char genre = pInfo->genre;
4127 /* for Genre Info */
4128 if (pInfo->tagV2Info.bGenreMarked == false) {
4129 if (pInfo->bV1tagFound == true) {
4130 debug_msg(RELEASE, "Genre: %d\n", genre);
4135 if (MpegAudio_Genre[genre] != NULL) {
4136 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
4137 if (pInfo->genreLen > 0) {
4138 /* Give space for NULL character. Hence added "+1" */
4139 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4140 if (pInfo->pGenre) {
4141 SAFE_STRLCPY(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen + 1);
4146 debug_msg(RELEASE, "Genre was not Found.\n");
4148 } else if (pInfo->tagV2Info.bGenreMarked == true) {
4149 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
4150 pInfo->pGenre[pInfo->genreLen + 1] = '\0';
4151 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
4153 debug_msg(RELEASE, "pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
4155 if (pInfo->pGenre) {
4156 pInfo->genreLen = strlen(pInfo->pGenre);
4157 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4158 if (mpegAudioGenre != NULL) {
4159 SAFE_STRLCPY(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen + 1);
4162 pInfo->genreLen = 0;
4166 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
4169 if (mpegAudioGenre != NULL) {
4172 * (XXX) XXX is 0 - 148
4174 pInfo->genreLen = strlen(mpegAudioGenre);
4175 if (pInfo->genreLen >= 3 &&
4176 mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
4177 bAdditionGenre = true;
4178 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
4179 if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
4180 bAdditionGenre = false;
4186 if (bAdditionGenre == true) {
4187 idv2IntGenre = atoi(mpegAudioGenre + 1);
4189 if (idv2IntGenre > 147 || idv2IntGenre < 0)
4192 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
4193 pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
4194 if (pInfo->genreLen > 0) {
4195 /* Give space for NULL character. Hence added "+1" */
4196 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4197 if (pInfo->pGenre) {
4198 SAFE_STRLCPY(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen + 1);
4202 debug_msg(RELEASE, "pInfo->pGenre = %s\n", pInfo->pGenre);
4203 } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
4208 /* Give space for NULL character. Hence added "+1" */
4209 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4210 if (pInfo->pGenre) {
4211 SAFE_STRLCPY(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen + 1);
4213 debug_msg(RELEASE, "pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
4215 debug_msg(RELEASE, "Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
4218 debug_msg(RELEASE, "mpegAudioGenre = %s\n", mpegAudioGenre);
4221 _FREE_EX(mpegAudioGenre);
4224 debug_msg(RELEASE, "Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
4229 void mm_file_free_synclyrics_list(GList *synclyrics_list)
4233 AvSynclyricsInfo *synclyrics_info = NULL;
4235 if (synclyrics_list == NULL) {
4239 list_len = g_list_length(synclyrics_list);
4240 for (idx = 0; idx < list_len; idx++) {
4241 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
4243 if (synclyrics_info != NULL) {
4244 mmfile_free(synclyrics_info->lyric_info);
4245 mmfile_free(synclyrics_info);
4249 if (synclyrics_list != NULL) {
4250 g_list_free(synclyrics_list);
4251 synclyrics_list = NULL;