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>
31 #include "mm_file_debug.h"
32 #include "mm_file_utils.h"
34 #define ENABLE_ITUNES_META /*All itunes metadata extracted by ffmpeg. see mov_read_udta_string() but Some cover art not support. */
36 typedef struct _mmfilemp4basicboxheader {
39 long long start_offset; /*huge file*/
40 } MMFILE_MP4_BASIC_BOX_HEADER;
42 typedef struct _mmfilemp4ftpybox {
43 unsigned int major_brand;
44 unsigned short major_version;
45 unsigned short minor_version;
46 unsigned int *compatiable_brands;
50 eMMFILE_3GP_TAG_TITLE = 0x01,
51 eMMFILE_3GP_TAG_CAPTION = 0x02,
52 eMMFILE_3GP_TAG_COPYRIGHT = 0x03,
53 eMMFILE_3GP_TAG_PERFORMER = 0x04,
54 eMMFILE_3GP_TAG_AUTHOR = 0x05,
55 eMMFILE_3GP_TAG_GENRE = 0x06,
56 } eMMFILE_3GP_TEXT_TAG;
58 typedef struct _mmfile3gptagtextbox {
59 unsigned char version;
60 unsigned char flag[3];
61 unsigned char language[2];
63 } MMFILE_3GP_TEXT_TAGBOX;
65 typedef struct _mmfile3gptagyearbox {
66 unsigned char version;
67 unsigned char flag[3];
69 } MMFILE_3GP_YEAR_TAGBOX;
71 typedef struct _mmfile3gptagalbumbox {
72 unsigned char version;
73 unsigned char flag[3];
74 unsigned char language[2];
75 unsigned char *albumtile;
76 unsigned char trackNumber;
77 } MMFILE_3GP_ALBUM_TAGBOX;
79 typedef struct _mmfile3gpratingbox {
80 unsigned char version;
81 unsigned char flag[3];
82 unsigned int ratingEntity;
83 unsigned int ratingCriteria;
84 unsigned char language[2];
85 unsigned char *ratingInfo;
86 } MMFILE_3GP_RATING_TAGBOX;
88 typedef struct _mmfile3gpclsfbox {
89 unsigned char version;
90 unsigned char flag[3];
91 unsigned int classificationEntity;
92 unsigned int classificationTable;
93 unsigned char language[2];
94 unsigned char *classificationInfo;
95 } MMFILE_3GP_CLASSIFICATION_TAGBOX;
97 typedef struct _mmfile3gphdlrbox {
99 unsigned int pre_defined;
100 unsigned int handler_type;
101 unsigned int reserved[3];
102 unsigned char *boxname;
103 } MMFILE_3GP_HANDLER_BOX;
105 typedef struct _mmfileidv2box {
106 unsigned char version;
107 unsigned char flag[3];
108 unsigned char language[2];
109 unsigned char *id3v2Data;
110 } MMFILE_3GP_ID3V2_BOX;
112 typedef struct _mmfilelocibox {
113 unsigned char version;
114 unsigned char flag[3];
115 unsigned char language[2];
121 unsigned char *astronomical_body;
122 unsigned char *additional_notes;
123 } MMFILE_3GP_LOCATION_TAGBOX;
125 typedef struct _mmfilesmtabox {
128 unsigned char saut[4];
130 } MMFILE_M4A_SMTA_TAGBOX;
132 #define MMFILE_MP4_BASIC_BOX_HEADER_LEN 8
133 #define MMFILE_MP4_MOVIE_HEADER_BOX_LEN 96
134 #define MMFILE_MP4_HDLR_BOX_LEN 24
135 #define MMFILE_MP4_STSZ_BOX_LEN 20
136 #define MMFILE_MP4_MP4VBOX_LEN 80
137 #define MMFILE_MP4_MP4ABOX_LEN 28
138 #define MMFILE_3GP_TEXT_TAGBOX_LEN 6
139 #define MMFILE_3GP_YEAR_TAGBOX_LEN 6
140 #define MMFILE_3GP_ALBUM_TAGBOX_LEN 6
141 #define MMFILE_3GP_RATING_TAGBOX_LEN 14
142 #define MMFILE_3GP_CLASS_TAGBOX_LEN 14
143 #define MMFILE_3GP_HANDLER_BOX_LEN 24
144 #define MMFILE_3GP_ID3V2_BOX_LEN 6
145 #define MMFILE_SYNC_LYRIC_INFO_MIN_LEN 5
148 #define FOURCC(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
150 /*#define MIN(a, b) (((a) < (b)) ? (a):(b))*/
152 #define GENRE_COUNT 149
154 static const char *MpegAudio_Genre[GENRE_COUNT] = {"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal",
155 "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial",
156 "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
157 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
158 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
159 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
160 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
161 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
162 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
163 "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic",
164 "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove",
165 "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
166 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore",
167 "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian", "Heavy Metal", "Black Metal", "Crossover",
168 "Contemporary", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "Synthpop", "Unknown"
171 static unsigned char gTagJPEGHeader[] = {0xff, 0xd8, 0xff };
172 static unsigned char gTagPNGHeader[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
174 static int GetJunkCounterLimit(void);
176 static int GetStringFromTextTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header, eMMFILE_3GP_TEXT_TAG eTag)
178 int ret = MMFILE_UTIL_FAIL; /*fail*/
179 MMFILE_3GP_TEXT_TAGBOX texttag = {0, };
182 char *temp_text = NULL;
184 if (!formatContext || !fp || !basic_header) {
185 debug_error(DEBUG, "invalid param\n");
186 return MMFILE_UTIL_FAIL;
189 textBytes = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_TEXT_TAGBOX_LEN;
191 readed = mmfile_read(fp, (unsigned char *)&texttag, MMFILE_3GP_TEXT_TAGBOX_LEN);
192 if (readed != MMFILE_3GP_TEXT_TAGBOX_LEN) {
193 debug_error(DEBUG, "read text tag header fail\n");
194 ret = MMFILE_UTIL_FAIL;
198 if (textBytes <= 1) { /* there exist only 00(null) */
199 debug_error(DEBUG, "Text is NULL\n");
203 texttag.text = mmfile_malloc(textBytes);
205 debug_error(DEBUG, "malloc fail for text box\n");
206 ret = MMFILE_UTIL_FAIL;
210 readed = mmfile_read(fp, (unsigned char *)texttag.text, textBytes);
211 if (readed != textBytes) {
212 debug_error(DEBUG, "read text fail\n");
213 ret = MMFILE_UTIL_FAIL;
218 if ((texttag.text[0] == 0xFE) && (texttag.text[1] == 0xFF)) {
219 /* this char is UTF-16 */
220 unsigned int bytes_written = 0;
221 temp_text = mmfile_string_convert((const char *)&texttag.text[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
223 temp_text = mmfile_strdup((const char *)texttag.text);
227 case eMMFILE_3GP_TAG_TITLE: {
228 if (!formatContext->title) {
229 formatContext->title = temp_text;
233 case eMMFILE_3GP_TAG_CAPTION: {
234 if (!formatContext->description) {
235 formatContext->description = temp_text;
239 case eMMFILE_3GP_TAG_COPYRIGHT: {
240 if (!formatContext->copyright) {
241 formatContext->copyright = temp_text;
245 case eMMFILE_3GP_TAG_PERFORMER: {
246 if (!formatContext->artist) {
247 formatContext->artist = temp_text;
251 case eMMFILE_3GP_TAG_AUTHOR: {
252 if (!formatContext->author) {
253 formatContext->author = temp_text;
257 case eMMFILE_3GP_TAG_GENRE: {
258 if (!formatContext->genre) {
259 formatContext->genre = temp_text;
264 debug_warning(DEBUG, "Not supported Text Tag type[%d]\n", eTag);
269 mmfile_free(texttag.text);
271 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
273 return MMFILE_UTIL_SUCCESS;
276 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
278 mmfile_free(texttag.text);
283 static int GetYearFromYearTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
285 #define MAX_YEAR_BUFFER 10
287 MMFILE_3GP_YEAR_TAGBOX yearbox = {0, };
288 char temp_year[MAX_YEAR_BUFFER] = {0, };
290 if (!formatContext || !fp || !basic_header) {
291 debug_error(DEBUG, "invalid param\n");
292 return MMFILE_UTIL_FAIL;
295 readed = mmfile_read(fp, (unsigned char *)&yearbox, MMFILE_3GP_YEAR_TAGBOX_LEN);
296 if (readed != MMFILE_3GP_YEAR_TAGBOX_LEN) {
297 debug_error(DEBUG, "read yeartag header fail\n");
301 if (!formatContext->year) {
302 yearbox.year = mmfile_io_be_int16(yearbox.year);
303 snprintf(temp_year, MAX_YEAR_BUFFER, "%d", yearbox.year);
304 temp_year[MAX_YEAR_BUFFER - 1] = '\0';
305 formatContext->year = mmfile_strdup((const char *)temp_year);
308 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
309 return MMFILE_UTIL_SUCCESS;
312 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
314 return MMFILE_UTIL_FAIL;
317 static int GetAlbumFromAlbumTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
319 int albumTitleLen = 0;
320 char *temp_text = NULL;
323 MMFILE_3GP_ALBUM_TAGBOX albumbox = {0, };
325 if (!formatContext || !fp || !basic_header) {
326 debug_error(DEBUG, "invalid param\n");
327 return MMFILE_UTIL_FAIL;
330 readed = mmfile_read(fp, (unsigned char *)&albumbox, MMFILE_3GP_ALBUM_TAGBOX_LEN);
331 if (readed != MMFILE_3GP_ALBUM_TAGBOX_LEN) {
332 debug_error(DEBUG, "read albumtag header fail\n");
336 albumTitleLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ALBUM_TAGBOX_LEN - 1; /* 1: track number */
337 if (albumTitleLen > 1) { /* there exist only 00(null) */
338 debug_msg(RELEASE, "albumTitleLen=%d\n", albumTitleLen);
340 albumbox.albumtile = mmfile_malloc(albumTitleLen + 1); /* 1: for null char */
341 if (!albumbox.albumtile) {
342 debug_error(DEBUG, "malloc fail for album title text\n");
346 readed = mmfile_read(fp, (unsigned char *)albumbox.albumtile, albumTitleLen);
347 if (readed != albumTitleLen) {
348 debug_error(DEBUG, "read album title fail\n");
352 if (albumbox.albumtile[albumTitleLen - 1] == '\0') { /* there exist track number */
356 readed = mmfile_read(fp, (unsigned char *)&(albumbox.albumtile[albumTitleLen]), 1);
358 debug_error(DEBUG, "read album title fail\n");
361 albumbox.albumtile[albumTitleLen] = '\0';
365 if ((albumbox.albumtile[0] == 0xFE) && (albumbox.albumtile[1] == 0xFF)) {
366 /* this char is UTF-16 */
367 unsigned int bytes_written = 0;
368 temp_text = mmfile_string_convert((const char *)&albumbox.albumtile[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
370 temp_text = mmfile_strdup((const char *)albumbox.albumtile);
373 if (!formatContext->album) {
374 formatContext->album = temp_text;
377 debug_msg(RELEASE, "formatContext->album=%s, strlen=%d\n", formatContext->album, strlen(formatContext->album));
381 readed = mmfile_read(fp, (unsigned char *)&albumbox.trackNumber, 1);
383 debug_error(DEBUG, "read track number fail\n");
387 if (formatContext->tagTrackNum == 0) {
388 char tracknum[10] = {0, };
389 snprintf(tracknum, 10, "%d", albumbox.trackNumber);
391 formatContext->tagTrackNum = mmfile_strdup((const char *)tracknum);
395 mmfile_free(albumbox.albumtile);
396 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
398 return MMFILE_UTIL_SUCCESS;
401 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
402 mmfile_free(albumbox.albumtile);
404 return MMFILE_UTIL_FAIL;
407 static int GetRatingFromRatingTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
410 int ratinginfoLen = 0;
411 char *temp_text = NULL;
413 MMFILE_3GP_RATING_TAGBOX ratingTag = {0, };
415 if (!formatContext || !fp || !basic_header) {
416 debug_error(DEBUG, "invalid param\n");
417 return MMFILE_UTIL_FAIL;
420 readed = mmfile_read(fp, (unsigned char *)&ratingTag, MMFILE_3GP_RATING_TAGBOX_LEN);
421 if (readed != MMFILE_3GP_RATING_TAGBOX_LEN) {
422 debug_error(DEBUG, "read rating tag header fail\n");
426 ratinginfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_RATING_TAGBOX_LEN;
428 if (ratinginfoLen == 1) {
429 debug_error(DEBUG, "Rating Text is NULL\n");
433 ratingTag.ratingInfo = mmfile_malloc(ratinginfoLen);
434 if (!ratingTag.ratingInfo) {
435 debug_error(DEBUG, "rating info error\n");
439 readed = mmfile_read(fp, (unsigned char *)ratingTag.ratingInfo, ratinginfoLen);
440 if (readed != ratinginfoLen) {
441 debug_error(DEBUG, "read rating info string fail\n");
446 if ((ratingTag.ratingInfo[0] == 0xFE) && (ratingTag.ratingInfo[1] == 0xFF)) {
447 /* this char is UTF-16 */
448 unsigned int bytes_written = 0;
449 temp_text = mmfile_string_convert((const char *)&ratingTag.ratingInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
451 temp_text = mmfile_strdup((const char *)ratingTag.ratingInfo);
454 if (!formatContext->rating) {
455 formatContext->rating = temp_text;
457 mmfile_free(temp_text);
460 mmfile_free(ratingTag.ratingInfo);
461 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
463 return MMFILE_UTIL_SUCCESS;
466 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
467 mmfile_free(ratingTag.ratingInfo);
469 return MMFILE_UTIL_FAIL;
473 static int GetClassficationFromClsfTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
475 int classinfoLen = 0;
477 char *temp_text = NULL;
478 MMFILE_3GP_CLASSIFICATION_TAGBOX classTag = {0, };
480 if (!formatContext || !fp || !basic_header) {
481 debug_error(DEBUG, "invalid param\n");
482 return MMFILE_UTIL_FAIL;
485 readed = mmfile_read(fp, (unsigned char *)&classTag, MMFILE_3GP_CLASS_TAGBOX_LEN);
486 if (readed != MMFILE_3GP_CLASS_TAGBOX_LEN) {
487 debug_error(DEBUG, "read classification tag header fail\n");
492 classinfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_CLASS_TAGBOX_LEN;
493 if (classinfoLen == 1) {
494 debug_error(DEBUG, "Classification Text is NULL\n");
498 classTag.classificationInfo = mmfile_malloc(classinfoLen);
499 if (!classTag.classificationInfo) {
500 debug_error(DEBUG, "class info error\n");
504 readed = mmfile_read(fp, (unsigned char *)classTag.classificationInfo, classinfoLen);
505 if (readed != classinfoLen) {
506 debug_error(DEBUG, "read class info string fail\n");
511 if ((classTag.classificationInfo[0] == 0xFE) && (classTag.classificationInfo[1] == 0xFF)) {
512 /* this char is UTF-16 */
513 unsigned int bytes_written = 0;
514 temp_text = mmfile_string_convert((const char *)&classTag.classificationInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
516 temp_text = mmfile_strdup((const char *)classTag.classificationInfo);
519 if (!formatContext->classification) {
520 formatContext->classification = temp_text;
522 mmfile_free(temp_text);
525 mmfile_free(classTag.classificationInfo);
526 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
528 return MMFILE_UTIL_SUCCESS;
531 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
532 mmfile_free(classTag.classificationInfo);
534 return MMFILE_UTIL_FAIL;
538 * The Location Information box
539 * --------------------+-------------------+-----------------------------------+------
540 * Field Type Details Value
541 * --------------------+-------------------+-----------------------------------+------
542 * BoxHeader.Size Unsigned int(32)
543 * BoxHeader.Type Unsigned int(32) 'loci'
544 * BoxHeader.Version Unsigned int(8) 0
545 * BoxHeader.Flags Bit(24) 0
547 * Language Unsigned int(5)[3] Packed ISO-639-2/T language code
548 * Name String Text of place name
549 * Role Unsigned int(8) Non-negative value indicating role
551 * Longitude Unsigned int(32) Fixed-point value of the longitude
552 * Latitude Unsigned int(32) Fixed-point value of the latitude
553 * Altitude Unsigned int(32) Fixed-point value of the Altitude
554 * Astronomical_body String Text of astronomical body
555 * Additional_notes String Text of additional location-related
557 * --------------------+-------------------+-----------------------------------+------
559 static int _get_char_position(unsigned char *src, char ch, int max)
562 for (i = 0; i < max; i++) {
563 if (*(src + i) == ch)
570 static int GetLocationFromLociTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
573 MMFILE_3GP_LOCATION_TAGBOX lociTag = {0, };
576 unsigned char *buffer = NULL;
577 unsigned char *p = NULL;
579 unsigned int bytes_written = 0;
580 unsigned int name_sz = 0;
581 unsigned int astro_sz = 0;
583 int ilong, ilati, ialti;
584 float flong, flati, falti;
587 if (!formatContext || !fp || !basic_header) {
588 debug_error(DEBUG, "invalid param\n");
589 return MMFILE_UTIL_FAIL;
592 readed = mmfile_read(fp, (unsigned char *)&lociTag, 6); /*6 = version + flag + pad + language */
594 debug_error(DEBUG, "read location tag header fail\n");
598 /*buffer len = name + role + ... + additional notes length */
599 bufferLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - 6;
601 debug_error(DEBUG, "too small buffer\n");
605 buffer = mmfile_malloc(bufferLen);
607 debug_error(DEBUG, "buffer malloc error\n");
611 readed = mmfile_read(fp, (unsigned char *)buffer, bufferLen);
612 if (readed != bufferLen) {
613 debug_error(DEBUG, "read location tag fail\n");
619 pos = _get_char_position(p, '\0', readed - (1 + 4 + 4 + 4 + 2));
621 if (p[0] == 0xFE && p[1] == 0xFF) {
622 lociTag.name = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
624 lociTag.name = (unsigned char *)mmfile_strdup((const char *)p);
636 debug_msg(RELEASE, "long: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 0), *(p + 1), *(p + 2), *(p + 3));
637 debug_msg(RELEASE, "lati: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 4), *(p + 5), *(p + 6), *(p + 7));
638 debug_msg(RELEASE, "alti: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 8), *(p + 9), *(p + 10), *(p + 11));
640 ilong = mmfile_io_be_uint32(*(unsigned int *)p);
641 ilati = mmfile_io_be_uint32(*(unsigned int *)(p + 4));
642 ialti = mmfile_io_be_uint32(*(unsigned int *)(p + 8));
644 flong = (float)ilong / (1 << 16);
645 flati = (float)ilati / (1 << 16);
646 falti = (float)ialti / (1 << 16);
649 lociTag.longitude = flong;
651 lociTag.latitude = flati;
653 lociTag.altitude = falti;
657 /*astronomical body*/
658 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + 1));
660 if (p[0] == 0xFE && p[1] == 0xFF) {
661 lociTag.astronomical_body = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
663 lociTag.astronomical_body = (unsigned char *)mmfile_strdup((const char *)p);
672 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + astro_sz));
674 if (p[0] == 0xFE && p[1] == 0xFF) {
675 lociTag.additional_notes = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
677 lociTag.additional_notes = (unsigned char *)mmfile_strdup((const char *)p);
683 debug_msg(RELEASE, "** Location Information **\n");
684 debug_msg(RELEASE, "Name : %s\n", lociTag.name);
685 debug_msg(RELEASE, "Role : %d (0: shooting, 1: real, 2: fictional, other: reserved)\n", lociTag.role);
686 debug_msg(RELEASE, "Longitude : %16.16f\n", lociTag.longitude);
687 debug_msg(RELEASE, "Latitude : %16.16f\n", lociTag.latitude);
688 debug_msg(RELEASE, "Altitude : %16.16f\n", lociTag.altitude);
689 debug_msg(RELEASE, "Astronomical body: %s\n", lociTag.astronomical_body);
690 debug_msg(RELEASE, "Additional notes : %s\n", lociTag.additional_notes);
692 formatContext->longitude = lociTag.longitude;
693 formatContext->latitude = lociTag.latitude;
694 formatContext->altitude = lociTag.altitude;
697 mmfile_free(lociTag.name);
698 mmfile_free(lociTag.astronomical_body);
699 mmfile_free(lociTag.additional_notes);
701 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
702 return MMFILE_UTIL_SUCCESS;
705 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
707 mmfile_free(lociTag.name);
708 mmfile_free(lociTag.astronomical_body);
709 mmfile_free(lociTag.additional_notes);
711 return MMFILE_UTIL_FAIL;
714 static int GetSAUTInfoFromSMTATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
716 MMFILE_M4A_SMTA_TAGBOX smtaTag = {0, };
719 if (!formatContext || !fp || !basic_header) {
720 debug_error(DEBUG, "invalid param\n");
721 return MMFILE_UTIL_FAIL;
724 readed = mmfile_read(fp, (unsigned char *)&smtaTag, sizeof(MMFILE_M4A_SMTA_TAGBOX));
725 if (readed != sizeof(MMFILE_M4A_SMTA_TAGBOX)) {
726 debug_error(DEBUG, "read smta tag header fail\n");
730 smtaTag.length = mmfile_io_be_uint32(smtaTag.length);
731 smtaTag.value = mmfile_io_be_uint32(smtaTag.value);
733 debug_msg(RELEASE, "Len : 0x%x", smtaTag.length);
734 debug_msg(RELEASE, "Saut : 0x%x 0x%x 0x%x 0x%x", smtaTag.saut[0], smtaTag.saut[1], smtaTag.saut[2], smtaTag.saut[3]);
735 debug_msg(RELEASE, "Value : 0x%x", smtaTag.value);
737 if (smtaTag.saut[0] == 's'
738 && smtaTag.saut[1] == 'a'
739 && smtaTag.saut[2] == 'u'
740 && smtaTag.saut[3] == 't') {
741 if (smtaTag.value == 0x01) {
742 debug_msg(RELEASE, "This has saut tag and valid value");
743 formatContext->smta = 1;
745 debug_error(DEBUG, "This has saut tag and but invalid value");
749 debug_error(DEBUG, "This hasn't saut tag and valid value");
753 return MMFILE_UTIL_SUCCESS;
756 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
758 return MMFILE_UTIL_FAIL;
761 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
763 unsigned int value = 0;
766 if (!formatContext || !fp || !basic_header) {
767 debug_error(DEBUG, "invalid param\n");
768 return MMFILE_UTIL_FAIL;
771 readed = mmfile_read(fp, (unsigned char *)&value, sizeof(unsigned int));
772 if (readed != sizeof(unsigned int)) {
773 debug_error(DEBUG, "read cdis tag header fail\n");
777 value = mmfile_io_be_uint32(value);
779 debug_msg(RELEASE, "Value : 0x%x", value);
782 debug_msg(RELEASE, "This has cdis tag and valid value");
783 formatContext->cdis = 1;
785 debug_error(DEBUG, "This has cdis tag and but invalid value");
789 return MMFILE_UTIL_SUCCESS;
792 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
794 return MMFILE_UTIL_FAIL;
797 static int GetTagFromMetaBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
800 MMFILE_MP4_BASIC_BOX_HEADER hdlrBoxHeader = {0, };
801 MMFILE_MP4_BASIC_BOX_HEADER id3v2BoxHeader = {0, };
802 MMFILE_3GP_ID3V2_BOX id3v2Box = {0, };
803 AvFileContentInfo tagInfo = {0, };
804 unsigned char tagVersion = 0;
805 bool versionCheck = false;
807 unsigned int meta_version = 0;
808 MMFILE_3GP_HANDLER_BOX hdlrBox = {0, };
809 unsigned int encSize = 0;
811 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
816 readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
818 debug_error(DEBUG, "read meta box version\n");
823 readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
824 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
825 debug_error(DEBUG, "read hdlr box header\n");
829 if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
830 debug_warning(DEBUG, "meta type is not hdlr\n");
834 hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
835 hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
837 readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
838 if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
839 debug_error(DEBUG, "read hdlr box\n");
843 hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
846 * check tag type (ID3v2 or iTunes)
848 if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
849 debug_msg(RELEASE, "ID3v2 tag detected.\n");
852 #ifdef ENABLE_ITUNES_META
855 } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
856 mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
858 debug_msg(RELEASE, "Apple iTunes tag detected by mdir.\n");
860 #ifdef ENABLE_ITUNES_META
864 debug_warning(DEBUG, "unknown meta type. 4CC:[%c%c%c%c]\n", ((char *)&hdlrBox.handler_type)[0],
865 ((char *)&hdlrBox.handler_type)[1],
866 ((char *)&hdlrBox.handler_type)[2],
867 ((char *)&hdlrBox.handler_type)[3]);
871 #ifdef ENABLE_ITUNES_META
872 if (!id3_meta && !iTunes_meta) {
874 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
875 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
876 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
878 const char *ilst_box = "ilst";
879 int buf_size = strlen(ilst_box);
881 unsigned char read_buf[buf_size + 1];
882 memset(read_buf, 0x00, buf_size + 1);
885 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR); /*+4 is hdlr size field */
887 readed = mmfile_read(fp, read_buf, buf_size); /* to find 'ilst' */
888 if (readed != buf_size) {
889 debug_error(DEBUG, "read fail [%d]\n", readed);
893 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
894 debug_msg(RELEASE, "Apple iTunes tag detected by ilst.\n");
900 #ifdef ENABLE_ITUNES_META
903 * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
911 #define _ITUNES_READ_BUF_SZ 20
912 #define _ITUNES_TRACK_NUM_SZ 4
913 #define _ITUNES_GENRE_NUM_SZ 4
914 #define _ITUNES_COVER_TYPE_JPEG 13
915 #define _ITUNES_COVER_TYPE_PNG 14
917 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
919 int cover_sz = 0, cover_type = 0, cover_found = 0;
920 /* int track_found = 0; */ /* , track_num = 0; */
921 /* int genre_found = 0; */ /* , genre_index = 0; */
922 /* int artist_found = 0; */ /* , artist_sz = 0; */
923 int limit = basic_header->size - hdlrBoxHeader.size;
924 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
926 /* 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++) { */
927 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
928 readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
929 if (readed != _ITUNES_READ_BUF_SZ)
932 /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
933 but ffmpeg does not support strange cover image.
934 only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
937 * Artist : Added 2010.10.28
939 if (artist_found == 0 &&
940 read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
941 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
944 artist_offset = mmfile_tell(fp);
945 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
947 debug_msg(RELEASE, "----------------------------------- artist found, offset=[%lld], size=[%d]\n", artist_offset, artist_sz);
953 if (track_found == 0 &&
954 read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
955 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
958 track_offset = mmfile_tell(fp);
960 debug_msg(RELEASE, "----------------------------------- Track found, offset=[%lld]\n", track_offset);
964 * Genre : Added 2010.10.27
966 /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
967 if (genre_found == 0 &&
968 read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
969 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
972 genre_offset = mmfile_tell(fp);
974 debug_msg(RELEASE, "----------------------------------- genre found, offset=[%lld]\n", genre_offset);
982 if (cover_found == 0 &&
983 read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
984 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
987 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
988 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
990 cover_offset = mmfile_tell(fp);
992 debug_msg(RELEASE, "----------------------------------- cover_found found, offset=[%lld]\n", cover_offset);
995 mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR); /*FIXME: poor search*/
998 /*ffmpeg extract artist, tracknum, excep cover image. see mov_read_udta_string()*/
1001 if (artist_sz > 0) {
1002 mmfile_seek(fp, artist_offset, SEEK_SET);
1004 if (formatContext->artist) {
1005 debug_msg(RELEASE, "----------------------------------- previous artist was [%s] \n", formatContext->artist);
1006 free(formatContext->artist);
1009 debug_msg(RELEASE, "----------------------------------- new artist will be allocated with size (len+1) [%d] \n", artist_sz + 1);
1010 formatContext->artist = mmfile_malloc(artist_sz + 1);
1012 if (formatContext->artist) {
1013 readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1014 formatContext->artist[artist_sz] = '\0';
1016 debug_msg(RELEASE, "----------------------------------- new artist is [%s] \n", formatContext->artist);
1018 if (readed != artist_sz) {
1019 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, artist_sz);
1020 mmfile_free(formatContext->artist);
1027 mmfile_seek(fp, track_offset, SEEK_SET);
1028 readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1029 if (readed != _ITUNES_TRACK_NUM_SZ) {
1030 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, _ITUNES_TRACK_NUM_SZ);
1032 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1033 if (!formatContext->tagTrackNum) {
1034 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1035 snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1036 formatContext->tagTrackNum = mmfile_strdup((const char *)read_buf);
1042 mmfile_seek(fp, genre_offset, SEEK_SET);
1043 readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1044 if (readed != _ITUNES_GENRE_NUM_SZ) {
1045 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, _ITUNES_GENRE_NUM_SZ);
1047 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1048 debug_msg(RELEASE, "genre index=[%d] \n", genre_index);
1050 if (genre_index > 0 && genre_index < GENRE_COUNT) {
1051 if (!formatContext->genre) {
1052 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1053 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1054 debug_msg(RELEASE, "genre string=[%s] \n", read_buf);
1055 formatContext->genre = mmfile_strdup((const char *)read_buf);
1063 1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1064 Music Cover Art Image Profile
1065 - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1066 - RGB (screen standard)
1067 - Minimum size of 600 x 600 pixels
1068 - Images must be at least 72 dpi
1070 2)I found below info from google.
1071 cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1073 3)So, FIXME when cover image format is tif!
1077 mmfile_seek(fp, cover_offset, SEEK_SET);
1079 formatContext->artwork = mmfile_malloc(cover_sz);
1080 formatContext->artworkSize = cover_sz;
1081 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1082 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1083 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1084 formatContext->artworkMime = mmfile_strdup("image/png");
1085 /*} else if(cover_type == _ITUNES_COVER_TYPE_TIF) {
1086 formatContext->artworkMime = mmfile_strdup("image/tif");*/
1088 debug_warning(DEBUG, "Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1089 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1092 if (formatContext->artwork) {
1093 readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1094 if (readed != cover_sz) {
1095 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, cover_sz);
1096 mmfile_free(formatContext->artwork);
1097 formatContext->artworkSize = 0;
1098 mmfile_free(formatContext->artworkMime);
1104 /*reset seek position*/
1105 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1107 return MMFILE_UTIL_SUCCESS;
1115 /* skip hdlr box name */
1116 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1119 readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1120 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1121 debug_error(DEBUG, "read id3v2 box header\n");
1125 id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1126 id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1128 if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1129 debug_warning(DEBUG, "meta type is not id3v2\n");
1133 readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1134 if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1135 debug_error(DEBUG, "read id3v2 box\n");
1139 id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1141 id3v2Box.id3v2Data = mmfile_malloc(id3v2Len);
1142 if (!id3v2Box.id3v2Data) {
1143 debug_error(DEBUG, "malloc id3tag data error\n");
1147 readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1148 if (readed != id3v2Len) {
1149 debug_error(DEBUG, "read id3tag data error\n");
1154 if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1155 debug_error(DEBUG, "it is not id3tag\n");
1159 if (id3v2Box.id3v2Data[3] == 0xFF || id3v2Box.id3v2Data[4] == 0xFF ||
1160 id3v2Box.id3v2Data[6] >= 0x80 || id3v2Box.id3v2Data[7] >= 0x80 ||
1161 id3v2Box.id3v2Data[8] >= 0x80 || id3v2Box.id3v2Data[9] >= 0x80) {
1162 debug_error(DEBUG, "it is not valid id3tag\n");
1166 tagVersion = id3v2Box.id3v2Data[3];
1167 if (tagVersion > 4) {
1168 debug_error(DEBUG, "tag vesion is too high\n");
1172 encSize = mmfile_io_le_uint32((unsigned int)&id3v2Box.id3v2Data[6]);
1173 tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1174 tagInfo.tagV2Info.tagLen += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
1175 tagInfo.tagV2Info.tagVersion = tagVersion;
1176 tagInfo.fileLen = id3v2Len;
1178 /* set id3v2 data to formatContext */
1179 switch (tagVersion) {
1181 versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data);
1185 versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data);
1189 versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data);
1194 debug_error(DEBUG, "tag vesion is not support\n");
1195 versionCheck = false;
1200 if (versionCheck == false) {
1201 debug_error(DEBUG, "tag parsing is fail\n");
1205 if (!formatContext->title) formatContext->title = mmfile_strdup((const char *)tagInfo.pTitle);
1206 if (!formatContext->artist) formatContext->artist = mmfile_strdup((const char *)tagInfo.pArtist);
1207 if (!formatContext->author) formatContext->author = mmfile_strdup((const char *)tagInfo.pAuthor);
1208 if (!formatContext->copyright) formatContext->copyright = mmfile_strdup((const char *)tagInfo.pCopyright);
1209 if (!formatContext->comment) formatContext->comment = mmfile_strdup((const char *)tagInfo.pComment);
1210 if (!formatContext->album) formatContext->album = mmfile_strdup((const char *)tagInfo.pAlbum);
1211 if (!formatContext->album_artist) formatContext->album_artist = mmfile_strdup((const char *)tagInfo.pAlbum_Artist);
1212 if (!formatContext->year) formatContext->year = mmfile_strdup((const char *)tagInfo.pYear);
1213 if (!formatContext->genre) formatContext->genre = mmfile_strdup((const char *)tagInfo.pGenre);
1214 if (!formatContext->tagTrackNum) formatContext->tagTrackNum = mmfile_strdup((const char *)tagInfo.pTrackNum);
1215 if (!formatContext->composer) formatContext->composer = mmfile_strdup((const char *)tagInfo.pComposer);
1216 if (!formatContext->classification) formatContext->classification = mmfile_strdup((const char *)tagInfo.pContentGroup);
1217 if (!formatContext->conductor) formatContext->conductor = mmfile_strdup((const char *)tagInfo.pConductor);
1219 formatContext->artwork = mmfile_malloc(tagInfo.imageInfo.imageLen);
1220 if ((tagInfo.imageInfo.imageLen > 0) && formatContext->artwork) {
1221 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1222 memcpy(formatContext->artwork, tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1225 mm_file_free_AvFileContentInfo(&tagInfo);
1226 mmfile_free(id3v2Box.id3v2Data);
1228 /*reset seek position*/
1229 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1231 return MMFILE_UTIL_SUCCESS;
1237 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1238 mmfile_free(id3v2Box.id3v2Data);
1239 mm_file_free_AvFileContentInfo(&tagInfo);
1241 return MMFILE_UTIL_FAIL;
1244 static int g_junk_counter_limit = 0;
1245 static int GetJunkCounterLimit(void)
1247 dictionary *dict = NULL;
1250 dict = iniparser_load(MM_FILE_INI_PATH);
1252 debug_error(DEBUG, "%s load failed", MM_FILE_INI_PATH);
1256 data = iniparser_getint(dict, "mm-file-config:junk_counter_limit", 0);
1257 debug_msg(DEBUG, "mm-file-config:junk_counter_limit= %u", data);
1259 iniparser_freedict(dict);
1264 #define BIG_CONTENT_BOX_SIZE_LEN 8
1265 EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
1267 MMFileIOHandle *fp = NULL;
1270 unsigned long long chunk_size = 0;
1271 long long moov_end = 0;
1273 ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1274 if (ret == MMFILE_UTIL_FAIL) {
1275 debug_error(DEBUG, "error: mmfile_open\n");
1279 MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
1280 basic_header.start_offset = mmfile_tell(fp);
1282 int junk_counter = 0;
1283 if (g_junk_counter_limit == 0)
1284 g_junk_counter_limit = GetJunkCounterLimit();
1286 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)) {
1287 basic_header.size = mmfile_io_be_uint32(basic_header.size);
1288 basic_header.type = mmfile_io_le_uint32(basic_header.type);
1290 if (basic_header.size == 0) {
1291 debug_warning(DEBUG, "header is invalid.\n");
1292 basic_header.size = readed;
1293 basic_header.type = 0;
1294 chunk_size = basic_header.size;
1296 if ((moov_end != 0) && (moov_end < basic_header.start_offset))
1298 debug_msg(DEBUG, "found junk data but moov data already was extracted, so junk counter will be increase: %d", junk_counter);
1301 /* stop the loop for junk case. */
1302 if ((g_junk_counter_limit > 0) && (junk_counter > g_junk_counter_limit))
1304 debug_msg(DEBUG, "stop the loop by junk-data checker");
1305 ret = MMFILE_UTIL_FAIL;
1309 } else if (basic_header.size == 1) {
1311 unsigned char temp[BIG_CONTENT_BOX_SIZE_LEN] = {0, };
1312 unsigned long long size = 0;
1314 mmfile_read(fp, (unsigned char *)&temp, BIG_CONTENT_BOX_SIZE_LEN);
1316 for(i = 0; i < BIG_CONTENT_BOX_SIZE_LEN; i++)
1317 size |= (unsigned long long)temp[i] << (BIG_CONTENT_BOX_SIZE_LEN - 1 - i) * BIG_CONTENT_BOX_SIZE_LEN;
1321 chunk_size = basic_header.size;
1325 switch (basic_header.type) {
1326 case FOURCC('m', 'o', 'o', 'v'): {
1327 debug_msg(RELEASE, "MPEG4: [moov] SIZE: [%lld]Byte\n", chunk_size);
1328 moov_end = basic_header.start_offset + chunk_size;
1331 case FOURCC('u', 'd', 't', 'a'): {
1332 debug_msg(RELEASE, "MPEG4: [udat] SIZE: [%lld]Byte\n", chunk_size);
1335 /*/////////////////////////////////////////////////////////////// */
1336 /* Extracting Tag Data // */
1337 /*/////////////////////////////////////////////////////////////// */
1338 case FOURCC('t', 'i', 't', 'l'): {
1339 debug_msg(RELEASE, "MPEG4: [titl] SIZE: [%lld]Byte\n", chunk_size);
1340 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
1343 case FOURCC('d', 's', 'c', 'p'): {
1344 debug_msg(RELEASE, "MPEG4: [dscp] SIZE: [%lld]Byte\n", chunk_size);
1345 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
1348 case FOURCC('c', 'p', 'r', 't'): {
1349 debug_msg(RELEASE, "MPEG4: [cprt] SIZE: [%lld]Byte\n", chunk_size);
1350 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
1353 case FOURCC('p', 'e', 'r', 'f'): {
1354 debug_msg(RELEASE, "MPEG4: [perf] SIZE: [%lld]Byte\n", chunk_size);
1355 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
1358 case FOURCC('a', 'u', 't', 'h'): {
1359 debug_msg(RELEASE, "MPEG4: [auth] SIZE: [%lld]Byte\n", chunk_size);
1360 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
1363 case FOURCC('g', 'n', 'r', 'e'): {
1364 debug_msg(RELEASE, "MPEG4: [gnre] SIZE: [%lld]Byte\n", chunk_size);
1365 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
1368 case FOURCC('a', 'l', 'b', 'm'): {
1369 debug_msg(RELEASE, "MPEG4: [albm] SIZE: [%lld]Byte\n", chunk_size);
1370 GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
1373 case FOURCC('y', 'r', 'r', 'c'): {
1374 debug_msg(RELEASE, "MPEG4: [yrrc] SIZE: [%lld]Byte\n", chunk_size);
1375 GetYearFromYearTagBox(formatContext, fp, &basic_header);
1378 case FOURCC('r', 't', 'n', 'g'): {
1379 debug_msg(RELEASE, "MPEG4: [rtng] SIZE: [%lld]Byte\n", chunk_size);
1380 GetRatingFromRatingTagBox(formatContext, fp, &basic_header); /* not use */
1383 case FOURCC('c', 'l', 's', 'f'): {
1384 debug_msg(RELEASE, "MPEG4: [clsf] SIZE: [%lld]Byte\n", chunk_size);
1385 GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
1388 case FOURCC('k', 'y', 'w', 'd'): {
1389 debug_msg(RELEASE, "MPEG4: [kywd] SIZE: [%lld]Byte\n", chunk_size);
1390 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
1393 case FOURCC('l', 'o', 'c', 'i'): {
1394 debug_msg(RELEASE, "MPEG4: [loci] SIZE: [%lld]Byte\n", chunk_size);
1395 GetLocationFromLociTagBox(formatContext, fp, &basic_header);
1398 /* Check smta in user data field (moov) to be compatible with android */
1399 case FOURCC('s', 'm', 't', 'a'): {
1400 debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
1401 GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
1404 /* Check cdis in user data field (moov) to be compatible with android */
1405 case FOURCC('c', 'd', 'i', 's'): {
1406 debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
1407 GetValueFromCDISTagBox(formatContext, fp, &basic_header);
1410 /*/////////////////////////////////////////////////////////////// */
1411 /* Extracting ID3 Tag Data // */
1412 /*/////////////////////////////////////////////////////////////// */
1413 case FOURCC('m', 'e', 't', 'a'): {
1414 debug_msg(RELEASE, "MPEG4: [meta] SIZE: [%lld]Byte\n", chunk_size);
1415 GetTagFromMetaBox(formatContext, fp, &basic_header);
1419 case FOURCC('t', 'r', 'a', 'k'): {
1420 debug_msg(RELEASE, "MPEG4: [trak] SIZE: [%lld]Byte\n", chunk_size);
1423 case FOURCC('u', 'u', 'i', 'd'): {
1424 unsigned long uuid[4] = {0, };
1426 debug_msg(RELEASE, "MPEG4: [uuid] SIZE: [%lld]Byte\n", chunk_size);
1428 mmfile_read(fp, (unsigned char *)uuid, sizeof(uuid));
1430 if (mmfile_io_be_uint32(uuid[0]) == 0xffcc8263
1431 && mmfile_io_be_uint32(uuid[1]) == 0xf8554a93
1432 && mmfile_io_be_uint32(uuid[2]) == 0x8814587a
1433 && mmfile_io_be_uint32(uuid[3]) == 0x02521fdd) {
1435 str = (char *)malloc(basic_header.size);
1438 memset(str, 0, basic_header.size);
1439 mmfile_read(fp, (unsigned char *)str, basic_header.size);
1441 if(strstr(str, "<GSpherical:Spherical>true</GSpherical:Spherical>"))
1442 formatContext->is_360 = 1;
1444 formatContext->is_360 = 0;
1446 if(formatContext->is_360 == 1) {
1447 if (strstr(str, "<GSpherical:Stitched>true</GSpherical:Stitched>"))
1448 formatContext->stitched_info = MMFILE_360_STITCHED;
1450 formatContext->stitched_info = MMFILE_360_NON_STITCHED;
1452 formatContext->stitched_info = MMFILE_360_NONE;
1456 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
1461 debug_msg(RELEASE, "4CC: Not Support [%c%c%c%c]. So skip it. Size [%lld Byte]\n",
1462 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
1463 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3], chunk_size);
1464 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
1469 if (ret == MMFILE_UTIL_FAIL) {
1470 debug_error(DEBUG, "mmfile operation is error\n");
1475 basic_header.start_offset = mmfile_tell(fp);
1483 static char *get_string(const char *buf, int buf_size, int *bytes_written)
1487 char str[512] = {0, };
1490 for (i = 0; i < buf_size; i++) {
1494 if ((q - str) >= (int)sizeof(str) - 1)
1500 if (strlen(str) > 0) {
1501 *bytes_written = strlen(str);
1509 static bool is_numeric(const char *buf, int buf_size)
1514 for (idx = 0; idx < buf_size; idx++) {
1515 if (isdigit((int)buf[idx])) {
1526 char *rtrimN(char *pStr)
1529 pos = strlen(pStr) - 1;
1530 for (; pos >= 0; pos--) {
1531 if (pStr[pos] == 0x20) {
1538 return strdup(pStr);
1541 bool safe_atoi(char *buffer, int *si)
1547 const long sl = strtol(buffer, &end, 10);
1549 if (end == buffer) {
1550 debug_error(RELEASE, "not a decimal number");
1552 } else if ('\0' != *end) {
1553 debug_error(RELEASE, "extra characters at end of input: %s", end);
1555 } else if ((LONG_MIN == sl || LONG_MAX == sl) && (ERANGE == errno)) {
1556 debug_error(RELEASE, "out of range of type long");
1558 } else if (sl > INT_MAX) {
1559 debug_error(RELEASE, "greater than INT_MAX");
1561 } else if (sl < INT_MIN) {
1562 debug_error(RELEASE, "less than INT_MIN");
1570 static bool make_characterset_array(char ***charset_array)
1572 char *locale = MMFileUtilGetLocale(NULL);
1574 *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
1576 if (*charset_array == NULL) {
1577 debug_error(DEBUG, "calloc failed ");
1583 if (locale != NULL) {
1584 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
1586 debug_error(DEBUG, "get locale failed");
1587 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
1590 (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
1591 (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
1592 (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
1597 static bool release_characterset_array(char **charset_array)
1601 for (i = 0; i < AV_ID3V2_MAX; i++) {
1602 if (charset_array[i] != NULL) {
1603 free(charset_array[i]);
1604 charset_array[i] = NULL;
1608 if (charset_array != NULL) {
1609 free(charset_array);
1610 charset_array = NULL;
1616 static void init_content_info(AvFileContentInfo *pInfo)
1618 pInfo->tagV2Info.bTitleMarked = false;
1619 pInfo->tagV2Info.bArtistMarked = false;
1620 pInfo->tagV2Info.bAlbumMarked = false;
1621 pInfo->tagV2Info.bAlbum_ArtistMarked = false;
1622 pInfo->tagV2Info.bYearMarked = false;
1623 pInfo->tagV2Info.bDescriptionMarked = false;
1624 pInfo->tagV2Info.bGenreMarked = false;
1625 pInfo->tagV2Info.bTrackNumMarked = false;
1626 pInfo->tagV2Info.bEncByMarked = false;
1627 pInfo->tagV2Info.bURLMarked = false;
1628 pInfo->tagV2Info.bCopyRightMarked = false;
1629 pInfo->tagV2Info.bOriginArtistMarked = false;
1630 pInfo->tagV2Info.bComposerMarked = false;
1631 pInfo->tagV2Info.bImageMarked = false;
1633 pInfo->tagV2Info.bRecDateMarked = false;
1634 pInfo->tagV2Info.bContentGroupMarked = false;
1636 pInfo->tagV2Info.bUnsyncLyricsMarked = false;
1637 pInfo->tagV2Info.bSyncLyricsMarked = false;
1638 pInfo->tagV2Info.bConductorMarked = false;
1639 pInfo->tagV2Info.bGenreUTF16 = false;
1641 pInfo->imageInfo.bURLInfo = false;
1642 pInfo->imageInfo.pImageBuf = NULL;
1643 pInfo->imageInfo.imageLen = 0;
1647 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo, unsigned char *buffer)
1649 const char *locale = MMFileUtilGetLocale(NULL);
1650 char *pFullStr = NULL;
1652 debug_msg(RELEASE, "ID3tag v110--------------------------------------------------------------\n");
1654 if (pInfo->tagV2Info.bTitleMarked == false) {
1655 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
1656 if (pFullStr != NULL) {
1657 pInfo->pTitle = rtrimN(pFullStr);
1661 debug_msg(RELEASE, "pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1664 if (pInfo->tagV2Info.bArtistMarked == false) {
1665 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
1666 if (pFullStr != NULL) {
1667 pInfo->pArtist = rtrimN(pFullStr);
1671 debug_msg(RELEASE, "pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1674 if (pInfo->tagV2Info.bAlbumMarked == false) {
1675 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
1676 if (pFullStr != NULL) {
1677 pInfo->pAlbum = rtrimN(pFullStr);
1681 debug_msg(RELEASE, "pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1684 if (pInfo->tagV2Info.bYearMarked == false) {
1686 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
1688 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1690 if (pInfo->pYear == NULL) { /*Use same logic with ffmpeg*/
1691 pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
1692 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1696 if (pInfo->tagV2Info.bDescriptionMarked == false) {
1697 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
1698 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1700 if (pInfo->pComment == NULL) { /*Use same logic with ffmpeg*/
1701 pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
1702 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1706 if (pInfo->tagV2Info.bTrackNumMarked == false) {
1707 pInfo->pTrackNum = mmfile_malloc(5);
1708 if (pInfo->pTrackNum != NULL) {
1709 pInfo->pTrackNum[4] = 0;
1710 snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
1711 pInfo->tracknumLen = strlen(pInfo->pTrackNum);
1713 debug_msg(RELEASE, "pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1717 if (pInfo->tagV2Info.bGenreMarked == false) {
1718 pInfo->genre = buffer[127];
1719 debug_msg(RELEASE, "pInfo->genre returned genre number (%d)\n", pInfo->genre);
1726 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
1728 unsigned long taglen = 0;
1729 unsigned long needToloopv2taglen;
1730 unsigned long oneFrameLen = 0;
1731 unsigned long v2numOfFrames = 0;
1732 unsigned long curPos = 0;
1734 unsigned char *pExtContent = NULL;
1735 unsigned long purelyFramelen = 0;
1736 unsigned int encodingOffSet = 0;
1737 int inx = 0, realCpyFrameNum = 0,
1738 /*checkImgMimeTypeMax = 0, */checkImgExtMax = 0,
1739 imgstartOffset = 0, tmp = 0;
1741 int textEncodingType = 0;
1743 char **charset_array = NULL;
1745 make_characterset_array(&charset_array);
1747 init_content_info(pInfo);
1749 taglen = pInfo->tagV2Info.tagLen;
1750 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
1751 curPos = MP3_TAGv2_HEADER_LEN;
1753 debug_msg(RELEASE, "ID3tag v222--------------------------------------------------------------\n");
1755 if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
1757 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
1758 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
1759 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
1762 memcpy(CompTmp, &buffer[curPos], 3);
1765 oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
1766 oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
1767 | (unsigned long)buffer[5 + curPos];
1768 if (oneFrameLen > taglen - curPos)
1770 purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
1771 curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
1773 if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
1774 curPos += purelyFramelen;
1776 if (buffer[curPos - purelyFramelen] == 0x00) {
1778 textEncodingType = AV_ID3V2_ISO_8859;
1779 } else if (buffer[curPos - purelyFramelen] == 0x01) {
1781 textEncodingType = AV_ID3V2_UTF16;
1784 /*in order to deliver valid string to MP */
1785 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
1788 if (encodingOffSet < purelyFramelen) {
1789 realCpyFrameNum = purelyFramelen - encodingOffSet;
1790 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
1792 if (pExtContent == NULL) {
1793 debug_error(DEBUG, "out of memory for pExtContent\n");
1797 memset(pExtContent, '\0', realCpyFrameNum + 3);
1799 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
1801 if (realCpyFrameNum > 0) {
1802 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
1803 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
1804 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1805 pInfo->tagV2Info.bTitleMarked = true;
1806 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
1807 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
1808 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1809 pInfo->tagV2Info.bArtistMarked = true;
1810 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
1811 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
1812 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
1813 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
1814 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
1815 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
1816 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
1817 pInfo->tagV2Info.bConductorMarked = true;
1818 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
1819 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
1820 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1821 pInfo->tagV2Info.bAlbumMarked = true;
1822 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
1823 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
1824 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1825 pInfo->tagV2Info.bYearMarked = true;
1826 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
1827 /*skip language data! */
1828 if (realCpyFrameNum > 4) {
1829 realCpyFrameNum -= 4;
1832 /*pExtContent[tmp+1] value should't have encoding value */
1833 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1834 if (pExtContent[tmp - 1] == 0x00)
1835 textEncodingType = AV_ID3V2_ISO_8859;
1837 textEncodingType = AV_ID3V2_UTF16;
1839 pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
1840 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1841 pInfo->tagV2Info.bDescriptionMarked = true;
1843 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
1846 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1850 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
1851 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
1852 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
1854 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
1858 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
1861 ret = safe_atoi(pInfo->pGenre, &int_genre);
1863 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
1865 /*Change int to string */
1866 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
1867 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
1868 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
1869 int tmp_genre_len = 0;
1871 memset(tmp_genre, 0, 6);
1872 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
1874 tmp_genre_len = strlen(tmp_genre);
1875 if (tmp_genre_len > 0) {
1876 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
1877 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
1878 if (pInfo->pGenre) {
1879 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
1880 pInfo->pGenre[tmp_genre_len] = 0;
1885 debug_error(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
1890 pInfo->tagV2Info.bGenreMarked = true;
1891 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
1892 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
1893 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1894 pInfo->tagV2Info.bTrackNumMarked = true;
1895 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
1896 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
1897 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
1898 pInfo->tagV2Info.bEncByMarked = true;
1899 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
1900 if (realCpyFrameNum > 4) {
1901 /*skip language data! */
1902 realCpyFrameNum -= 4;
1905 /*pExtContent[tmp+1] value should't have null value */
1906 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1907 if (pExtContent[tmp - 1] == 0x00)
1908 textEncodingType = AV_ID3V2_ISO_8859;
1910 textEncodingType = AV_ID3V2_UTF16;
1912 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
1913 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
1914 pInfo->tagV2Info.bURLMarked = true;
1916 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
1919 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1922 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
1923 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
1924 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
1925 pInfo->tagV2Info.bCopyRightMarked = true;
1926 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
1927 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
1928 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
1929 pInfo->tagV2Info.bOriginArtistMarked = true;
1930 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
1931 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
1932 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
1933 pInfo->tagV2Info.bComposerMarked = true;
1934 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
1935 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
1936 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
1937 pInfo->tagV2Info.bRecDateMarked = true;
1938 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
1939 if (pExtContent[0] != 0) {
1940 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
1941 pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
1943 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
1944 pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
1948 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
1951 imgstartOffset += checkImgExtMax;
1953 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
1954 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
1956 imgstartOffset++;/*PictureType(1byte) */
1958 if (pExtContent[imgstartOffset] != 0x0) {
1961 int new_dis_len = 0;
1962 char *tmp_desc = NULL;
1965 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
1966 if (realCpyFrameNum < imgstartOffset + cur_pos) {
1967 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
1970 /*check end of image description*/
1971 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
1972 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
1973 debug_msg(RELEASE, "length of description (%d)", cur_pos);
1980 dis_len = cur_pos + 1;
1982 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
1984 if (tmp_desc != NULL) {
1985 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
1987 /*convert description*/
1988 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
1989 mmfile_free(tmp_desc);
1990 debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
1991 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
1994 imgstartOffset += cur_pos;
1996 pInfo->imageInfo.imgDesLen = 0;
1999 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2000 imgstartOffset++; /* endofDesceriptionType(1byte) */
2002 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2006 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2008 if (realCpyFrameNum - imgstartOffset > 0) {
2009 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2010 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2012 if (pInfo->imageInfo.pImageBuf != NULL) {
2013 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2014 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2017 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2018 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2020 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2024 /*checkImgMimeTypeMax = 0;*/
2028 pInfo->tagV2Info.bImageMarked = true;
2035 curPos += purelyFramelen;
2036 if (purelyFramelen != 0)
2037 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2040 if (pExtContent) _FREE_EX(pExtContent);
2041 memset(CompTmp, 0, 4);
2042 if (curPos < taglen) {
2043 needToloopv2taglen -= oneFrameLen;
2046 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2049 realCpyFrameNum = 0;
2050 textEncodingType = 0;
2056 release_characterset_array(charset_array);
2066 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2068 unsigned long taglen = 0;
2069 unsigned long needToloopv2taglen;
2070 unsigned long oneFrameLen = 0;
2071 unsigned long v2numOfFrames = 0;
2072 unsigned long curPos = 0;
2074 unsigned char *pExtContent = NULL;
2075 unsigned long purelyFramelen = 0;
2076 unsigned int encodingOffSet = 0;
2077 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2078 int textEncodingType = 0;
2079 char **charset_array = NULL;
2080 const char *MIME_PRFIX = "image/";
2082 make_characterset_array(&charset_array);
2084 init_content_info(pInfo);
2086 taglen = pInfo->tagV2Info.tagLen;
2087 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2088 curPos = MP3_TAGv2_HEADER_LEN;
2090 debug_msg(RELEASE, "ID3tag v223--------------------------------------------------------------\n");
2092 /* check Extended Header */
2093 if (buffer[5] & 0x40) {
2094 /* if extended header exists, skip it*/
2095 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2097 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2099 if (extendedHeaderLen > (int)(taglen - curPos)) {
2100 debug_error(DEBUG, "extended header too long.\n");
2102 curPos += extendedHeaderLen;
2107 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2109 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2110 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2111 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2114 memcpy(CompTmp, &buffer[curPos], 4);
2117 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2118 oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2119 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2121 debug_msg(RELEASE, "----------------------------------------------------------------------------------------------------\n");
2123 if (oneFrameLen > taglen - curPos)
2126 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2127 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2129 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2130 curPos += purelyFramelen;
2132 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2134 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2135 textEncodingType = AV_ID3V2_UTF16;
2136 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2138 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2139 textEncodingType = AV_ID3V2_UTF16_BE;
2140 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2142 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2143 textEncodingType = AV_ID3V2_UTF16;
2144 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2146 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2147 textEncodingType = AV_ID3V2_UTF16_BE;
2149 if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2150 debug_msg(RELEASE, "encodingOffset will be set to 1\n");
2153 debug_msg(RELEASE, "Finding encodingOffset\n");
2155 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2158 textEncodingType = AV_ID3V2_ISO_8859;
2159 debug_msg(RELEASE, "this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2162 if (encodingOffSet < purelyFramelen) {
2163 realCpyFrameNum = purelyFramelen - encodingOffSet;
2164 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2166 if (pExtContent == NULL) {
2167 debug_msg(DEBUG, "pExtContent malloc failed\n");
2171 memset(pExtContent, '\0', realCpyFrameNum + 3);
2173 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2174 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2175 debug_msg(RELEASE, "get the new text ecoding type\n");
2176 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2180 if (textEncodingType > AV_ID3V2_MAX) {
2181 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2185 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2186 if (realCpyFrameNum > 0) {
2187 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2188 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2189 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2190 pInfo->tagV2Info.bTitleMarked = true;
2192 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2193 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2194 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2195 pInfo->tagV2Info.bArtistMarked = true;
2196 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2197 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2198 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2199 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2200 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2201 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2202 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2203 pInfo->tagV2Info.bConductorMarked = true;
2204 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2205 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2206 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2207 pInfo->tagV2Info.bAlbumMarked = true;
2208 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2209 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2210 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2211 pInfo->tagV2Info.bYearMarked = true;
2212 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2213 if (realCpyFrameNum > 3) {
2214 realCpyFrameNum -= 3;
2217 /*pExtContent[tmp+1] value should't have encoding value */
2218 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2219 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2220 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2221 realCpyFrameNum -= 4;
2225 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2226 realCpyFrameNum -= 2;
2228 textEncodingType = AV_ID3V2_UTF16;
2229 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2230 realCpyFrameNum -= 2;
2232 textEncodingType = AV_ID3V2_UTF16_BE;
2233 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2234 realCpyFrameNum -= 3;
2236 textEncodingType = AV_ID3V2_UTF16;
2237 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2238 realCpyFrameNum -= 3;
2240 textEncodingType = AV_ID3V2_UTF16_BE;
2242 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
2245 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2249 textEncodingType = AV_ID3V2_ISO_8859;
2252 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2253 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2255 debug_msg(RELEASE, "failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2256 pInfo->commentLen = 0;
2259 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2260 pInfo->commentLen = 0;
2264 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2265 pInfo->tagV2Info.bDescriptionMarked = true;
2266 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2269 int copy_start_pos = tmp;
2270 AvSynclyricsInfo *synclyrics_info = NULL;
2271 GList *synclyrics_info_list = NULL;
2273 if (realCpyFrameNum > 5) {
2274 realCpyFrameNum -= 5;
2277 /*pExtContent[tmp+1] value should't have encoding value */
2278 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2279 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2280 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2281 realCpyFrameNum -= 4;
2285 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2286 realCpyFrameNum -= 2;
2288 textEncodingType = AV_ID3V2_UTF16;
2289 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2290 realCpyFrameNum -= 2;
2292 textEncodingType = AV_ID3V2_UTF16_BE;
2293 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2294 realCpyFrameNum -= 3;
2296 textEncodingType = AV_ID3V2_UTF16;
2297 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2298 realCpyFrameNum -= 3;
2300 textEncodingType = AV_ID3V2_UTF16_BE;
2302 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
2305 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2309 textEncodingType = AV_ID3V2_ISO_8859;
2312 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2314 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2315 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
2316 pInfo->syncLyricsNum = 0;
2318 if (textEncodingType == AV_ID3V2_UTF16) {
2319 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
2320 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
2321 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
2323 for (idx = 0; idx < realCpyFrameNum; idx++) {
2324 if (pExtContent[tmp + idx] == 0x00) {
2325 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
2327 if (synclyrics_info != NULL) {
2328 if (textEncodingType == AV_ID3V2_UTF8) {
2329 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
2330 if (synclyrics_info->lyric_info != NULL) {
2331 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
2332 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
2333 synclyrics_info->lyric_info[copy_len] = '\0';
2336 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);
2339 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];
2341 copy_start_pos = tmp + idx + 1;
2342 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);
2344 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
2349 pInfo->pSyncLyrics = synclyrics_info_list;
2350 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
2354 debug_msg(RELEASE, "failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2355 pInfo->syncLyricsNum = 0;
2358 debug_msg(RELEASE, "Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2359 pInfo->syncLyricsNum = 0;
2363 //debug_msg(RELEASE, "pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
2364 debug_msg(RELEASE, "pInfo->syncLyricsNum(%d)\n", pInfo->syncLyricsNum);
2365 pInfo->tagV2Info.bSyncLyricsMarked = true;
2366 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
2367 char *lang_info = strndup((char *)pExtContent, 3);
2369 if (realCpyFrameNum > 3) {
2370 realCpyFrameNum -= 3;
2373 /*find start of lyrics */
2375 if (pExtContent[tmp] == 0x00) {
2376 if (pExtContent[tmp + 1] == 0x00) {
2377 realCpyFrameNum -= 2;
2387 /*pExtContent[tmp+1] value should't have encoding value */
2388 debug_msg(RELEASE, "tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
2390 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2391 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2392 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2393 realCpyFrameNum -= 4;
2397 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2398 realCpyFrameNum -= 2;
2400 textEncodingType = AV_ID3V2_UTF16;
2401 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2402 realCpyFrameNum -= 2;
2404 textEncodingType = AV_ID3V2_UTF16_BE;
2405 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2406 realCpyFrameNum -= 3;
2408 textEncodingType = AV_ID3V2_UTF16;
2409 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2410 realCpyFrameNum -= 3;
2412 textEncodingType = AV_ID3V2_UTF16_BE;
2414 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
2417 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2421 textEncodingType = AV_ID3V2_ISO_8859;
2424 char *char_set = NULL;
2426 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2428 if (textEncodingType == AV_ID3V2_ISO_8859) {
2429 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
2430 char_set = strdup("EUC-KR");
2432 char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
2434 _FREE_EX(lang_info);
2437 if (char_set == NULL) {
2438 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2440 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2444 debug_msg(RELEASE, "failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2445 pInfo->unsynclyricsLen = 0;
2448 debug_msg(RELEASE, "Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2449 pInfo->unsynclyricsLen = 0;
2453 debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
2454 pInfo->tagV2Info.bUnsyncLyricsMarked = true;
2455 mmfile_free(lang_info);
2456 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2457 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2458 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2460 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2464 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2467 ret = safe_atoi(pInfo->pGenre, &int_genre);
2469 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
2471 /*Change int to string */
2472 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2473 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2474 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
2475 int tmp_genre_len = 0;
2477 memset(tmp_genre, 0, 6);
2478 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2480 tmp_genre_len = strlen(tmp_genre);
2481 if (tmp_genre_len > 0) {
2482 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2483 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2484 if (pInfo->pGenre) {
2485 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
2486 pInfo->pGenre[tmp_genre_len] = 0;
2491 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
2496 pInfo->tagV2Info.bGenreMarked = true;
2497 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2498 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2499 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2500 pInfo->tagV2Info.bTrackNumMarked = true;
2501 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2502 pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2503 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2504 pInfo->tagV2Info.bEncByMarked = true;
2505 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2506 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2507 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2508 pInfo->tagV2Info.bURLMarked = true;
2509 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2510 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2511 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2512 pInfo->tagV2Info.bCopyRightMarked = true;
2513 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2514 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2515 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2516 pInfo->tagV2Info.bOriginArtistMarked = true;
2517 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2518 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2519 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2520 pInfo->tagV2Info.bComposerMarked = true;
2521 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2522 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2523 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2524 pInfo->tagV2Info.bRecDateMarked = true;
2525 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2526 debug_msg(DEBUG, "text encoding %d \n", textEncodingType);
2528 if (pExtContent[0] != '\0') {
2529 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
2530 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
2532 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
2533 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
2534 checkImgMimeTypeMax++;
2536 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
2538 pInfo->imageInfo.imgMimetypeLen = 0;
2539 debug_msg(RELEASE, "APIC image's not included to MIME type\n");
2542 imgstartOffset += checkImgMimeTypeMax;
2544 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2545 pInfo->imageInfo.imgMimetypeLen = 0;
2546 debug_error(DEBUG, "APIC NOT VALID");
2550 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2551 imgstartOffset++;/*endofMIME(1byte) */
2552 debug_msg(RELEASE, "after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
2554 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2555 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2557 debug_msg(RELEASE, "APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
2559 imgstartOffset++;/*PictureType(1byte) */
2560 debug_msg(RELEASE, "after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
2562 if (pExtContent[imgstartOffset] != 0x0) {
2565 int new_dis_len = 0;
2566 char *tmp_desc = NULL;
2569 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2570 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2571 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2574 /*check end of image description*/
2575 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2576 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2577 debug_msg(RELEASE, "length of description (%d)", cur_pos);
2584 dis_len = cur_pos + 1;
2586 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2587 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2589 /*convert description*/
2590 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2591 debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2592 mmfile_free(tmp_desc);
2594 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2595 imgstartOffset += cur_pos;
2597 pInfo->imageInfo.imgDesLen = 0;
2598 debug_msg(RELEASE, "APIC image's not included to Description!!!\n");
2601 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2602 imgstartOffset++; /* endofDesceriptionType(1byte) */
2604 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2608 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2610 if (realCpyFrameNum - imgstartOffset > 0) {
2611 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2612 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2614 if (pInfo->imageInfo.pImageBuf != NULL) {
2615 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2616 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2619 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2620 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2622 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2624 debug_msg(RELEASE, "pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
2626 debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
2627 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2630 debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
2631 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2634 checkImgMimeTypeMax = 0;
2637 pInfo->tagV2Info.bImageMarked = true;
2640 debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
2645 debug_msg(RELEASE, "All of the pExtContent Values are NULL\n");
2648 curPos += purelyFramelen;
2649 if (purelyFramelen != 0)
2650 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2652 debug_msg(RELEASE, "This Frame's size is Zero! purelyFramelen(%lu)\n", purelyFramelen);
2655 if (pExtContent) _FREE_EX(pExtContent);
2656 memset(CompTmp, 0, 4);
2658 if (curPos < taglen) {
2659 needToloopv2taglen -= oneFrameLen;
2662 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2665 realCpyFrameNum = 0;
2666 textEncodingType = 0;
2672 release_characterset_array(charset_array);
2682 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
2684 unsigned long taglen = 0;
2685 unsigned long needToloopv2taglen;
2686 unsigned long oneFrameLen = 0;
2687 unsigned long v2numOfFrames = 0;
2688 unsigned long curPos = 0;
2690 unsigned char *pExtContent = NULL;
2691 unsigned long purelyFramelen = 0;
2692 unsigned int encodingOffSet = 0;
2693 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2694 int textEncodingType = 0;
2695 char **charset_array = NULL;
2696 const char *MIME_PRFIX = "image/";
2698 make_characterset_array(&charset_array);
2700 init_content_info(pInfo);
2702 taglen = pInfo->tagV2Info.tagLen;
2703 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2704 curPos = MP3_TAGv2_HEADER_LEN;
2706 debug_msg(RELEASE, "ID3tag v224--------------------------------------------------------------\n");
2708 /* check Extended Header */
2709 if (buffer[5] & 0x40) {
2710 /* if extended header exists, skip it*/
2711 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2713 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2715 if (extendedHeaderLen > (int)(taglen - curPos)) {
2716 debug_error(DEBUG, "extended header too long.\n");
2718 curPos += extendedHeaderLen;
2722 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2724 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2725 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2726 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2729 memcpy(CompTmp, &buffer[curPos], 4);
2732 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2733 oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
2734 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
2735 if (oneFrameLen > taglen - curPos)
2738 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2739 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2741 debug_msg(RELEASE, "-----------------------------------------------------------------------------------\n");
2743 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2744 curPos += purelyFramelen;
2746 /*in case of UTF 16 encoding */
2747 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
2748 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2750 textEncodingType = AV_ID3V2_UTF16;
2751 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2753 textEncodingType = AV_ID3V2_UTF16_BE;
2754 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2756 textEncodingType = AV_ID3V2_UTF16;
2757 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2759 textEncodingType = AV_ID3V2_UTF16_BE;
2761 /*in case of UTF-16 BE encoding */
2762 if (buffer[curPos - purelyFramelen] == 0x02) {
2764 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2765 encodingOffSet++;/*null skip! */
2766 textEncodingType = AV_ID3V2_UTF16_BE;
2768 /*in case of UTF8 encoding */
2769 else if (buffer[curPos - purelyFramelen] == 0x03) {
2771 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2772 encodingOffSet++;/*null skip! */
2773 textEncodingType = AV_ID3V2_UTF8;
2775 /*in case of ISO-8859-1 encoding */
2777 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
2779 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2780 encodingOffSet++;/*less than 0x20 value skip! */
2781 textEncodingType = AV_ID3V2_ISO_8859;
2785 if (encodingOffSet < purelyFramelen) {
2786 realCpyFrameNum = purelyFramelen - encodingOffSet;
2787 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2789 if (pExtContent == NULL) {
2790 debug_error(DEBUG, "out of memoryu for id3tag parse\n");
2794 memset(pExtContent, '\0', realCpyFrameNum + 3);
2796 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2797 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2798 debug_msg(RELEASE, "get the new text ecoding type\n");
2799 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2803 if (textEncodingType > AV_ID3V2_MAX) {
2804 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2808 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2810 if (realCpyFrameNum > 0) {
2811 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2812 if (textEncodingType == AV_ID3V2_UTF8) {
2813 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2814 if (pInfo->pTitle) {
2815 memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
2816 pInfo->pTitle[realCpyFrameNum] = '\0';
2817 /*string copy with '\0'*/
2818 pInfo->titleLen = realCpyFrameNum;
2819 _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
2822 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2825 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2826 pInfo->tagV2Info.bTitleMarked = true;
2828 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2829 if (textEncodingType == AV_ID3V2_UTF8) {
2830 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2831 if (pInfo->pArtist) {
2832 memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
2833 pInfo->pArtist[realCpyFrameNum] = '\0';
2834 /*string copy with '\0'*/
2835 pInfo->artistLen = realCpyFrameNum;
2836 _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
2839 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2843 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2844 pInfo->tagV2Info.bArtistMarked = true;
2845 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2846 if (textEncodingType == AV_ID3V2_UTF8) {
2847 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2848 if (pInfo->pAlbum_Artist) {
2849 memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
2850 pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
2851 /*string copy with '\0'*/
2852 pInfo->album_artistLen = realCpyFrameNum;
2853 _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
2856 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2859 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2860 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2861 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2862 if (textEncodingType == AV_ID3V2_UTF8) {
2863 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2864 if (pInfo->pConductor) {
2865 memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
2866 pInfo->pConductor[realCpyFrameNum] = '\0';
2867 /*string copy with '\0'*/
2868 pInfo->conductorLen = realCpyFrameNum;
2869 _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
2872 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2875 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2876 pInfo->tagV2Info.bConductorMarked = true;
2877 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2878 if (textEncodingType == AV_ID3V2_UTF8) {
2879 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2880 if (pInfo->pAlbum) {
2881 memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
2882 pInfo->pAlbum[realCpyFrameNum] = '\0';
2883 /*string copy with '\0'*/
2884 pInfo->albumLen = realCpyFrameNum;
2885 _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
2888 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) { /*TODO. TYER is replaced by the TDRC. but many files use TYER in v2.4 */
2894 if (textEncodingType == AV_ID3V2_UTF8) {
2895 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2897 memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
2898 pInfo->pYear[realCpyFrameNum] = '\0';
2899 /*string copy with '\0'*/
2900 pInfo->yearLen = realCpyFrameNum;
2901 _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
2904 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2907 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2908 pInfo->tagV2Info.bYearMarked = true;
2909 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2910 if (realCpyFrameNum > 3) {
2911 realCpyFrameNum -= 3;
2914 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
2915 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2916 realCpyFrameNum -= 4;
2920 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2921 realCpyFrameNum -= 2;
2923 textEncodingType = AV_ID3V2_UTF16;
2925 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
2927 } else if (textEncodingType == AV_ID3V2_UTF8) {
2928 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2932 textEncodingType = AV_ID3V2_UTF8;
2934 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2938 textEncodingType = AV_ID3V2_ISO_8859;
2941 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2943 if (textEncodingType == AV_ID3V2_UTF8) {
2944 pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2945 if (pInfo->pComment) {
2946 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
2947 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
2948 pInfo->pComment[realCpyFrameNum] = '\0';
2949 /*string copy with '\0'*/
2950 pInfo->commentLen = realCpyFrameNum;
2951 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
2954 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2957 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2962 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2963 pInfo->tagV2Info.bDescriptionMarked = true;
2964 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2967 int copy_start_pos = tmp;
2968 AvSynclyricsInfo *synclyrics_info = NULL;
2969 GList *synclyrics_info_list = NULL;
2971 if (realCpyFrameNum > 5) {
2972 realCpyFrameNum -= 5;
2975 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
2976 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2977 realCpyFrameNum -= 4;
2981 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2982 realCpyFrameNum -= 2;
2984 textEncodingType = AV_ID3V2_UTF16;
2986 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
2988 } else if (textEncodingType == AV_ID3V2_UTF8) {
2989 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2993 textEncodingType = AV_ID3V2_UTF8;
2995 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2999 textEncodingType = AV_ID3V2_ISO_8859;
3002 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3004 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3005 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3006 pInfo->syncLyricsNum = 0;
3008 if (textEncodingType == AV_ID3V2_UTF16) {
3009 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3010 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3011 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3013 for (idx = 0; idx < realCpyFrameNum; idx++) {
3014 if (pExtContent[tmp + idx] == 0x00) {
3015 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3017 if (textEncodingType == AV_ID3V2_UTF8) {
3018 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3019 if (synclyrics_info->lyric_info) {
3020 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3021 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3022 synclyrics_info->lyric_info[copy_len] = '\0';
3025 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3028 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];
3030 copy_start_pos = tmp + idx + 1;
3031 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);
3033 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3037 pInfo->pSyncLyrics = synclyrics_info_list;
3038 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3042 debug_msg(RELEASE, "SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3046 pInfo->tagV2Info.bSyncLyricsMarked = true;
3047 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3048 if (realCpyFrameNum > 3) {
3049 realCpyFrameNum -= 3;
3052 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3053 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3054 realCpyFrameNum -= 4;
3058 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3059 realCpyFrameNum -= 2;
3061 textEncodingType = AV_ID3V2_UTF16;
3063 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3065 } else if (textEncodingType == AV_ID3V2_UTF8) {
3066 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3070 textEncodingType = AV_ID3V2_UTF8;
3072 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3076 textEncodingType = AV_ID3V2_ISO_8859;
3079 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3081 if (textEncodingType == AV_ID3V2_UTF8) {
3082 pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3084 if (pInfo->pUnsyncLyrics != NULL) {
3085 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3086 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3087 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3088 /*string copy with '\0'*/
3089 pInfo->unsynclyricsLen = realCpyFrameNum;
3090 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3092 debug_error(DEBUG, "out of memoryu for SyncLyrics\n");
3095 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3098 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3103 debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3104 pInfo->tagV2Info.bDescriptionMarked = true;
3105 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3106 if (textEncodingType == AV_ID3V2_UTF8) {
3107 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3108 if (pInfo->pGenre) {
3109 memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3110 pInfo->pGenre[realCpyFrameNum] = '\0';
3111 /*string copy with '\0'*/
3112 pInfo->genreLen = realCpyFrameNum;
3113 _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3116 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3119 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3121 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3125 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3128 ret = safe_atoi(pInfo->pGenre, &int_genre);
3130 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
3132 /*Change int to string */
3133 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3134 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3135 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3136 int tmp_genre_len = 0;
3138 memset(tmp_genre, 0, 6);
3139 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3141 tmp_genre_len = strlen(tmp_genre);
3142 if (tmp_genre_len > 0) {
3143 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3144 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3145 if (pInfo->pGenre) {
3146 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
3147 pInfo->pGenre[tmp_genre_len] = 0;
3152 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
3157 pInfo->tagV2Info.bGenreMarked = true;
3158 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3159 if (textEncodingType == AV_ID3V2_UTF8) {
3160 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3161 if (pInfo->pTrackNum != NULL) {
3162 memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3163 pInfo->pTrackNum[realCpyFrameNum] = '\0';
3164 /*string copy with '\0'*/
3165 pInfo->tracknumLen = realCpyFrameNum;
3166 _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3169 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3172 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3173 pInfo->tagV2Info.bTrackNumMarked = true;
3174 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3175 if (textEncodingType == AV_ID3V2_UTF8) {
3176 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3177 if (pInfo->pEncBy != NULL) {
3178 memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3179 pInfo->pEncBy[realCpyFrameNum] = '\0';
3180 /*string copy with '\0'*/
3181 pInfo->encbyLen = realCpyFrameNum;
3182 _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3185 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3188 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3189 pInfo->tagV2Info.bEncByMarked = true;
3190 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3191 if (textEncodingType == AV_ID3V2_UTF8) {
3192 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3193 if (pInfo->pURL != NULL) {
3194 memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3195 pInfo->pURL[realCpyFrameNum] = '\0';
3196 /*string copy with '\0'*/
3197 pInfo->urlLen = realCpyFrameNum;
3198 _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3201 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3204 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3205 pInfo->tagV2Info.bURLMarked = true;
3206 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3207 if (textEncodingType == AV_ID3V2_UTF8) {
3208 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3209 if (pInfo->pCopyright != NULL) {
3210 memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3211 pInfo->pCopyright[realCpyFrameNum] = '\0';
3212 /*string copy with '\0'*/
3213 pInfo->copyrightLen = realCpyFrameNum;
3214 _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3217 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3220 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3221 pInfo->tagV2Info.bCopyRightMarked = true;
3222 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3223 if (textEncodingType == AV_ID3V2_UTF8) {
3224 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3225 if (pInfo->pOriginArtist != NULL) {
3226 memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3227 pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3228 /*string copy with '\0'*/
3229 pInfo->originartistLen = realCpyFrameNum;
3230 _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3233 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3236 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3237 pInfo->tagV2Info.bOriginArtistMarked = true;
3238 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3239 if (textEncodingType == AV_ID3V2_UTF8) {
3240 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3241 if (pInfo->pComposer != NULL) {
3242 memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3243 pInfo->pComposer[realCpyFrameNum] = '\0';
3244 /*string copy with '\0'*/
3245 pInfo->composerLen = realCpyFrameNum;
3246 _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3249 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3252 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3253 pInfo->tagV2Info.bComposerMarked = true;
3254 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) { /*TYER(year) and TRDA are replaced by the TDRC */
3255 if (textEncodingType == AV_ID3V2_UTF8) {
3256 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3257 if (pInfo->pRecDate != NULL) {
3258 memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3259 pInfo->pRecDate[realCpyFrameNum] = '\0';
3260 /*string copy with '\0'*/
3261 pInfo->recdateLen = realCpyFrameNum;
3262 _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3265 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3268 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3269 pInfo->tagV2Info.bRecDateMarked = true;
3270 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3271 if (textEncodingType == AV_ID3V2_UTF8) {
3272 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3273 if (pInfo->pContentGroup != NULL) {
3274 memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3275 pInfo->pContentGroup[realCpyFrameNum] = '\0';
3276 /*string copy with '\0'*/
3277 pInfo->contentGroupLen = realCpyFrameNum;
3278 _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3281 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3284 debug_msg(RELEASE, "pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3285 pInfo->tagV2Info.bContentGroupMarked = true;
3286 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3287 if (pExtContent[0] != '\0') {
3288 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3289 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3291 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3292 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3293 checkImgMimeTypeMax++;
3295 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3297 pInfo->imageInfo.imgMimetypeLen = 0;
3300 imgstartOffset += checkImgMimeTypeMax;
3302 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3303 pInfo->imageInfo.imgMimetypeLen = 0;
3304 debug_error(DEBUG, "APIC NOT VALID");
3308 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3309 imgstartOffset++;/*endofMIME(1byte) */
3311 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3312 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3314 imgstartOffset++;/*PictureType(1byte) */
3316 if (pExtContent[imgstartOffset] != 0x0) {
3319 int new_dis_len = 0;
3320 char *tmp_desc = NULL;
3323 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3324 if (realCpyFrameNum < imgstartOffset + cur_pos) {
3325 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3328 /*check end of image description*/
3329 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
3330 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
3331 debug_msg(RELEASE, "length of description (%d)", cur_pos);
3338 dis_len = cur_pos + 1;
3340 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3342 if (tmp_desc != NULL) {
3343 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3344 debug_msg(DEBUG, "tmp_desc %s\n", tmp_desc);
3346 /*convert description*/
3347 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3348 debug_msg(DEBUG, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3349 mmfile_free(tmp_desc);
3351 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3354 imgstartOffset += cur_pos;
3356 pInfo->imageInfo.imgDesLen = 0;
3359 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3360 imgstartOffset++; /* endofDesceriptionType(1byte) */
3362 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
3366 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3368 if (realCpyFrameNum - imgstartOffset > 0) {
3369 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3370 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3372 if (pInfo->imageInfo.pImageBuf != NULL) {
3373 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3374 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3377 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3378 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3380 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3385 checkImgMimeTypeMax = 0;
3388 pInfo->tagV2Info.bImageMarked = true;
3390 debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3395 debug_msg(RELEASE, "mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
3399 curPos += purelyFramelen;
3400 if (purelyFramelen != 0)
3401 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3404 if (pExtContent) _FREE_EX(pExtContent);
3405 memset(CompTmp, 0, 4);
3406 if (curPos < taglen) {
3407 needToloopv2taglen -= oneFrameLen;
3410 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3414 realCpyFrameNum = 0;
3415 textEncodingType = 0;
3421 release_characterset_array(charset_array);
3431 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3433 char *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
3434 bool bAdditionGenre = false /*, bMpegAudioFrame = false*/;
3435 int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
3437 char *pGenreForUTF16;
3439 unsigned char genre = pInfo->genre;
3441 /* for Genre Info */
3442 if (pInfo->tagV2Info.bGenreMarked == false) {
3443 if (pInfo->bV1tagFound == true) {
3444 debug_msg(RELEASE, "Genre: %d\n", genre);
3449 if (MpegAudio_Genre[genre] != NULL) {
3450 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
3451 if (pInfo->genreLen > 0) {
3452 /* Give space for NULL character. Hence added "+1" */
3453 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3454 if (pInfo->pGenre) {
3455 strncpy(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen);
3456 pInfo->pGenre[pInfo->genreLen] = '\0';
3461 debug_msg(RELEASE, "Genre was not Found.\n");
3463 } else if (pInfo->tagV2Info.bGenreMarked == true) {
3464 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
3465 pInfo->pGenre[pInfo->genreLen + 1] = '\0';
3466 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
3468 pGenreForUTF16 = (char *)pInfo->pGenre;
3470 if (WmConvert2LCode(mpegAudioGenre, sizeof(char) * AV_WM_LOCALCODE_SIZE_MAX * (pInfo->genreLen + 1), pGenreForUTF16)) {
3471 pInfo->genreLen = strlen(mpegAudioGenre);
3472 mpegAudioGenre[pInfo->genreLen] = '\0';
3476 debug_msg(RELEASE, "pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
3478 if (pInfo->pGenre) {
3479 pInfo->genreLen = strlen(pInfo->pGenre);
3480 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3481 if (mpegAudioGenre != NULL) {
3482 mpegAudioGenre[pInfo->genreLen] = '\0';
3483 strncpy(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen);
3486 pInfo->genreLen = 0;
3490 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3493 if (mpegAudioGenre != NULL) {
3496 * (XXX) XXX is 0 - 148
3498 pInfo->genreLen = strlen(mpegAudioGenre);
3499 if (pInfo->genreLen >= 3 &&
3500 mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
3501 bAdditionGenre = true;
3502 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
3503 if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
3504 bAdditionGenre = false;
3510 if (bAdditionGenre == true) {
3511 idv2IntGenre = atoi(mpegAudioGenre + 1);
3513 if (idv2IntGenre > 147 || idv2IntGenre < 0)
3516 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
3517 pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
3518 if (pInfo->genreLen > 0) {
3519 /* Give space for NULL character. Hence added "+1" */
3520 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3521 if (pInfo->pGenre) {
3522 strncpy(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen);
3523 pInfo->pGenre[pInfo->genreLen] = 0;
3527 debug_msg(RELEASE, "pInfo->pGenre = %s\n", pInfo->pGenre);
3528 } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
3533 /* Give space for NULL character. Hence added "+1" */
3534 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3535 if (pInfo->pGenre) {
3536 strncpy(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen);
3537 pInfo->pGenre[pInfo->genreLen] = '\0';
3539 debug_msg(RELEASE, "pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
3541 debug_msg(RELEASE, "Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
3544 debug_msg(RELEASE, "mpegAudioGenre = %s\n", mpegAudioGenre);
3547 _FREE_EX(mpegAudioGenre);
3550 debug_msg(RELEASE, "Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
3555 void mm_file_free_synclyrics_list(GList *synclyrics_list)
3559 AvSynclyricsInfo *synclyrics_info = NULL;
3561 if (synclyrics_list == NULL) {
3565 list_len = g_list_length(synclyrics_list);
3566 for (idx = 0; idx < list_len; idx++) {
3567 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
3569 if (synclyrics_info != NULL) {
3570 mmfile_free(synclyrics_info->lyric_info);
3571 mmfile_free(synclyrics_info);
3575 if (synclyrics_list != NULL) {
3576 g_list_free(synclyrics_list);
3577 synclyrics_list = NULL;