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.
29 #include "mm_file_debug.h"
30 #include "mm_file_utils.h"
32 #define ENABLE_ITUNES_META /*All itunes metadata extracted by ffmpeg. see mov_read_udta_string() but Some cover art not support. */
34 typedef struct _mmfilemp4basicboxheader {
37 long long start_offset; /*huge file*/
38 } MMFILE_MP4_BASIC_BOX_HEADER;
40 typedef struct _mmfilemp4ftpybox {
41 unsigned int major_brand;
42 unsigned short major_version;
43 unsigned short minor_version;
44 unsigned int *compatiable_brands;
48 eMMFILE_3GP_TAG_TITLE = 0x01,
49 eMMFILE_3GP_TAG_CAPTION = 0x02,
50 eMMFILE_3GP_TAG_COPYRIGHT = 0x03,
51 eMMFILE_3GP_TAG_PERFORMER = 0x04,
52 eMMFILE_3GP_TAG_AUTHOR = 0x05,
53 eMMFILE_3GP_TAG_GENRE = 0x06,
54 } eMMFILE_3GP_TEXT_TAG;
56 typedef struct _mmfile3gptagtextbox {
57 unsigned char version;
58 unsigned char flag[3];
59 unsigned char language[2];
61 } MMFILE_3GP_TEXT_TAGBOX;
63 typedef struct _mmfile3gptagyearbox {
64 unsigned char version;
65 unsigned char flag[3];
67 } MMFILE_3GP_YEAR_TAGBOX;
69 typedef struct _mmfile3gptagalbumbox {
70 unsigned char version;
71 unsigned char flag[3];
72 unsigned char language[2];
73 unsigned char *albumtile;
74 unsigned char trackNumber;
75 } MMFILE_3GP_ALBUM_TAGBOX;
77 typedef struct _mmfile3gpratingbox {
78 unsigned char version;
79 unsigned char flag[3];
80 unsigned int ratingEntity;
81 unsigned int ratingCriteria;
82 unsigned char language[2];
83 unsigned char *ratingInfo;
84 } MMFILE_3GP_RATING_TAGBOX;
86 typedef struct _mmfile3gpclsfbox {
87 unsigned char version;
88 unsigned char flag[3];
89 unsigned int classificationEntity;
90 unsigned int classificationTable;
91 unsigned char language[2];
92 unsigned char *classificationInfo;
93 } MMFILE_3GP_CLASSIFICATION_TAGBOX;
95 typedef struct _mmfile3gphdlrbox {
97 unsigned int pre_defined;
98 unsigned int handler_type;
99 unsigned int reserved[3];
100 unsigned char *boxname;
101 } MMFILE_3GP_HANDLER_BOX;
103 typedef struct _mmfileidv2box {
104 unsigned char version;
105 unsigned char flag[3];
106 unsigned char language[2];
107 unsigned char *id3v2Data;
108 } MMFILE_3GP_ID3V2_BOX;
110 typedef struct _mmfilelocibox {
111 unsigned char version;
112 unsigned char flag[3];
113 unsigned char language[2];
119 unsigned char *astronomical_body;
120 unsigned char *additional_notes;
121 } MMFILE_3GP_LOCATION_TAGBOX;
123 typedef struct _mmfilesmtabox {
126 unsigned char saut[4];
128 } MMFILE_M4A_SMTA_TAGBOX;
130 #define MMFILE_MP4_BASIC_BOX_HEADER_LEN 8
131 #define MMFILE_MP4_MOVIE_HEADER_BOX_LEN 96
132 #define MMFILE_MP4_HDLR_BOX_LEN 24
133 #define MMFILE_MP4_STSZ_BOX_LEN 20
134 #define MMFILE_MP4_MP4VBOX_LEN 80
135 #define MMFILE_MP4_MP4ABOX_LEN 28
136 #define MMFILE_3GP_TEXT_TAGBOX_LEN 6
137 #define MMFILE_3GP_YEAR_TAGBOX_LEN 6
138 #define MMFILE_3GP_ALBUM_TAGBOX_LEN 6
139 #define MMFILE_3GP_RATING_TAGBOX_LEN 14
140 #define MMFILE_3GP_CLASS_TAGBOX_LEN 14
141 #define MMFILE_3GP_HANDLER_BOX_LEN 24
142 #define MMFILE_3GP_ID3V2_BOX_LEN 6
143 #define MMFILE_SYNC_LYRIC_INFO_MIN_LEN 5
146 #define FOURCC(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
148 /*#define MIN(a, b) (((a) < (b)) ? (a):(b))*/
150 #define GENRE_COUNT 149
152 static const char *MpegAudio_Genre[GENRE_COUNT] = {"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal",
153 "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial",
154 "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
155 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
156 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
157 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
158 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
159 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
160 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
161 "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic",
162 "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove",
163 "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
164 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore",
165 "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian", "Heavy Metal", "Black Metal", "Crossover",
166 "Contemporary", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "Synthpop", "Unknown"
169 static unsigned char gTagJPEGHeader[] = {0xff, 0xd8, 0xff };
170 static unsigned char gTagPNGHeader[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
172 static int GetStringFromTextTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header, eMMFILE_3GP_TEXT_TAG eTag)
174 int ret = MMFILE_UTIL_FAIL; /*fail*/
175 MMFILE_3GP_TEXT_TAGBOX texttag = {0, };
178 char *temp_text = NULL;
180 if (!formatContext || !fp || !basic_header) {
181 debug_error("invalid param\n");
182 return MMFILE_UTIL_FAIL;
185 textBytes = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_TEXT_TAGBOX_LEN;
187 readed = mmfile_read(fp, (unsigned char *)&texttag, MMFILE_3GP_TEXT_TAGBOX_LEN);
188 if (readed != MMFILE_3GP_TEXT_TAGBOX_LEN) {
189 debug_error("read text tag header fail\n");
190 ret = MMFILE_UTIL_FAIL;
194 if (textBytes <= 1) { /* there exist only 00(null) */
195 debug_error("Text is NULL\n");
199 texttag.text = mmfile_malloc(textBytes);
201 debug_error("malloc fail for text box\n");
202 ret = MMFILE_UTIL_FAIL;
206 readed = mmfile_read(fp, (unsigned char *)texttag.text, textBytes);
207 if (readed != textBytes) {
208 debug_error("read text fail\n");
209 ret = MMFILE_UTIL_FAIL;
214 if ((texttag.text[0] == 0xFE) && (texttag.text[1] == 0xFF)) {
215 /* this char is UTF-16 */
216 unsigned int bytes_written = 0;
217 temp_text = mmfile_string_convert((const char *)&texttag.text[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
219 temp_text = mmfile_strdup((const char *)texttag.text);
223 case eMMFILE_3GP_TAG_TITLE: {
224 if (!formatContext->title) {
225 formatContext->title = temp_text;
229 case eMMFILE_3GP_TAG_CAPTION: {
230 if (!formatContext->description) {
231 formatContext->description = temp_text;
235 case eMMFILE_3GP_TAG_COPYRIGHT: {
236 if (!formatContext->copyright) {
237 formatContext->copyright = temp_text;
241 case eMMFILE_3GP_TAG_PERFORMER: {
242 if (!formatContext->artist) {
243 formatContext->artist = temp_text;
247 case eMMFILE_3GP_TAG_AUTHOR: {
248 if (!formatContext->author) {
249 formatContext->author = temp_text;
253 case eMMFILE_3GP_TAG_GENRE: {
254 if (!formatContext->genre) {
255 formatContext->genre = temp_text;
260 debug_warning("Not supported Text Tag type[%d]\n", eTag);
265 mmfile_free(texttag.text);
267 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
269 return MMFILE_UTIL_SUCCESS;
272 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
274 mmfile_free(texttag.text);
279 static int GetYearFromYearTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
281 #define MAX_YEAR_BUFFER 10
283 MMFILE_3GP_YEAR_TAGBOX yearbox = {0, };
284 char temp_year[MAX_YEAR_BUFFER] = {0, };
286 if (!formatContext || !fp || !basic_header) {
287 debug_error("invalid param\n");
288 return MMFILE_UTIL_FAIL;
291 readed = mmfile_read(fp, (unsigned char *)&yearbox, MMFILE_3GP_YEAR_TAGBOX_LEN);
292 if (readed != MMFILE_3GP_YEAR_TAGBOX_LEN) {
293 debug_error("read yeartag header fail\n");
297 if (!formatContext->year) {
298 yearbox.year = mmfile_io_be_int16(yearbox.year);
299 snprintf(temp_year, MAX_YEAR_BUFFER, "%d", yearbox.year);
300 temp_year[MAX_YEAR_BUFFER - 1] = '\0';
301 formatContext->year = mmfile_strdup((const char *)temp_year);
304 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
305 return MMFILE_UTIL_SUCCESS;
308 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
310 return MMFILE_UTIL_FAIL;
313 static int GetAlbumFromAlbumTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
315 int albumTitleLen = 0;
316 char *temp_text = NULL;
319 MMFILE_3GP_ALBUM_TAGBOX albumbox = {0, };
321 if (!formatContext || !fp || !basic_header) {
322 debug_error("invalid param\n");
323 return MMFILE_UTIL_FAIL;
326 readed = mmfile_read(fp, (unsigned char *)&albumbox, MMFILE_3GP_ALBUM_TAGBOX_LEN);
327 if (readed != MMFILE_3GP_ALBUM_TAGBOX_LEN) {
328 debug_error("read albumtag header fail\n");
332 albumTitleLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ALBUM_TAGBOX_LEN - 1; /* 1: track number */
333 if (albumTitleLen > 1) { /* there exist only 00(null) */
334 #ifdef __MMFILE_TEST_MODE__
335 debug_msg("albumTitleLen=%d\n", albumTitleLen);
338 albumbox.albumtile = mmfile_malloc(albumTitleLen + 1); /* 1: for null char */
339 if (!albumbox.albumtile) {
340 debug_error("malloc fail for album title text\n");
344 readed = mmfile_read(fp, (unsigned char *)albumbox.albumtile, albumTitleLen);
345 if (readed != albumTitleLen) {
346 debug_error("read album title fail\n");
350 if (albumbox.albumtile[albumTitleLen - 1] == '\0') { /* there exist track number */
354 readed = mmfile_read(fp, (unsigned char *)&(albumbox.albumtile[albumTitleLen]), 1);
356 debug_error("read album title fail\n");
359 albumbox.albumtile[albumTitleLen] = '\0';
363 if ((albumbox.albumtile[0] == 0xFE) && (albumbox.albumtile[1] == 0xFF)) {
364 /* this char is UTF-16 */
365 unsigned int bytes_written = 0;
366 temp_text = mmfile_string_convert((const char *)&albumbox.albumtile[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
368 temp_text = mmfile_strdup((const char *)albumbox.albumtile);
371 if (!formatContext->album) {
372 formatContext->album = temp_text;
375 #ifdef __MMFILE_TEST_MODE__
376 debug_msg("formatContext->album=%s, strlen=%d\n", formatContext->album, strlen(formatContext->album));
381 readed = mmfile_read(fp, (unsigned char *)&albumbox.trackNumber, 1);
383 debug_error("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("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("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("Rating Text is NULL\n");
433 ratingTag.ratingInfo = mmfile_malloc(ratinginfoLen);
434 if (!ratingTag.ratingInfo) {
435 debug_error("rating info error\n");
439 readed = mmfile_read(fp, (unsigned char *)ratingTag.ratingInfo, ratinginfoLen);
440 if (readed != ratinginfoLen) {
441 debug_error("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("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("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("Classification Text is NULL\n");
498 classTag.classificationInfo = mmfile_malloc(classinfoLen);
499 if (!classTag.classificationInfo) {
500 debug_error("class info error\n");
504 readed = mmfile_read(fp, (unsigned char *)classTag.classificationInfo, classinfoLen);
505 if (readed != classinfoLen) {
506 debug_error("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("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("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("too small buffer\n");
605 buffer = mmfile_malloc(bufferLen);
607 debug_error("buffer malloc error\n");
611 readed = mmfile_read(fp, (unsigned char *)buffer, bufferLen);
612 if (readed != bufferLen) {
613 debug_error("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 #ifdef __MMFILE_TEST_MODE__
637 debug_msg("long: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 0), *(p + 1), *(p + 2), *(p + 3));
638 debug_msg("lati: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 4), *(p + 5), *(p + 6), *(p + 7));
639 debug_msg("alti: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 8), *(p + 9), *(p + 10), *(p + 11));
642 ilong = mmfile_io_be_uint32(*(unsigned int *)p);
643 ilati = mmfile_io_be_uint32(*(unsigned int *)(p + 4));
644 ialti = mmfile_io_be_uint32(*(unsigned int *)(p + 8));
646 flong = (float)ilong / (1 << 16);
647 flati = (float)ilati / (1 << 16);
648 falti = (float)ialti / (1 << 16);
651 lociTag.longitude = flong;
653 lociTag.latitude = flati;
655 lociTag.altitude = falti;
659 /*astronomical body*/
660 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + 1));
662 if (p[0] == 0xFE && p[1] == 0xFF) {
663 lociTag.astronomical_body = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
665 lociTag.astronomical_body = (unsigned char *)mmfile_strdup((const char *)p);
674 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + astro_sz));
676 if (p[0] == 0xFE && p[1] == 0xFF) {
677 lociTag.additional_notes = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
679 lociTag.additional_notes = (unsigned char *)mmfile_strdup((const char *)p);
685 #ifdef __MMFILE_TEST_MODE__
686 debug_msg("** Location Information **\n");
687 debug_msg("Name : %s\n", lociTag.name);
688 debug_msg("Role : %d (0: shooting, 1: real, 2: fictional, other: reserved)\n", lociTag.role);
689 debug_msg("Longitude : %16.16f\n", lociTag.longitude);
690 debug_msg("Latitude : %16.16f\n", lociTag.latitude);
691 debug_msg("Altitude : %16.16f\n", lociTag.altitude);
692 debug_msg("Astronomical body: %s\n", lociTag.astronomical_body);
693 debug_msg("Additional notes : %s\n", lociTag.additional_notes);
696 formatContext->longitude = lociTag.longitude;
697 formatContext->latitude = lociTag.latitude;
698 formatContext->altitude = lociTag.altitude;
701 mmfile_free(lociTag.name);
702 mmfile_free(lociTag.astronomical_body);
703 mmfile_free(lociTag.additional_notes);
705 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
706 return MMFILE_UTIL_SUCCESS;
709 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
711 mmfile_free(lociTag.name);
712 mmfile_free(lociTag.astronomical_body);
713 mmfile_free(lociTag.additional_notes);
715 return MMFILE_UTIL_FAIL;
718 static int GetSAUTInfoFromSMTATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
720 MMFILE_M4A_SMTA_TAGBOX smtaTag = {0, };
723 if (!formatContext || !fp || !basic_header) {
724 debug_error("invalid param\n");
725 return MMFILE_UTIL_FAIL;
728 readed = mmfile_read(fp, (unsigned char *)&smtaTag, sizeof(MMFILE_M4A_SMTA_TAGBOX));
729 if (readed != sizeof(MMFILE_M4A_SMTA_TAGBOX)) {
730 debug_error("read smta tag header fail\n");
734 smtaTag.length = mmfile_io_be_uint32(smtaTag.length);
735 smtaTag.value = mmfile_io_be_uint32(smtaTag.value);
736 #ifdef __MMFILE_TEST_MODE__
737 debug_msg("Len : 0x%x", smtaTag.length);
738 debug_msg("Saut : 0x%x 0x%x 0x%x 0x%x", smtaTag.saut[0], smtaTag.saut[1], smtaTag.saut[2], smtaTag.saut[3]);
739 debug_msg("Value : 0x%x", smtaTag.value);
742 if (smtaTag.saut[0] == 's'
743 && smtaTag.saut[1] == 'a'
744 && smtaTag.saut[2] == 'u'
745 && smtaTag.saut[3] == 't') {
746 if (smtaTag.value == 0x01) {
747 #ifdef __MMFILE_TEST_MODE__
748 debug_msg("This has saut tag and valid value");
750 formatContext->smta = 1;
752 debug_error("This has saut tag and but invalid value");
756 debug_error("This hasn't saut tag and valid value");
760 return MMFILE_UTIL_SUCCESS;
763 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
765 return MMFILE_UTIL_FAIL;
768 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
770 unsigned int value = 0;
773 if (!formatContext || !fp || !basic_header) {
774 debug_error("invalid param\n");
775 return MMFILE_UTIL_FAIL;
778 readed = mmfile_read(fp, (unsigned char *)&value, sizeof(unsigned int));
779 if (readed != sizeof(unsigned int)) {
780 debug_error("read cdis tag header fail\n");
784 value = mmfile_io_be_uint32(value);
786 #ifdef __MMFILE_TEST_MODE__
787 debug_msg("Value : 0x%x", value);
791 #ifdef __MMFILE_TEST_MODE__
792 debug_msg("This has cdis tag and valid value");
794 formatContext->cdis = 1;
796 debug_error("This has cdis tag and but invalid value");
800 return MMFILE_UTIL_SUCCESS;
803 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
805 return MMFILE_UTIL_FAIL;
808 static int GetTagFromMetaBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
811 MMFILE_MP4_BASIC_BOX_HEADER hdlrBoxHeader = {0, };
812 MMFILE_MP4_BASIC_BOX_HEADER id3v2BoxHeader = {0, };
813 MMFILE_3GP_ID3V2_BOX id3v2Box = {0, };
814 AvFileContentInfo tagInfo = {0, };
815 unsigned char tagVersion = 0;
816 bool versionCheck = false;
818 unsigned int meta_version = 0;
819 MMFILE_3GP_HANDLER_BOX hdlrBox = {0, };
820 unsigned int encSize = 0;
822 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
827 readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
829 debug_error("read meta box version\n");
834 readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
835 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
836 debug_error("read hdlr box header\n");
840 if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
841 debug_warning("meta type is not hdlr\n");
845 hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
846 hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
848 readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
849 if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
850 debug_error("read hdlr box\n");
854 hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
857 * check tag type (ID3v2 or iTunes)
859 if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
860 #ifdef __MMFILE_TEST_MODE__
861 debug_msg("ID3v2 tag detected.\n");
865 #ifdef ENABLE_ITUNES_META
868 } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
869 mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
871 #ifdef __MMFILE_TEST_MODE__
872 debug_msg("Apple iTunes tag detected by mdir.\n");
875 #ifdef ENABLE_ITUNES_META
879 debug_warning("unknown meta type. 4CC:[%c%c%c%c]\n", ((char *)&hdlrBox.handler_type)[0],
880 ((char *)&hdlrBox.handler_type)[1],
881 ((char *)&hdlrBox.handler_type)[2],
882 ((char *)&hdlrBox.handler_type)[3]);
886 #ifdef ENABLE_ITUNES_META
887 if (!id3_meta && !iTunes_meta) {
889 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
890 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
891 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
893 const char *ilst_box = "ilst";
894 int buf_size = strlen(ilst_box);
896 unsigned char read_buf[buf_size + 1];
897 memset(read_buf, 0x00, buf_size + 1);
900 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR); /*+4 is hdlr size field */
902 readed = mmfile_read(fp, read_buf, buf_size); /* to find 'ilst' */
903 if (readed != buf_size) {
904 debug_error("read fail [%d]\n", readed);
908 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
909 #ifdef __MMFILE_TEST_MODE__
910 debug_msg("Apple iTunes tag detected by ilst.\n");
918 #ifdef ENABLE_ITUNES_META
921 * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
929 #define _ITUNES_READ_BUF_SZ 20
930 #define _ITUNES_TRACK_NUM_SZ 4
931 #define _ITUNES_GENRE_NUM_SZ 4
932 #define _ITUNES_COVER_TYPE_JPEG 13
933 #define _ITUNES_COVER_TYPE_PNG 14
935 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
937 int cover_sz = 0, cover_type = 0, cover_found = 0;
938 /* int track_found = 0; */ /* , track_num = 0; */
939 /* int genre_found = 0; */ /* , genre_index = 0; */
940 /* int artist_found = 0; */ /* , artist_sz = 0; */
941 int limit = basic_header->size - hdlrBoxHeader.size;
942 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
944 /* 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++) { */
945 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
946 readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
947 if (readed != _ITUNES_READ_BUF_SZ)
950 /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
951 but ffmpeg does not support strange cover image.
952 only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
955 * Artist : Added 2010.10.28
957 if (artist_found == 0 &&
958 read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
959 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
962 artist_offset = mmfile_tell(fp);
963 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
965 #ifdef __MMFILE_TEST_MODE__
966 debug_msg("----------------------------------- artist found, offset=[%lld], size=[%d]\n", artist_offset, artist_sz);
973 if (track_found == 0 &&
974 read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
975 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
978 track_offset = mmfile_tell(fp);
980 #ifdef __MMFILE_TEST_MODE__
981 debug_msg("----------------------------------- Track found, offset=[%lld]\n", track_offset);
986 * Genre : Added 2010.10.27
988 /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
989 if (genre_found == 0 &&
990 read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
991 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
994 genre_offset = mmfile_tell(fp);
996 #ifdef __MMFILE_TEST_MODE__
997 debug_msg("----------------------------------- genre found, offset=[%lld]\n", genre_offset);
1006 if (cover_found == 0 &&
1007 read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
1008 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1011 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
1012 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
1014 cover_offset = mmfile_tell(fp);
1016 #ifdef __MMFILE_TEST_MODE__
1017 debug_msg("----------------------------------- cover_found found, offset=[%lld]\n", cover_offset);
1021 mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR); /*FIXME: poor search*/
1024 /*ffmpeg extract artist, tracknum, excep cover image. see mov_read_udta_string()*/
1027 if (artist_sz > 0) {
1028 mmfile_seek(fp, artist_offset, SEEK_SET);
1030 if (formatContext->artist) {
1031 #ifdef __MMFILE_TEST_MODE__
1032 debug_msg("----------------------------------- previous artist was [%s] \n", formatContext->artist);
1034 free(formatContext->artist);
1036 #ifdef __MMFILE_TEST_MODE__
1037 debug_msg("----------------------------------- new artist will be allocated with size (len+1) [%d] \n", artist_sz + 1);
1039 formatContext->artist = mmfile_malloc(artist_sz + 1);
1041 if (formatContext->artist) {
1042 readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1043 formatContext->artist[artist_sz] = '\0';
1045 #ifdef __MMFILE_TEST_MODE__
1046 debug_msg("----------------------------------- new artist is [%s] \n", formatContext->artist);
1049 if (readed != artist_sz) {
1050 debug_error("failed to read. ret = %d, in = %d\n", readed, artist_sz);
1051 mmfile_free(formatContext->artist);
1058 mmfile_seek(fp, track_offset, SEEK_SET);
1059 readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1060 if (readed != _ITUNES_TRACK_NUM_SZ) {
1061 debug_error("failed to read. ret = %d, in = %d\n", readed, _ITUNES_TRACK_NUM_SZ);
1063 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1064 if (!formatContext->tagTrackNum) {
1065 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1066 snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1067 formatContext->tagTrackNum = mmfile_strdup((const char *)read_buf);
1073 mmfile_seek(fp, genre_offset, SEEK_SET);
1074 readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1075 if (readed != _ITUNES_GENRE_NUM_SZ) {
1076 debug_error("failed to read. ret = %d, in = %d\n", readed, _ITUNES_GENRE_NUM_SZ);
1078 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1079 #ifdef __MMFILE_TEST_MODE__
1080 debug_msg("genre index=[%d] \n", genre_index);
1082 if (genre_index > 0 && genre_index < GENRE_COUNT) {
1083 if (!formatContext->genre) {
1084 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1085 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1086 #ifdef __MMFILE_TEST_MODE__
1087 debug_msg("genre string=[%s] \n", read_buf);
1089 formatContext->genre = mmfile_strdup((const char *)read_buf);
1097 1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1098 Music Cover Art Image Profile
1099 - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1100 - RGB (screen standard)
1101 - Minimum size of 600 x 600 pixels
1102 - Images must be at least 72 dpi
1104 2)I found below info from google.
1105 cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1107 3)So, FIXME when cover image format is tif!
1111 mmfile_seek(fp, cover_offset, SEEK_SET);
1113 formatContext->artwork = mmfile_malloc(cover_sz);
1114 formatContext->artworkSize = cover_sz;
1115 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1116 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1117 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1118 formatContext->artworkMime = mmfile_strdup("image/png");
1119 /*} else if(cover_type == _ITUNES_COVER_TYPE_TIF) {
1120 formatContext->artworkMime = mmfile_strdup("image/tif");*/
1122 debug_warning("Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1123 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1126 if (formatContext->artwork) {
1127 readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1128 if (readed != cover_sz) {
1129 debug_error("failed to read. ret = %d, in = %d\n", readed, cover_sz);
1130 mmfile_free(formatContext->artwork);
1131 formatContext->artworkSize = 0;
1132 mmfile_free(formatContext->artworkMime);
1138 /*reset seek position*/
1139 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1141 return MMFILE_UTIL_SUCCESS;
1149 /* skip hdlr box name */
1150 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1153 readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1154 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1155 debug_error("read id3v2 box header\n");
1159 id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1160 id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1162 if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1163 debug_warning("meta type is not id3v2\n");
1167 readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1168 if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1169 debug_error("read id3v2 box\n");
1173 id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1175 id3v2Box.id3v2Data = mmfile_malloc(id3v2Len);
1176 if (!id3v2Box.id3v2Data) {
1177 debug_error("malloc id3tag data error\n");
1181 readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1182 if (readed != id3v2Len) {
1183 debug_error("read id3tag data error\n");
1188 if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1189 debug_error("it is not id3tag\n");
1193 if (id3v2Box.id3v2Data[3] == 0xFF || id3v2Box.id3v2Data[4] == 0xFF ||
1194 id3v2Box.id3v2Data[6] >= 0x80 || id3v2Box.id3v2Data[7] >= 0x80 ||
1195 id3v2Box.id3v2Data[8] >= 0x80 || id3v2Box.id3v2Data[9] >= 0x80) {
1196 debug_error("it is not valid id3tag\n");
1200 tagVersion = id3v2Box.id3v2Data[3];
1201 if (tagVersion > 4) {
1202 debug_error("tag vesion is too high\n");
1206 encSize = mmfile_io_le_uint32((unsigned int)&id3v2Box.id3v2Data[6]);
1207 tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1208 tagInfo.tagV2Info.tagLen += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
1209 tagInfo.tagV2Info.tagVersion = tagVersion;
1210 tagInfo.fileLen = id3v2Len;
1212 /* set id3v2 data to formatContext */
1213 switch (tagVersion) {
1215 versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data);
1219 versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data);
1223 versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data);
1228 debug_error("tag vesion is not support\n");
1229 versionCheck = false;
1234 if (versionCheck == false) {
1235 debug_error("tag parsing is fail\n");
1239 if (!formatContext->title) formatContext->title = mmfile_strdup((const char *)tagInfo.pTitle);
1240 if (!formatContext->artist) formatContext->artist = mmfile_strdup((const char *)tagInfo.pArtist);
1241 if (!formatContext->author) formatContext->author = mmfile_strdup((const char *)tagInfo.pAuthor);
1242 if (!formatContext->copyright) formatContext->copyright = mmfile_strdup((const char *)tagInfo.pCopyright);
1243 if (!formatContext->comment) formatContext->comment = mmfile_strdup((const char *)tagInfo.pComment);
1244 if (!formatContext->album) formatContext->album = mmfile_strdup((const char *)tagInfo.pAlbum);
1245 if (!formatContext->album_artist) formatContext->album_artist = mmfile_strdup((const char *)tagInfo.pAlbum_Artist);
1246 if (!formatContext->year) formatContext->year = mmfile_strdup((const char *)tagInfo.pYear);
1247 if (!formatContext->genre) formatContext->genre = mmfile_strdup((const char *)tagInfo.pGenre);
1248 if (!formatContext->tagTrackNum) formatContext->tagTrackNum = mmfile_strdup((const char *)tagInfo.pTrackNum);
1249 if (!formatContext->composer) formatContext->composer = mmfile_strdup((const char *)tagInfo.pComposer);
1250 if (!formatContext->classification) formatContext->classification = mmfile_strdup((const char *)tagInfo.pContentGroup);
1251 if (!formatContext->conductor) formatContext->conductor = mmfile_strdup((const char *)tagInfo.pConductor);
1253 formatContext->artwork = mmfile_malloc(tagInfo.imageInfo.imageLen);
1254 if ((tagInfo.imageInfo.imageLen > 0) && formatContext->artwork) {
1255 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1256 memcpy(formatContext->artwork, tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1259 mm_file_free_AvFileContentInfo(&tagInfo);
1260 mmfile_free(id3v2Box.id3v2Data);
1262 /*reset seek position*/
1263 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1265 return MMFILE_UTIL_SUCCESS;
1271 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1272 mmfile_free(id3v2Box.id3v2Data);
1273 mm_file_free_AvFileContentInfo(&tagInfo);
1275 return MMFILE_UTIL_FAIL;
1279 #define BIG_CONTENT_BOX_SIZE_LEN 8
1280 EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
1282 MMFileIOHandle *fp = NULL;
1285 unsigned long long chunk_size = 0;
1287 ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1288 if (ret == MMFILE_UTIL_FAIL) {
1289 debug_error("error: mmfile_open\n");
1293 MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
1294 basic_header.start_offset = mmfile_tell(fp);
1296 while ((ret != MMFILE_UTIL_FAIL) && ((readed = mmfile_read(fp, (unsigned char *)&basic_header, MMFILE_MP4_BASIC_BOX_HEADER_LEN)) > 0)) {
1297 basic_header.size = mmfile_io_be_uint32(basic_header.size);
1298 basic_header.type = mmfile_io_le_uint32(basic_header.type);
1300 if (basic_header.size == 0) {
1301 debug_warning("header is invalid.\n");
1302 basic_header.size = readed;
1303 basic_header.type = 0;
1304 chunk_size = basic_header.size;
1305 } else if (basic_header.size == 1) {
1307 unsigned char temp[BIG_CONTENT_BOX_SIZE_LEN] = {0, };
1308 unsigned long long size = 0;
1310 mmfile_read(fp, (unsigned char *)&temp, BIG_CONTENT_BOX_SIZE_LEN);
1312 for(i = 0; i < BIG_CONTENT_BOX_SIZE_LEN; i++)
1313 size |= (unsigned long long)temp[i] << (BIG_CONTENT_BOX_SIZE_LEN - 1 - i) * BIG_CONTENT_BOX_SIZE_LEN;
1316 chunk_size = basic_header.size;
1319 #ifdef __MMFILE_TEST_MODE__
1320 debug_msg("START_OFFSET:[%lld] SIZE:[%d Byte] 4CC:[%c%c%c%c]\n",
1321 basic_header.start_offset, basic_header.size,
1322 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
1323 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3]);
1326 switch (basic_header.type) {
1327 case FOURCC('m', 'o', 'o', 'v'): {
1328 #ifdef __MMFILE_TEST_MODE__
1329 debug_msg("MPEG4: [moov] SIZE: [%lld]Byte\n", chunk_size);
1333 case FOURCC('u', 'd', 't', 'a'): {
1334 #ifdef __MMFILE_TEST_MODE__
1335 debug_msg("MPEG4: [udat] SIZE: [%lld]Byte\n", chunk_size);
1339 /*/////////////////////////////////////////////////////////////// */
1340 /* Extracting Tag Data // */
1341 /*/////////////////////////////////////////////////////////////// */
1342 case FOURCC('t', 'i', 't', 'l'): {
1343 #ifdef __MMFILE_TEST_MODE__
1344 debug_msg("MPEG4: [titl] SIZE: [%lld]Byte\n", chunk_size);
1346 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
1349 case FOURCC('d', 's', 'c', 'p'): {
1350 #ifdef __MMFILE_TEST_MODE__
1351 debug_msg("MPEG4: [dscp] SIZE: [%lld]Byte\n", chunk_size);
1353 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
1356 case FOURCC('c', 'p', 'r', 't'): {
1357 #ifdef __MMFILE_TEST_MODE__
1358 debug_msg("MPEG4: [cprt] SIZE: [%lld]Byte\n", chunk_size);
1360 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
1363 case FOURCC('p', 'e', 'r', 'f'): {
1364 #ifdef __MMFILE_TEST_MODE__
1365 debug_msg("MPEG4: [perf] SIZE: [%lld]Byte\n", chunk_size);
1367 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
1370 case FOURCC('a', 'u', 't', 'h'): {
1371 #ifdef __MMFILE_TEST_MODE__
1372 debug_msg("MPEG4: [auth] SIZE: [%lld]Byte\n", chunk_size);
1374 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
1377 case FOURCC('g', 'n', 'r', 'e'): {
1378 #ifdef __MMFILE_TEST_MODE__
1379 debug_msg("MPEG4: [gnre] SIZE: [%lld]Byte\n", chunk_size);
1381 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
1384 case FOURCC('a', 'l', 'b', 'm'): {
1385 #ifdef __MMFILE_TEST_MODE__
1386 debug_msg("MPEG4: [albm] SIZE: [%lld]Byte\n", chunk_size);
1388 GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
1391 case FOURCC('y', 'r', 'r', 'c'): {
1392 #ifdef __MMFILE_TEST_MODE__
1393 debug_msg("MPEG4: [yrrc] SIZE: [%lld]Byte\n", chunk_size);
1395 GetYearFromYearTagBox(formatContext, fp, &basic_header);
1398 case FOURCC('r', 't', 'n', 'g'): {
1399 #ifdef __MMFILE_TEST_MODE__
1400 debug_msg("MPEG4: [rtng] SIZE: [%lld]Byte\n", chunk_size);
1402 GetRatingFromRatingTagBox(formatContext, fp, &basic_header); /* not use */
1405 case FOURCC('c', 'l', 's', 'f'): {
1406 #ifdef __MMFILE_TEST_MODE__
1407 debug_msg("MPEG4: [clsf] SIZE: [%lld]Byte\n", chunk_size);
1409 GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
1412 case FOURCC('k', 'y', 'w', 'd'): {
1413 #ifdef __MMFILE_TEST_MODE__
1414 debug_msg("MPEG4: [kywd] SIZE: [%lld]Byte\n", chunk_size);
1416 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
1419 case FOURCC('l', 'o', 'c', 'i'): {
1420 #ifdef __MMFILE_TEST_MODE__
1421 debug_msg("MPEG4: [loci] SIZE: [%lld]Byte\n", chunk_size);
1423 GetLocationFromLociTagBox(formatContext, fp, &basic_header);
1426 /* Check smta in user data field to be compatible with android */
1427 case FOURCC('s', 'm', 't', 'a'): {
1428 #ifdef __MMFILE_TEST_MODE__
1429 debug_msg("MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
1431 GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
1434 /* Check smta in user data field to be compatible with android */
1435 case FOURCC('c', 'd', 'i', 's'): {
1436 #ifdef __MMFILE_TEST_MODE__
1437 debug_msg("MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
1439 GetValueFromCDISTagBox(formatContext, fp, &basic_header);
1442 /*/////////////////////////////////////////////////////////////// */
1443 /* Extracting ID3 Tag Data // */
1444 /*/////////////////////////////////////////////////////////////// */
1445 case FOURCC('m', 'e', 't', 'a'): {
1446 #ifdef __MMFILE_TEST_MODE__
1447 debug_msg("MPEG4: [meta] SIZE: [%lld]Byte\n", chunk_size);
1449 GetTagFromMetaBox(formatContext, fp, &basic_header);
1453 case FOURCC('t', 'r', 'a', 'k'): {
1454 #ifdef __MMFILE_TEST_MODE__
1455 debug_msg("MPEG4: [trak] SIZE: [%d]Byte\n", basic_header.size);
1459 case FOURCC('u', 'u', 'i', 'd'): {
1460 #ifdef __MMFILE_TEST_MODE__
1461 debug_msg("MPEG4: [uuid] SIZE: [%d]Byte\n", basic_header.size);
1463 if (!formatContext->is_360) {
1464 unsigned long uuid[4] = {0, };
1466 mmfile_read(fp, (unsigned char *)uuid, sizeof(uuid));
1468 if (mmfile_io_be_uint32(uuid[0]) == 0xffcc8263
1469 && mmfile_io_be_uint32(uuid[1]) == 0xf8554a93
1470 && mmfile_io_be_uint32(uuid[2]) == 0x8814587a
1471 && mmfile_io_be_uint32(uuid[3]) == 0x02521fdd) {
1472 formatContext->is_360 = 1;
1474 ret = mmfile_seek(fp, basic_header.start_offset + basic_header.size, SEEK_SET);
1481 #ifdef __MMFILE_TEST_MODE__
1482 debug_msg("4CC: Not Support [%c%c%c%c]. So skip it. Size [%lld Byte]\n",
1483 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
1484 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3], chunk_size);
1486 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
1491 if (ret == MMFILE_UTIL_FAIL) {
1492 debug_error("mmfile operation is error\n");
1497 basic_header.start_offset = mmfile_tell(fp);
1505 static char *get_string(const char *buf, int buf_size, int *bytes_written)
1509 char str[512] = {0, };
1512 for (i = 0; i < buf_size; i++) {
1516 if ((q - str) >= (int)sizeof(str) - 1)
1522 if (strlen(str) > 0) {
1523 *bytes_written = strlen(str);
1531 static bool is_numeric(const char *buf, int buf_size)
1536 for (idx = 0; idx < buf_size; idx++) {
1537 if (isdigit((int)buf[idx])) {
1548 char *rtrimN(char *pStr)
1551 pos = strlen(pStr) - 1;
1552 for (; pos >= 0; pos--) {
1553 if (pStr[pos] == 0x20) {
1560 return strdup(pStr);
1563 static bool make_characterset_array(char ***charset_array)
1565 char *locale = MMFileUtilGetLocale(NULL);
1567 *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
1569 if (*charset_array == NULL) {
1570 debug_error("calloc failed ");
1576 if (locale != NULL) {
1577 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
1579 debug_error("get locale failed");
1580 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
1583 (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
1584 (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
1585 (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
1590 static bool release_characterset_array(char **charset_array)
1594 for (i = 0; i < AV_ID3V2_MAX; i++) {
1595 if (charset_array[i] != NULL) {
1596 free(charset_array[i]);
1597 charset_array[i] = NULL;
1601 if (charset_array != NULL) {
1602 free(charset_array);
1603 charset_array = NULL;
1609 static void init_content_info(AvFileContentInfo *pInfo)
1611 pInfo->tagV2Info.bTitleMarked = false;
1612 pInfo->tagV2Info.bArtistMarked = false;
1613 pInfo->tagV2Info.bAlbumMarked = false;
1614 pInfo->tagV2Info.bAlbum_ArtistMarked = false;
1615 pInfo->tagV2Info.bYearMarked = false;
1616 pInfo->tagV2Info.bDescriptionMarked = false;
1617 pInfo->tagV2Info.bGenreMarked = false;
1618 pInfo->tagV2Info.bTrackNumMarked = false;
1619 pInfo->tagV2Info.bEncByMarked = false;
1620 pInfo->tagV2Info.bURLMarked = false;
1621 pInfo->tagV2Info.bCopyRightMarked = false;
1622 pInfo->tagV2Info.bOriginArtistMarked = false;
1623 pInfo->tagV2Info.bComposerMarked = false;
1624 pInfo->tagV2Info.bImageMarked = false;
1626 pInfo->tagV2Info.bRecDateMarked = false;
1627 pInfo->tagV2Info.bContentGroupMarked = false;
1629 pInfo->tagV2Info.bUnsyncLyricsMarked = false;
1630 pInfo->tagV2Info.bSyncLyricsMarked = false;
1631 pInfo->tagV2Info.bConductorMarked = false;
1632 pInfo->tagV2Info.bGenreUTF16 = false;
1634 pInfo->imageInfo.bURLInfo = false;
1635 pInfo->imageInfo.pImageBuf = NULL;
1636 pInfo->imageInfo.imageLen = 0;
1640 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo, unsigned char *buffer)
1642 const char *locale = MMFileUtilGetLocale(NULL);
1643 char *pFullStr = NULL;
1645 #ifdef __MMFILE_TEST_MODE__
1646 debug_msg("ID3tag v110--------------------------------------------------------------\n");
1649 if (pInfo->tagV2Info.bTitleMarked == false) {
1650 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
1651 if (pFullStr != NULL) {
1652 pInfo->pTitle = rtrimN(pFullStr);
1656 #ifdef __MMFILE_TEST_MODE__
1657 debug_msg("pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1661 if (pInfo->tagV2Info.bArtistMarked == false) {
1662 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
1663 if (pFullStr != NULL) {
1664 pInfo->pArtist = rtrimN(pFullStr);
1668 #ifdef __MMFILE_TEST_MODE__
1669 debug_msg("pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1673 if (pInfo->tagV2Info.bAlbumMarked == false) {
1674 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
1675 if (pFullStr != NULL) {
1676 pInfo->pAlbum = rtrimN(pFullStr);
1680 #ifdef __MMFILE_TEST_MODE__
1681 debug_msg("pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1685 if (pInfo->tagV2Info.bYearMarked == false) {
1687 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
1688 #ifdef __MMFILE_TEST_MODE__
1689 debug_msg("pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1692 if (pInfo->pYear == NULL) { /*Use same logic with ffmpeg*/
1693 pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
1694 #ifdef __MMFILE_TEST_MODE__
1695 debug_msg("pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1700 if (pInfo->tagV2Info.bDescriptionMarked == false) {
1701 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
1702 #ifdef __MMFILE_TEST_MODE__
1703 debug_msg("pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1706 if (pInfo->pComment == NULL) { /*Use same logic with ffmpeg*/
1707 pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
1708 #ifdef __MMFILE_TEST_MODE__
1709 debug_msg("pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1714 if (pInfo->tagV2Info.bTrackNumMarked == false) {
1715 pInfo->pTrackNum = mmfile_malloc(5);
1716 if (pInfo->pTrackNum != NULL) {
1717 pInfo->pTrackNum[4] = 0;
1718 snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
1719 pInfo->tracknumLen = strlen(pInfo->pTrackNum);
1720 #ifdef __MMFILE_TEST_MODE__
1721 debug_msg("pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1726 if (pInfo->tagV2Info.bGenreMarked == false) {
1727 pInfo->genre = buffer[127];
1728 #ifdef __MMFILE_TEST_MODE__
1729 debug_msg("pInfo->genre returned genre number (%d)\n", pInfo->genre);
1737 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
1739 unsigned long taglen = 0;
1740 unsigned long needToloopv2taglen;
1741 unsigned long oneFrameLen = 0;
1742 unsigned long v2numOfFrames = 0;
1743 unsigned long curPos = 0;
1745 unsigned char *pExtContent = NULL;
1746 unsigned long purelyFramelen = 0;
1747 unsigned int encodingOffSet = 0;
1748 int inx = 0, realCpyFrameNum = 0,
1749 /*checkImgMimeTypeMax = 0, */checkImgExtMax = 0,
1750 imgstartOffset = 0, tmp = 0;
1752 int textEncodingType = 0;
1754 char **charset_array = NULL;
1756 make_characterset_array(&charset_array);
1758 init_content_info(pInfo);
1760 taglen = pInfo->tagV2Info.tagLen;
1761 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
1762 curPos = MP3_TAGv2_HEADER_LEN;
1764 #ifdef __MMFILE_TEST_MODE__
1765 debug_msg("ID3tag v222--------------------------------------------------------------\n");
1767 if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
1769 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
1770 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
1771 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
1774 memcpy(CompTmp, &buffer[curPos], 3);
1777 oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
1778 oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
1779 | (unsigned long)buffer[5 + curPos];
1780 if (oneFrameLen > taglen - curPos)
1782 purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
1783 curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
1785 if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
1786 curPos += purelyFramelen;
1788 if (buffer[curPos - purelyFramelen] == 0x00) {
1790 textEncodingType = AV_ID3V2_ISO_8859;
1791 } else if (buffer[curPos - purelyFramelen] == 0x01) {
1793 textEncodingType = AV_ID3V2_UTF16;
1796 if (textEncodingType > AV_ID3V2_MAX) {
1797 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
1801 /*in order to deliver valid string to MP */
1802 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
1805 if (encodingOffSet < purelyFramelen) {
1806 realCpyFrameNum = purelyFramelen - encodingOffSet;
1807 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
1809 if (pExtContent == NULL) {
1810 debug_error("out of memory for pExtContent\n");
1814 memset(pExtContent, '\0', realCpyFrameNum + 3);
1816 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
1818 if (realCpyFrameNum > 0) {
1819 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
1820 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
1822 #ifdef __MMFILE_TEST_MODE__
1823 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1825 pInfo->tagV2Info.bTitleMarked = true;
1826 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
1827 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
1829 #ifdef __MMFILE_TEST_MODE__
1830 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1832 pInfo->tagV2Info.bArtistMarked = true;
1833 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
1834 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
1836 #ifdef __MMFILE_TEST_MODE__
1837 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
1839 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
1840 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
1841 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
1843 #ifdef __MMFILE_TEST_MODE__
1844 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
1846 pInfo->tagV2Info.bConductorMarked = true;
1847 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
1848 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
1850 #ifdef __MMFILE_TEST_MODE__
1851 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1853 pInfo->tagV2Info.bAlbumMarked = true;
1854 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
1855 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
1857 #ifdef __MMFILE_TEST_MODE__
1858 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1860 pInfo->tagV2Info.bYearMarked = true;
1861 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
1862 /*skip language data! */
1863 if (realCpyFrameNum > 4) {
1864 realCpyFrameNum -= 4;
1867 /*pExtContent[tmp+1] value should't have encoding value */
1868 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1869 if (pExtContent[tmp - 1] == 0x00)
1870 textEncodingType = AV_ID3V2_ISO_8859;
1872 textEncodingType = AV_ID3V2_UTF16;
1874 pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
1876 #ifdef __MMFILE_TEST_MODE__
1877 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1879 pInfo->tagV2Info.bDescriptionMarked = true;
1881 #ifdef __MMFILE_TEST_MODE__
1882 debug_msg("mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1886 #ifdef __MMFILE_TEST_MODE__
1887 debug_msg("mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1892 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
1893 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
1895 #ifdef __MMFILE_TEST_MODE__
1896 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
1899 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
1903 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
1906 sscanf(pInfo->pGenre, "%d", &int_genre);
1907 #ifdef __MMFILE_TEST_MODE__
1908 debug_msg("genre information is inteager [%d]\n", int_genre);
1911 /*Change int to string */
1912 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
1913 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
1914 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
1915 int tmp_genre_len = 0;
1917 memset(tmp_genre, 0, 6);
1918 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
1920 tmp_genre_len = strlen(tmp_genre);
1921 if (tmp_genre_len > 0) {
1922 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
1923 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
1924 if (pInfo->pGenre) {
1925 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
1926 pInfo->pGenre[tmp_genre_len] = 0;
1933 pInfo->tagV2Info.bGenreMarked = true;
1934 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
1935 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
1937 #ifdef __MMFILE_TEST_MODE__
1938 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1940 pInfo->tagV2Info.bTrackNumMarked = true;
1941 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
1942 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
1944 #ifdef __MMFILE_TEST_MODE__
1945 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
1947 pInfo->tagV2Info.bEncByMarked = true;
1948 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
1949 if (realCpyFrameNum > 4) {
1950 /*skip language data! */
1951 realCpyFrameNum -= 4;
1954 /*pExtContent[tmp+1] value should't have null value */
1955 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1956 if (pExtContent[tmp - 1] == 0x00)
1957 textEncodingType = AV_ID3V2_ISO_8859;
1959 textEncodingType = AV_ID3V2_UTF16;
1961 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
1963 #ifdef __MMFILE_TEST_MODE__
1964 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
1966 pInfo->tagV2Info.bURLMarked = true;
1968 #ifdef __MMFILE_TEST_MODE__
1969 debug_msg("mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1973 #ifdef __MMFILE_TEST_MODE__
1974 debug_msg("mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1978 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
1979 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
1981 #ifdef __MMFILE_TEST_MODE__
1982 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
1984 pInfo->tagV2Info.bCopyRightMarked = true;
1985 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
1986 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
1988 #ifdef __MMFILE_TEST_MODE__
1989 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
1991 pInfo->tagV2Info.bOriginArtistMarked = true;
1992 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
1993 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
1995 #ifdef __MMFILE_TEST_MODE__
1996 debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
1998 pInfo->tagV2Info.bComposerMarked = true;
1999 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2000 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2002 #ifdef __MMFILE_TEST_MODE__
2003 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2005 pInfo->tagV2Info.bRecDateMarked = true;
2006 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2007 if (pExtContent[0] != 0) {
2008 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
2009 pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
2011 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
2012 pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
2016 #ifdef __MMFILE_TEST_MODE__
2017 debug_msg("mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
2021 imgstartOffset += checkImgExtMax;
2023 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2024 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2026 imgstartOffset++;/*PictureType(1byte) */
2028 if (pExtContent[imgstartOffset] != 0x0) {
2031 int new_dis_len = 0;
2032 char *tmp_desc = NULL;
2035 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2036 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2037 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2040 /*check end of image description*/
2041 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2042 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2043 #ifdef __MMFILE_TEST_MODE__
2044 debug_msg("length of description (%d)", cur_pos);
2053 dis_len = cur_pos + 1;
2055 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2057 if (tmp_desc != NULL) {
2058 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2060 /*convert description*/
2061 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2062 mmfile_free(tmp_desc);
2064 #ifdef __MMFILE_TEST_MODE__
2065 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2067 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2070 imgstartOffset += cur_pos;
2072 pInfo->imageInfo.imgDesLen = 0;
2075 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2076 imgstartOffset++; /* endofDesceriptionType(1byte) */
2078 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2082 #ifdef __MMFILE_TEST_MODE__
2083 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2086 if (realCpyFrameNum - imgstartOffset > 0) {
2087 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2088 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2090 if (pInfo->imageInfo.pImageBuf != NULL) {
2091 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2092 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2095 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2096 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2098 #ifdef __MMFILE_TEST_MODE__
2099 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2104 /*checkImgMimeTypeMax = 0;*/
2108 pInfo->tagV2Info.bImageMarked = true;
2115 curPos += purelyFramelen;
2116 if (purelyFramelen != 0)
2117 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2120 if (pExtContent) _FREE_EX(pExtContent);
2121 memset(CompTmp, 0, 4);
2122 if (curPos < taglen) {
2123 needToloopv2taglen -= oneFrameLen;
2126 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2129 realCpyFrameNum = 0;
2130 textEncodingType = 0;
2136 release_characterset_array(charset_array);
2146 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2148 unsigned long taglen = 0;
2149 unsigned long needToloopv2taglen;
2150 unsigned long oneFrameLen = 0;
2151 unsigned long v2numOfFrames = 0;
2152 unsigned long curPos = 0;
2154 unsigned char *pExtContent = NULL;
2155 unsigned long purelyFramelen = 0;
2156 unsigned int encodingOffSet = 0;
2157 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2158 int textEncodingType = 0;
2159 char **charset_array = NULL;
2160 const char *MIME_PRFIX = "image/";
2162 make_characterset_array(&charset_array);
2164 init_content_info(pInfo);
2166 taglen = pInfo->tagV2Info.tagLen;
2167 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2168 curPos = MP3_TAGv2_HEADER_LEN;
2170 #ifdef __MMFILE_TEST_MODE__
2171 debug_msg("ID3tag v223--------------------------------------------------------------\n");
2174 /* check Extended Header */
2175 if (buffer[5] & 0x40) {
2176 /* if extended header exists, skip it*/
2177 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2179 #ifdef __MMFILE_TEST_MODE__
2180 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2183 if (extendedHeaderLen > (int)(taglen - curPos)) {
2184 debug_error("extended header too long.\n");
2186 curPos += extendedHeaderLen;
2191 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2193 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2194 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2195 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2198 memcpy(CompTmp, &buffer[curPos], 4);
2201 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2202 oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2203 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2205 #ifdef __MMFILE_TEST_MODE__
2206 debug_msg("----------------------------------------------------------------------------------------------------\n");
2209 if (oneFrameLen > taglen - curPos)
2212 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2213 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2215 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2216 curPos += purelyFramelen;
2218 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2220 #ifdef __MMFILE_TEST_MODE__
2221 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2223 textEncodingType = AV_ID3V2_UTF16;
2224 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2226 #ifdef __MMFILE_TEST_MODE__
2227 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2229 textEncodingType = AV_ID3V2_UTF16_BE;
2230 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2232 #ifdef __MMFILE_TEST_MODE__
2233 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2235 textEncodingType = AV_ID3V2_UTF16;
2236 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2238 #ifdef __MMFILE_TEST_MODE__
2239 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2241 textEncodingType = AV_ID3V2_UTF16_BE;
2243 if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2244 #ifdef __MMFILE_TEST_MODE__
2245 debug_msg("encodingOffset will be set to 1\n");
2250 #ifdef __MMFILE_TEST_MODE__
2251 debug_msg("Finding encodingOffset\n");
2254 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2257 textEncodingType = AV_ID3V2_ISO_8859;
2258 #ifdef __MMFILE_TEST_MODE__
2259 debug_msg("this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2263 if (encodingOffSet < purelyFramelen) {
2264 realCpyFrameNum = purelyFramelen - encodingOffSet;
2265 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2267 if (pExtContent == NULL) {
2268 debug_msg("pExtContent malloc failed\n");
2272 memset(pExtContent, '\0', realCpyFrameNum + 3);
2274 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2275 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2276 #ifdef __MMFILE_TEST_MODE__
2277 debug_msg("get the new text ecoding type\n");
2279 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2283 if (textEncodingType > AV_ID3V2_MAX) {
2284 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2288 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2289 if (realCpyFrameNum > 0) {
2290 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2291 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2293 #ifdef __MMFILE_TEST_MODE__
2294 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2296 pInfo->tagV2Info.bTitleMarked = true;
2298 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2299 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2301 #ifdef __MMFILE_TEST_MODE__
2302 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2304 pInfo->tagV2Info.bArtistMarked = true;
2305 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2306 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2308 #ifdef __MMFILE_TEST_MODE__
2309 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2311 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2312 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2313 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2315 #ifdef __MMFILE_TEST_MODE__
2316 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2318 pInfo->tagV2Info.bConductorMarked = true;
2319 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2320 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2322 #ifdef __MMFILE_TEST_MODE__
2323 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2325 pInfo->tagV2Info.bAlbumMarked = true;
2326 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2327 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2329 #ifdef __MMFILE_TEST_MODE__
2330 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2332 pInfo->tagV2Info.bYearMarked = true;
2333 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2334 if (realCpyFrameNum > 3) {
2335 realCpyFrameNum -= 3;
2338 /*pExtContent[tmp+1] value should't have encoding value */
2339 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2340 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2341 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2342 realCpyFrameNum -= 4;
2346 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2347 realCpyFrameNum -= 2;
2349 textEncodingType = AV_ID3V2_UTF16;
2350 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2351 realCpyFrameNum -= 2;
2353 textEncodingType = AV_ID3V2_UTF16_BE;
2354 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2355 realCpyFrameNum -= 3;
2357 textEncodingType = AV_ID3V2_UTF16;
2358 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2359 realCpyFrameNum -= 3;
2361 textEncodingType = AV_ID3V2_UTF16_BE;
2363 #ifdef __MMFILE_TEST_MODE__
2364 debug_msg("pInfo->pComment Never Get Here!!\n");
2368 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2372 textEncodingType = AV_ID3V2_ISO_8859;
2375 #ifdef __MMFILE_TEST_MODE__
2376 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2379 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2381 #ifdef __MMFILE_TEST_MODE__
2382 debug_msg("failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2384 pInfo->commentLen = 0;
2387 #ifdef __MMFILE_TEST_MODE__
2388 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2390 pInfo->commentLen = 0;
2394 #ifdef __MMFILE_TEST_MODE__
2395 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2397 pInfo->tagV2Info.bDescriptionMarked = true;
2398 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2401 int copy_start_pos = tmp;
2402 AvSynclyricsInfo *synclyrics_info = NULL;
2403 GList *synclyrics_info_list = NULL;
2405 if (realCpyFrameNum > 5) {
2406 realCpyFrameNum -= 5;
2409 /*pExtContent[tmp+1] value should't have encoding value */
2410 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2411 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2412 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2413 realCpyFrameNum -= 4;
2417 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2418 realCpyFrameNum -= 2;
2420 textEncodingType = AV_ID3V2_UTF16;
2421 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2422 realCpyFrameNum -= 2;
2424 textEncodingType = AV_ID3V2_UTF16_BE;
2425 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2426 realCpyFrameNum -= 3;
2428 textEncodingType = AV_ID3V2_UTF16;
2429 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2430 realCpyFrameNum -= 3;
2432 textEncodingType = AV_ID3V2_UTF16_BE;
2434 #ifdef __MMFILE_TEST_MODE__
2435 debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
2439 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2443 textEncodingType = AV_ID3V2_ISO_8859;
2446 #ifdef __MMFILE_TEST_MODE__
2447 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2450 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2451 #ifdef __MMFILE_TEST_MODE__
2452 debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
2454 pInfo->syncLyricsNum = 0;
2456 if (textEncodingType == AV_ID3V2_UTF16) {
2457 debug_warning("[AV_ID3V2_UTF16] not implemented\n");
2458 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
2459 debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
2461 for (idx = 0; idx < realCpyFrameNum; idx++) {
2462 if (pExtContent[tmp + idx] == 0x00) {
2463 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
2465 if (synclyrics_info != NULL) {
2466 if (textEncodingType == AV_ID3V2_UTF8) {
2467 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
2468 if (synclyrics_info->lyric_info != NULL) {
2469 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
2470 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
2471 synclyrics_info->lyric_info[copy_len + 1] = '\0';
2474 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);
2477 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];
2479 copy_start_pos = tmp + idx + 1;
2480 #ifdef __MMFILE_TEST_MODE__
2481 debug_msg("[%d][%s] idx[%d], copy_len[%d] copy_start_pos[%d]", synclyrics_info->time_info, synclyrics_info->lyric_info, idx, copy_len, copy_start_pos);
2484 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
2489 pInfo->pSyncLyrics = synclyrics_info_list;
2490 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
2494 #ifdef __MMFILE_TEST_MODE__
2495 debug_msg("failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2497 pInfo->syncLyricsNum = 0;
2500 #ifdef __MMFILE_TEST_MODE__
2501 debug_msg("Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2503 pInfo->syncLyricsNum = 0;
2507 #ifdef __MMFILE_TEST_MODE__
2508 debug_msg("pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
2510 pInfo->tagV2Info.bSyncLyricsMarked = true;
2511 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
2512 char *lang_info = strndup((char *)pExtContent, 3);
2514 if (realCpyFrameNum > 3) {
2515 realCpyFrameNum -= 3;
2518 /*find start of lyrics */
2520 if (pExtContent[tmp] == 0x00) {
2521 if (pExtContent[tmp + 1] == 0x00) {
2522 realCpyFrameNum -= 2;
2532 /*pExtContent[tmp+1] value should't have encoding value */
2533 #ifdef __MMFILE_TEST_MODE__
2534 debug_msg("tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
2536 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2537 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2538 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2539 realCpyFrameNum -= 4;
2543 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2544 realCpyFrameNum -= 2;
2546 textEncodingType = AV_ID3V2_UTF16;
2547 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2548 realCpyFrameNum -= 2;
2550 textEncodingType = AV_ID3V2_UTF16_BE;
2551 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2552 realCpyFrameNum -= 3;
2554 textEncodingType = AV_ID3V2_UTF16;
2555 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2556 realCpyFrameNum -= 3;
2558 textEncodingType = AV_ID3V2_UTF16_BE;
2560 #ifdef __MMFILE_TEST_MODE__
2561 debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
2565 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2569 textEncodingType = AV_ID3V2_ISO_8859;
2572 #ifdef __MMFILE_TEST_MODE__
2573 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2576 char *char_set = NULL;
2577 if (textEncodingType == AV_ID3V2_ISO_8859) {
2578 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
2579 char_set = strdup("EUC-KR");
2581 char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
2583 _FREE_EX(lang_info);
2586 if (char_set == NULL) {
2587 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2589 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2593 #ifdef __MMFILE_TEST_MODE__
2594 debug_msg("failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2596 pInfo->unsynclyricsLen = 0;
2599 #ifdef __MMFILE_TEST_MODE__
2600 debug_msg("Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2602 pInfo->unsynclyricsLen = 0;
2606 #ifdef __MMFILE_TEST_MODE__
2607 debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
2609 pInfo->tagV2Info.bUnsyncLyricsMarked = true;
2610 mmfile_free(lang_info);
2611 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2612 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2614 #ifdef __MMFILE_TEST_MODE__
2615 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2618 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2622 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2625 sscanf(pInfo->pGenre, "%d", &int_genre);
2626 #ifdef __MMFILE_TEST_MODE__
2627 debug_msg("genre information is inteager [%d]\n", int_genre);
2630 /*Change int to string */
2631 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2632 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2633 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
2634 int tmp_genre_len = 0;
2636 memset(tmp_genre, 0, 6);
2637 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2639 tmp_genre_len = strlen(tmp_genre);
2640 if (tmp_genre_len > 0) {
2641 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2642 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2643 if (pInfo->pGenre) {
2644 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
2645 pInfo->pGenre[tmp_genre_len] = 0;
2652 pInfo->tagV2Info.bGenreMarked = true;
2653 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2654 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2656 #ifdef __MMFILE_TEST_MODE__
2657 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2659 pInfo->tagV2Info.bTrackNumMarked = true;
2660 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2661 pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2663 #ifdef __MMFILE_TEST_MODE__
2664 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2666 pInfo->tagV2Info.bEncByMarked = true;
2667 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2668 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2670 #ifdef __MMFILE_TEST_MODE__
2671 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2673 pInfo->tagV2Info.bURLMarked = true;
2674 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2675 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2677 #ifdef __MMFILE_TEST_MODE__
2678 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2680 pInfo->tagV2Info.bCopyRightMarked = true;
2681 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2682 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2684 #ifdef __MMFILE_TEST_MODE__
2685 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2687 pInfo->tagV2Info.bOriginArtistMarked = true;
2688 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2689 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2691 #ifdef __MMFILE_TEST_MODE__
2692 debug_msg("pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2694 pInfo->tagV2Info.bComposerMarked = true;
2695 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2696 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2698 #ifdef __MMFILE_TEST_MODE__
2699 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2701 pInfo->tagV2Info.bRecDateMarked = true;
2702 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2703 debug_msg("text encoding %d \n", textEncodingType);
2705 if (pExtContent[0] != '\0') {
2706 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
2707 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
2709 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
2710 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
2711 checkImgMimeTypeMax++;
2713 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
2715 pInfo->imageInfo.imgMimetypeLen = 0;
2716 #ifdef __MMFILE_TEST_MODE__
2717 debug_msg("APIC image's not included to MIME type\n");
2721 imgstartOffset += checkImgMimeTypeMax;
2723 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2724 pInfo->imageInfo.imgMimetypeLen = 0;
2725 debug_error("APIC NOT VALID");
2729 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2730 imgstartOffset++;/*endofMIME(1byte) */
2731 #ifdef __MMFILE_TEST_MODE__
2732 debug_msg("after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
2735 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2736 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2738 #ifdef __MMFILE_TEST_MODE__
2739 debug_msg("APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
2742 imgstartOffset++;/*PictureType(1byte) */
2743 #ifdef __MMFILE_TEST_MODE__
2744 debug_msg("after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
2747 if (pExtContent[imgstartOffset] != 0x0) {
2750 int new_dis_len = 0;
2751 char *tmp_desc = NULL;
2754 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2755 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2756 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2759 /*check end of image description*/
2760 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2761 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2762 #ifdef __MMFILE_TEST_MODE__
2763 debug_msg("length of description (%d)", cur_pos);
2772 dis_len = cur_pos + 1;
2774 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2775 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2777 /*convert description*/
2778 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2779 #ifdef __MMFILE_TEST_MODE__
2780 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2782 mmfile_free(tmp_desc);
2784 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2785 imgstartOffset += cur_pos;
2787 pInfo->imageInfo.imgDesLen = 0;
2788 #ifdef __MMFILE_TEST_MODE__
2789 debug_msg("APIC image's not included to Description!!!\n");
2793 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2794 imgstartOffset++; /* endofDesceriptionType(1byte) */
2796 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2800 #ifdef __MMFILE_TEST_MODE__
2801 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2804 if (realCpyFrameNum - imgstartOffset > 0) {
2805 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2806 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2808 if (pInfo->imageInfo.pImageBuf != NULL) {
2809 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2810 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2813 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2814 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2816 #ifdef __MMFILE_TEST_MODE__
2817 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2820 #ifdef __MMFILE_TEST_MODE__
2821 debug_msg("pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
2824 #ifdef __MMFILE_TEST_MODE__
2825 debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
2826 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2830 #ifdef __MMFILE_TEST_MODE__
2831 debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
2832 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2836 checkImgMimeTypeMax = 0;
2839 pInfo->tagV2Info.bImageMarked = true;
2842 #ifdef __MMFILE_TEST_MODE__
2843 debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
2849 #ifdef __MMFILE_TEST_MODE__
2850 debug_msg("All of the pExtContent Values are NULL\n");
2854 curPos += purelyFramelen;
2855 if (purelyFramelen != 0)
2856 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2857 #ifdef __MMFILE_TEST_MODE__
2858 debug_msg("This Frame's size is Zero! purelyFramelen(%d)\n", purelyFramelen);
2862 if (pExtContent) _FREE_EX(pExtContent);
2863 memset(CompTmp, 0, 4);
2865 if (curPos < taglen) {
2866 needToloopv2taglen -= oneFrameLen;
2869 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2872 realCpyFrameNum = 0;
2873 textEncodingType = 0;
2879 release_characterset_array(charset_array);
2889 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
2891 unsigned long taglen = 0;
2892 unsigned long needToloopv2taglen;
2893 unsigned long oneFrameLen = 0;
2894 unsigned long v2numOfFrames = 0;
2895 unsigned long curPos = 0;
2897 unsigned char *pExtContent = NULL;
2898 unsigned long purelyFramelen = 0;
2899 unsigned int encodingOffSet = 0;
2900 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2901 int textEncodingType = 0;
2902 char **charset_array = NULL;
2903 const char *MIME_PRFIX = "image/";
2905 make_characterset_array(&charset_array);
2907 init_content_info(pInfo);
2909 taglen = pInfo->tagV2Info.tagLen;
2910 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2911 curPos = MP3_TAGv2_HEADER_LEN;
2913 #ifdef __MMFILE_TEST_MODE__
2914 debug_msg("ID3tag v224--------------------------------------------------------------\n");
2917 /* check Extended Header */
2918 if (buffer[5] & 0x40) {
2919 /* if extended header exists, skip it*/
2920 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2922 #ifdef __MMFILE_TEST_MODE__
2923 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2926 if (extendedHeaderLen > (int)(taglen - curPos)) {
2927 debug_error("extended header too long.\n");
2929 curPos += extendedHeaderLen;
2933 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2935 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2936 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2937 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2940 memcpy(CompTmp, &buffer[curPos], 4);
2943 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2944 oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
2945 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
2946 if (oneFrameLen > taglen - curPos)
2949 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2950 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2952 #ifdef __MMFILE_TEST_MODE__
2953 debug_msg("-----------------------------------------------------------------------------------\n");
2956 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2957 curPos += purelyFramelen;
2959 /*in case of UTF 16 encoding */
2960 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
2961 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2963 textEncodingType = AV_ID3V2_UTF16;
2964 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2966 textEncodingType = AV_ID3V2_UTF16_BE;
2967 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2969 textEncodingType = AV_ID3V2_UTF16;
2970 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2972 textEncodingType = AV_ID3V2_UTF16_BE;
2974 /*in case of UTF-16 BE encoding */
2975 if (buffer[curPos - purelyFramelen] == 0x02) {
2977 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2978 encodingOffSet++;/*null skip! */
2979 textEncodingType = AV_ID3V2_UTF16_BE;
2981 /*in case of UTF8 encoding */
2982 else if (buffer[curPos - purelyFramelen] == 0x03) {
2984 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2985 encodingOffSet++;/*null skip! */
2986 textEncodingType = AV_ID3V2_UTF8;
2988 /*in case of ISO-8859-1 encoding */
2990 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
2992 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2993 encodingOffSet++;/*less than 0x20 value skip! */
2994 textEncodingType = AV_ID3V2_ISO_8859;
2998 if (encodingOffSet < purelyFramelen) {
2999 realCpyFrameNum = purelyFramelen - encodingOffSet;
3000 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
3002 if (pExtContent == NULL) {
3003 debug_error("out of memoryu for id3tag parse\n");
3007 memset(pExtContent, '\0', realCpyFrameNum + 3);
3009 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
3010 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
3011 #ifdef __MMFILE_TEST_MODE__
3012 debug_msg("get the new text ecoding type\n");
3014 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
3018 if (textEncodingType > AV_ID3V2_MAX) {
3019 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
3023 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
3025 if (realCpyFrameNum > 0) {
3026 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
3027 if (textEncodingType == AV_ID3V2_UTF8) {
3028 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3029 if (pInfo->pTitle) {
3030 memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
3031 pInfo->pTitle[realCpyFrameNum] = '\0';
3032 /*string copy with '\0'*/
3033 pInfo->titleLen = realCpyFrameNum;
3034 _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
3037 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
3040 #ifdef __MMFILE_TEST_MODE__
3041 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
3043 pInfo->tagV2Info.bTitleMarked = true;
3045 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
3046 if (textEncodingType == AV_ID3V2_UTF8) {
3047 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3048 if (pInfo->pArtist) {
3049 memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
3050 pInfo->pArtist[realCpyFrameNum] = '\0';
3051 /*string copy with '\0'*/
3052 pInfo->artistLen = realCpyFrameNum;
3053 _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
3056 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
3059 #ifdef __MMFILE_TEST_MODE__
3060 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
3062 pInfo->tagV2Info.bArtistMarked = true;
3063 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
3064 if (textEncodingType == AV_ID3V2_UTF8) {
3065 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3066 if (pInfo->pAlbum_Artist) {
3067 memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
3068 pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
3069 /*string copy with '\0'*/
3070 pInfo->album_artistLen = realCpyFrameNum;
3071 _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
3074 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3077 #ifdef __MMFILE_TEST_MODE__
3078 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3080 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3081 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3082 if (textEncodingType == AV_ID3V2_UTF8) {
3083 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3084 if (pInfo->pConductor) {
3085 memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
3086 pInfo->pConductor[realCpyFrameNum] = '\0';
3087 /*string copy with '\0'*/
3088 pInfo->conductorLen = realCpyFrameNum;
3089 _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
3092 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3095 #ifdef __MMFILE_TEST_MODE__
3096 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3098 pInfo->tagV2Info.bConductorMarked = true;
3099 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3100 if (textEncodingType == AV_ID3V2_UTF8) {
3101 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3102 if (pInfo->pAlbum) {
3103 memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
3104 pInfo->pAlbum[realCpyFrameNum] = '\0';
3105 /*string copy with '\0'*/
3106 pInfo->albumLen = realCpyFrameNum;
3107 _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
3110 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3113 #ifdef __MMFILE_TEST_MODE__
3114 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3116 pInfo->tagV2Info.bAlbumMarked = true;
3117 } 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 */
3118 if (textEncodingType == AV_ID3V2_UTF8) {
3119 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3121 memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
3122 pInfo->pYear[realCpyFrameNum] = '\0';
3123 /*string copy with '\0'*/
3124 pInfo->yearLen = realCpyFrameNum;
3125 _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
3128 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3131 #ifdef __MMFILE_TEST_MODE__
3132 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3134 pInfo->tagV2Info.bYearMarked = true;
3135 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3136 if (realCpyFrameNum > 3) {
3137 realCpyFrameNum -= 3;
3140 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3141 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3142 realCpyFrameNum -= 4;
3146 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3147 realCpyFrameNum -= 2;
3149 textEncodingType = AV_ID3V2_UTF16;
3151 #ifdef __MMFILE_TEST_MODE__
3152 debug_msg("pInfo->pComment Never Get Here!!\n");
3155 } else if (textEncodingType == AV_ID3V2_UTF8) {
3156 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3160 textEncodingType = AV_ID3V2_UTF8;
3162 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3166 textEncodingType = AV_ID3V2_ISO_8859;
3169 #ifdef __MMFILE_TEST_MODE__
3170 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3173 if (textEncodingType == AV_ID3V2_UTF8) {
3174 pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3175 if (pInfo->pComment) {
3176 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
3177 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
3178 pInfo->pComment[realCpyFrameNum] = '\0';
3179 /*string copy with '\0'*/
3180 pInfo->commentLen = realCpyFrameNum;
3181 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
3184 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3187 #ifdef __MMFILE_TEST_MODE__
3188 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3194 #ifdef __MMFILE_TEST_MODE__
3195 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3197 pInfo->tagV2Info.bDescriptionMarked = true;
3198 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3201 int copy_start_pos = tmp;
3202 AvSynclyricsInfo *synclyrics_info = NULL;
3203 GList *synclyrics_info_list = NULL;
3205 if (realCpyFrameNum > 5) {
3206 realCpyFrameNum -= 5;
3209 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3210 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3211 realCpyFrameNum -= 4;
3215 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3216 realCpyFrameNum -= 2;
3218 textEncodingType = AV_ID3V2_UTF16;
3220 #ifdef __MMFILE_TEST_MODE__
3221 debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
3224 } else if (textEncodingType == AV_ID3V2_UTF8) {
3225 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3229 textEncodingType = AV_ID3V2_UTF8;
3231 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3235 textEncodingType = AV_ID3V2_ISO_8859;
3238 #ifdef __MMFILE_TEST_MODE__
3239 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3242 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3243 #ifdef __MMFILE_TEST_MODE__
3244 debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3246 pInfo->syncLyricsNum = 0;
3248 if (textEncodingType == AV_ID3V2_UTF16) {
3249 debug_warning("[AV_ID3V2_UTF16] not implemented\n");
3250 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3251 debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
3253 for (idx = 0; idx < realCpyFrameNum; idx++) {
3254 if (pExtContent[tmp + idx] == 0x00) {
3255 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3257 if (textEncodingType == AV_ID3V2_UTF8) {
3258 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3259 if (synclyrics_info->lyric_info) {
3260 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3261 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3262 synclyrics_info->lyric_info[copy_len + 1] = '\0';
3265 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3268 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];
3270 copy_start_pos = tmp + idx + 1;
3271 #ifdef __MMFILE_TEST_MODE__
3272 debug_msg("[%d][%s] idx[%d], copy_len[%d] copy_start_pos[%d]", synclyrics_info->time_info, synclyrics_info->lyric_info, idx, copy_len, copy_start_pos);
3275 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3279 pInfo->pSyncLyrics = synclyrics_info_list;
3280 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3284 #ifdef __MMFILE_TEST_MODE__
3285 debug_msg("SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3290 pInfo->tagV2Info.bSyncLyricsMarked = true;
3291 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3292 if (realCpyFrameNum > 3) {
3293 realCpyFrameNum -= 3;
3296 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3297 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3298 realCpyFrameNum -= 4;
3302 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3303 realCpyFrameNum -= 2;
3305 textEncodingType = AV_ID3V2_UTF16;
3307 #ifdef __MMFILE_TEST_MODE__
3308 debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
3311 } else if (textEncodingType == AV_ID3V2_UTF8) {
3312 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3316 textEncodingType = AV_ID3V2_UTF8;
3318 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3322 textEncodingType = AV_ID3V2_ISO_8859;
3325 #ifdef __MMFILE_TEST_MODE__
3326 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3329 if (textEncodingType == AV_ID3V2_UTF8) {
3330 pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3332 if (pInfo->pUnsyncLyrics != NULL) {
3333 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3334 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3335 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3336 /*string copy with '\0'*/
3337 pInfo->unsynclyricsLen = realCpyFrameNum;
3338 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3340 debug_error("out of memoryu for SyncLyrics\n");
3343 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3346 #ifdef __MMFILE_TEST_MODE__
3347 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3353 #ifdef __MMFILE_TEST_MODE__
3354 debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3356 pInfo->tagV2Info.bDescriptionMarked = true;
3357 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3358 if (textEncodingType == AV_ID3V2_UTF8) {
3359 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3360 if (pInfo->pGenre) {
3361 memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3362 pInfo->pGenre[realCpyFrameNum] = '\0';
3363 /*string copy with '\0'*/
3364 pInfo->genreLen = realCpyFrameNum;
3365 _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3368 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3371 #ifdef __MMFILE_TEST_MODE__
3372 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3375 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3379 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3382 sscanf(pInfo->pGenre, "%d", &int_genre);
3383 #ifdef __MMFILE_TEST_MODE__
3384 debug_msg("genre information is inteager [%d]\n", int_genre);
3387 /*Change int to string */
3388 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3389 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3390 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3391 int tmp_genre_len = 0;
3393 memset(tmp_genre, 0, 6);
3394 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3396 tmp_genre_len = strlen(tmp_genre);
3397 if (tmp_genre_len > 0) {
3398 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3399 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3400 if (pInfo->pGenre) {
3401 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
3402 pInfo->pGenre[tmp_genre_len] = 0;
3409 pInfo->tagV2Info.bGenreMarked = true;
3410 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3411 if (textEncodingType == AV_ID3V2_UTF8) {
3412 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3413 if (pInfo->pTrackNum != NULL) {
3414 memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3415 pInfo->pTrackNum[realCpyFrameNum] = '\0';
3416 /*string copy with '\0'*/
3417 pInfo->tracknumLen = realCpyFrameNum;
3418 _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3421 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3425 #ifdef __MMFILE_TEST_MODE__
3426 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3428 pInfo->tagV2Info.bTrackNumMarked = true;
3429 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3430 if (textEncodingType == AV_ID3V2_UTF8) {
3431 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3432 if (pInfo->pEncBy != NULL) {
3433 memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3434 pInfo->pEncBy[realCpyFrameNum] = '\0';
3435 /*string copy with '\0'*/
3436 pInfo->encbyLen = realCpyFrameNum;
3437 _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3440 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3443 #ifdef __MMFILE_TEST_MODE__
3444 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3446 pInfo->tagV2Info.bEncByMarked = true;
3447 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3448 if (textEncodingType == AV_ID3V2_UTF8) {
3449 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3450 if (pInfo->pURL != NULL) {
3451 memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3452 pInfo->pURL[realCpyFrameNum] = '\0';
3453 /*string copy with '\0'*/
3454 pInfo->urlLen = realCpyFrameNum;
3455 _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3458 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3461 #ifdef __MMFILE_TEST_MODE__
3462 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3464 pInfo->tagV2Info.bURLMarked = true;
3465 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3466 if (textEncodingType == AV_ID3V2_UTF8) {
3467 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3468 if (pInfo->pCopyright != NULL) {
3469 memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3470 pInfo->pCopyright[realCpyFrameNum] = '\0';
3471 /*string copy with '\0'*/
3472 pInfo->copyrightLen = realCpyFrameNum;
3473 _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3476 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3479 #ifdef __MMFILE_TEST_MODE__
3480 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3482 pInfo->tagV2Info.bCopyRightMarked = true;
3483 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3484 if (textEncodingType == AV_ID3V2_UTF8) {
3485 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3486 if (pInfo->pOriginArtist != NULL) {
3487 memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3488 pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3489 /*string copy with '\0'*/
3490 pInfo->originartistLen = realCpyFrameNum;
3491 _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3494 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3497 #ifdef __MMFILE_TEST_MODE__
3498 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3500 pInfo->tagV2Info.bOriginArtistMarked = true;
3501 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3502 if (textEncodingType == AV_ID3V2_UTF8) {
3503 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3504 if (pInfo->pComposer != NULL) {
3505 memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3506 pInfo->pComposer[realCpyFrameNum] = '\0';
3507 /*string copy with '\0'*/
3508 pInfo->composerLen = realCpyFrameNum;
3509 _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3512 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3515 #ifdef __MMFILE_TEST_MODE__
3516 debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3518 pInfo->tagV2Info.bComposerMarked = true;
3519 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) { /*TYER(year) and TRDA are replaced by the TDRC */
3520 if (textEncodingType == AV_ID3V2_UTF8) {
3521 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3522 if (pInfo->pRecDate != NULL) {
3523 memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3524 pInfo->pRecDate[realCpyFrameNum] = '\0';
3525 /*string copy with '\0'*/
3526 pInfo->recdateLen = realCpyFrameNum;
3527 _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3530 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3533 #ifdef __MMFILE_TEST_MODE__
3534 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3536 pInfo->tagV2Info.bRecDateMarked = true;
3537 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3538 if (textEncodingType == AV_ID3V2_UTF8) {
3539 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3540 if (pInfo->pContentGroup != NULL) {
3541 memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3542 pInfo->pContentGroup[realCpyFrameNum] = '\0';
3543 /*string copy with '\0'*/
3544 pInfo->contentGroupLen = realCpyFrameNum;
3545 _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3548 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3550 #ifdef __MMFILE_TEST_MODE__
3551 debug_msg("pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3553 pInfo->tagV2Info.bContentGroupMarked = true;
3554 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3555 if (pExtContent[0] != '\0') {
3556 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3557 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3559 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3560 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3561 checkImgMimeTypeMax++;
3563 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3565 pInfo->imageInfo.imgMimetypeLen = 0;
3568 imgstartOffset += checkImgMimeTypeMax;
3570 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3571 pInfo->imageInfo.imgMimetypeLen = 0;
3572 debug_error("APIC NOT VALID");
3576 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3577 imgstartOffset++;/*endofMIME(1byte) */
3579 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3580 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3582 imgstartOffset++;/*PictureType(1byte) */
3584 if (pExtContent[imgstartOffset] != 0x0) {
3587 int new_dis_len = 0;
3588 char *tmp_desc = NULL;
3591 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3592 if (realCpyFrameNum < imgstartOffset + cur_pos) {
3593 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3596 /*check end of image description*/
3597 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
3598 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
3599 #ifdef __MMFILE_TEST_MODE__
3600 debug_msg("length of description (%d)", cur_pos);
3609 dis_len = cur_pos + 1;
3611 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3613 if (tmp_desc != NULL) {
3614 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3615 debug_msg("tmp_desc %s\n", tmp_desc);
3617 /*convert description*/
3618 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3619 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3620 mmfile_free(tmp_desc);
3622 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3625 imgstartOffset += cur_pos;
3627 pInfo->imageInfo.imgDesLen = 0;
3630 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3631 imgstartOffset++; /* endofDesceriptionType(1byte) */
3633 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
3637 #ifdef __MMFILE_TEST_MODE__
3638 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3641 if (realCpyFrameNum - imgstartOffset > 0) {
3642 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3643 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3645 if (pInfo->imageInfo.pImageBuf != NULL) {
3646 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3647 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3650 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3651 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3653 #ifdef __MMFILE_TEST_MODE__
3654 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3660 checkImgMimeTypeMax = 0;
3663 pInfo->tagV2Info.bImageMarked = true;
3665 #ifdef __MMFILE_TEST_MODE__
3666 debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3672 #ifdef __MMFILE_TEST_MODE__
3673 debug_msg("mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
3678 curPos += purelyFramelen;
3679 if (purelyFramelen != 0)
3680 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3683 if (pExtContent) _FREE_EX(pExtContent);
3684 memset(CompTmp, 0, 4);
3685 if (curPos < taglen) {
3686 needToloopv2taglen -= oneFrameLen;
3689 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3693 realCpyFrameNum = 0;
3694 textEncodingType = 0;
3700 release_characterset_array(charset_array);
3710 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3712 char *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
3713 bool bAdditionGenre = false /*, bMpegAudioFrame = false*/;
3714 int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
3716 char *pGenreForUTF16;
3718 unsigned char genre = pInfo->genre;
3720 /* for Genre Info */
3721 if (pInfo->tagV2Info.bGenreMarked == false) {
3722 if (pInfo->bV1tagFound == true) {
3723 #ifdef __MMFILE_TEST_MODE__
3724 debug_msg("Genre: %d\n", genre);
3729 if (MpegAudio_Genre[genre] != NULL) {
3730 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
3731 if (pInfo->genreLen > 0) {
3732 /* Give space for NULL character. Hence added "+1" */
3733 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3734 if (pInfo->pGenre) {
3735 strncpy(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen);
3736 pInfo->pGenre[pInfo->genreLen] = '\0';
3741 #ifdef __MMFILE_TEST_MODE__
3742 debug_msg("Genre was not Found.\n");
3745 } else if (pInfo->tagV2Info.bGenreMarked == true) {
3746 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
3747 pInfo->pGenre[pInfo->genreLen + 1] = '\0';
3748 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
3750 pGenreForUTF16 = (char *)pInfo->pGenre;
3752 if (WmConvert2LCode(mpegAudioGenre, sizeof(char) * AV_WM_LOCALCODE_SIZE_MAX * (pInfo->genreLen + 1), pGenreForUTF16)) {
3753 pInfo->genreLen = strlen(mpegAudioGenre);
3754 mpegAudioGenre[pInfo->genreLen] = '\0';
3758 #ifdef __MMFILE_TEST_MODE__
3759 debug_msg("pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
3761 if (pInfo->pGenre) {
3762 pInfo->genreLen = strlen(pInfo->pGenre);
3763 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3764 if (mpegAudioGenre != NULL) {
3765 mpegAudioGenre[pInfo->genreLen] = '\0';
3766 strncpy(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen);
3769 pInfo->genreLen = 0;
3773 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3776 if (mpegAudioGenre != NULL) {
3779 * (XXX) XXX is 0 - 148
3781 pInfo->genreLen = strlen(mpegAudioGenre);
3782 if (pInfo->genreLen >= 3 &&
3783 mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
3784 bAdditionGenre = true;
3785 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
3786 if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
3787 bAdditionGenre = false;
3793 if (bAdditionGenre == true) {
3794 idv2IntGenre = atoi(mpegAudioGenre + 1);
3796 if (idv2IntGenre > 147 || idv2IntGenre < 0)
3799 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
3800 pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
3801 if (pInfo->genreLen > 0) {
3802 /* Give space for NULL character. Hence added "+1" */
3803 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3804 if (pInfo->pGenre) {
3805 strncpy(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen);
3806 pInfo->pGenre[pInfo->genreLen] = 0;
3810 #ifdef __MMFILE_TEST_MODE__
3811 debug_msg("pInfo->pGenre = %s\n", pInfo->pGenre);
3813 } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
3818 /* Give space for NULL character. Hence added "+1" */
3819 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3820 if (pInfo->pGenre) {
3821 strncpy(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen);
3822 pInfo->pGenre[pInfo->genreLen] = '\0';
3824 #ifdef __MMFILE_TEST_MODE__
3825 debug_msg("pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
3828 #ifdef __MMFILE_TEST_MODE__
3829 debug_msg("Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
3833 #ifdef __MMFILE_TEST_MODE__
3834 debug_msg("mpegAudioGenre = %x\n", mpegAudioGenre);
3838 _FREE_EX(mpegAudioGenre);
3841 #ifdef __MMFILE_TEST_MODE__
3842 debug_msg("Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
3848 void mm_file_free_synclyrics_list(GList *synclyrics_list)
3852 AvSynclyricsInfo *synclyrics_info = NULL;
3854 if (synclyrics_list == NULL) {
3858 list_len = g_list_length(synclyrics_list);
3859 for (idx = 0; idx < list_len; idx++) {
3860 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
3862 if (synclyrics_info != NULL) {
3863 mmfile_free(synclyrics_info->lyric_info);
3864 mmfile_free(synclyrics_info);
3868 if (synclyrics_list != NULL) {
3869 g_list_free(synclyrics_list);
3870 synclyrics_list = NULL;