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"
170 static int GetStringFromTextTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header, eMMFILE_3GP_TEXT_TAG eTag)
172 int ret = MMFILE_UTIL_FAIL; /*fail*/
173 MMFILE_3GP_TEXT_TAGBOX texttag = {0, };
176 char *temp_text = NULL;
178 if (!formatContext || !fp || !basic_header) {
179 debug_error("invalid param\n");
180 return MMFILE_UTIL_FAIL;
183 textBytes = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_TEXT_TAGBOX_LEN;
185 readed = mmfile_read(fp, (unsigned char *)&texttag, MMFILE_3GP_TEXT_TAGBOX_LEN);
186 if (readed != MMFILE_3GP_TEXT_TAGBOX_LEN) {
187 debug_error("read text tag header fail\n");
188 ret = MMFILE_UTIL_FAIL;
192 if (textBytes <= 1) { /* there exist only 00(null) */
193 debug_error("Text is NULL\n");
197 texttag.text = mmfile_malloc(textBytes);
199 debug_error("malloc fail for text box\n");
200 ret = MMFILE_UTIL_FAIL;
204 readed = mmfile_read(fp, (unsigned char *)texttag.text, textBytes);
205 if (readed != textBytes) {
206 debug_error("read text fail\n");
207 ret = MMFILE_UTIL_FAIL;
212 if ((texttag.text[0] == 0xFE) && (texttag.text[1] == 0xFF)) {
213 /* this char is UTF-16 */
214 unsigned int bytes_written = 0;
215 temp_text = mmfile_string_convert((const char *)&texttag.text[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
217 temp_text = mmfile_strdup((const char *)texttag.text);
221 case eMMFILE_3GP_TAG_TITLE: {
222 if (!formatContext->title) {
223 formatContext->title = temp_text;
227 case eMMFILE_3GP_TAG_CAPTION: {
228 if (!formatContext->description) {
229 formatContext->description = temp_text;
233 case eMMFILE_3GP_TAG_COPYRIGHT: {
234 if (!formatContext->copyright) {
235 formatContext->copyright = temp_text;
239 case eMMFILE_3GP_TAG_PERFORMER: {
240 if (!formatContext->artist) {
241 formatContext->artist = temp_text;
245 case eMMFILE_3GP_TAG_AUTHOR: {
246 if (!formatContext->author) {
247 formatContext->author = temp_text;
251 case eMMFILE_3GP_TAG_GENRE: {
252 if (!formatContext->genre) {
253 formatContext->genre = temp_text;
258 debug_warning("Not supported Text Tag type[%d]\n", eTag);
263 mmfile_free(texttag.text);
265 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
267 return MMFILE_UTIL_SUCCESS;
270 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
272 mmfile_free(texttag.text);
277 static int GetYearFromYearTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
279 #define MAX_YEAR_BUFFER 10
281 MMFILE_3GP_YEAR_TAGBOX yearbox = {0, };
282 char temp_year[MAX_YEAR_BUFFER] = {0, };
284 if (!formatContext || !fp || !basic_header) {
285 debug_error("invalid param\n");
286 return MMFILE_UTIL_FAIL;
289 readed = mmfile_read(fp, (unsigned char *)&yearbox, MMFILE_3GP_YEAR_TAGBOX_LEN);
290 if (readed != MMFILE_3GP_YEAR_TAGBOX_LEN) {
291 debug_error("read yeartag header fail\n");
295 if (!formatContext->year) {
296 yearbox.year = mmfile_io_be_int16(yearbox.year);
297 snprintf(temp_year, MAX_YEAR_BUFFER, "%d", yearbox.year);
298 temp_year[MAX_YEAR_BUFFER - 1] = '\0';
299 formatContext->year = mmfile_strdup((const char *)temp_year);
302 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
303 return MMFILE_UTIL_SUCCESS;
306 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
308 return MMFILE_UTIL_FAIL;
311 static int GetAlbumFromAlbumTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
313 int albumTitleLen = 0;
314 char *temp_text = NULL;
317 MMFILE_3GP_ALBUM_TAGBOX albumbox = {0, };
319 if (!formatContext || !fp || !basic_header) {
320 debug_error("invalid param\n");
321 return MMFILE_UTIL_FAIL;
324 readed = mmfile_read(fp, (unsigned char *)&albumbox, MMFILE_3GP_ALBUM_TAGBOX_LEN);
325 if (readed != MMFILE_3GP_ALBUM_TAGBOX_LEN) {
326 debug_error("read albumtag header fail\n");
330 albumTitleLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ALBUM_TAGBOX_LEN - 1; /* 1: track number */
331 if (albumTitleLen > 1) { /* there exist only 00(null) */
332 #ifdef __MMFILE_TEST_MODE__
333 debug_msg("albumTitleLen=%d\n", albumTitleLen);
336 albumbox.albumtile = mmfile_malloc(albumTitleLen + 1); /* 1: for null char */
337 if (!albumbox.albumtile) {
338 debug_error("malloc fail for album title text\n");
342 readed = mmfile_read(fp, (unsigned char *)albumbox.albumtile, albumTitleLen);
343 if (readed != albumTitleLen) {
344 debug_error("read album title fail\n");
348 if (albumbox.albumtile[albumTitleLen - 1] == '\0') { /* there exist track number */
352 readed = mmfile_read(fp, (unsigned char *)&(albumbox.albumtile[albumTitleLen]), 1);
354 debug_error("read album title fail\n");
357 albumbox.albumtile[albumTitleLen] = '\0';
361 if ((albumbox.albumtile[0] == 0xFE) && (albumbox.albumtile[1] == 0xFF)) {
362 /* this char is UTF-16 */
363 unsigned int bytes_written = 0;
364 temp_text = mmfile_string_convert((const char *)&albumbox.albumtile[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
366 temp_text = mmfile_strdup((const char *)albumbox.albumtile);
369 if (!formatContext->album) {
370 formatContext->album = temp_text;
373 #ifdef __MMFILE_TEST_MODE__
374 debug_msg("formatContext->album=%s, strlen=%d\n", formatContext->album, strlen(formatContext->album));
379 readed = mmfile_read(fp, (unsigned char *)&albumbox.trackNumber, 1);
381 debug_error("read track number fail\n");
385 if (formatContext->tagTrackNum == 0) {
386 char tracknum[10] = {0, };
387 snprintf(tracknum, 10, "%d", albumbox.trackNumber);
389 formatContext->tagTrackNum = mmfile_strdup((const char *)tracknum);
393 mmfile_free(albumbox.albumtile);
394 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
396 return MMFILE_UTIL_SUCCESS;
399 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
400 mmfile_free(albumbox.albumtile);
402 return MMFILE_UTIL_FAIL;
405 static int GetRatingFromRatingTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
408 int ratinginfoLen = 0;
409 char *temp_text = NULL;
411 MMFILE_3GP_RATING_TAGBOX ratingTag = {0, };
413 if (!formatContext || !fp || !basic_header) {
414 debug_error("invalid param\n");
415 return MMFILE_UTIL_FAIL;
418 readed = mmfile_read(fp, (unsigned char *)&ratingTag, MMFILE_3GP_RATING_TAGBOX_LEN);
419 if (readed != MMFILE_3GP_RATING_TAGBOX_LEN) {
420 debug_error("read rating tag header fail\n");
424 ratinginfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_RATING_TAGBOX_LEN;
426 if (ratinginfoLen == 1) {
427 debug_error("Rating Text is NULL\n");
431 ratingTag.ratingInfo = mmfile_malloc(ratinginfoLen);
432 if (!ratingTag.ratingInfo) {
433 debug_error("rating info error\n");
437 readed = mmfile_read(fp, (unsigned char *)ratingTag.ratingInfo, ratinginfoLen);
438 if (readed != ratinginfoLen) {
439 debug_error("read rating info string fail\n");
444 if ((ratingTag.ratingInfo[0] == 0xFE) && (ratingTag.ratingInfo[1] == 0xFF)) {
445 /* this char is UTF-16 */
446 unsigned int bytes_written = 0;
447 temp_text = mmfile_string_convert((const char *)&ratingTag.ratingInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
449 temp_text = mmfile_strdup((const char *)ratingTag.ratingInfo);
452 if (!formatContext->rating) {
453 formatContext->rating = temp_text;
455 mmfile_free(temp_text);
458 mmfile_free(ratingTag.ratingInfo);
459 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
461 return MMFILE_UTIL_SUCCESS;
464 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
465 mmfile_free(ratingTag.ratingInfo);
467 return MMFILE_UTIL_FAIL;
471 static int GetClassficationFromClsfTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
473 int classinfoLen = 0;
475 char *temp_text = NULL;
476 MMFILE_3GP_CLASSIFICATION_TAGBOX classTag = {0, };
478 if (!formatContext || !fp || !basic_header) {
479 debug_error("invalid param\n");
480 return MMFILE_UTIL_FAIL;
483 readed = mmfile_read(fp, (unsigned char *)&classTag, MMFILE_3GP_CLASS_TAGBOX_LEN);
484 if (readed != MMFILE_3GP_CLASS_TAGBOX_LEN) {
485 debug_error("read classification tag header fail\n");
490 classinfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_CLASS_TAGBOX_LEN;
491 if (classinfoLen == 1) {
492 debug_error("Classification Text is NULL\n");
496 classTag.classificationInfo = mmfile_malloc(classinfoLen);
497 if (!classTag.classificationInfo) {
498 debug_error("class info error\n");
502 readed = mmfile_read(fp, (unsigned char *)classTag.classificationInfo, classinfoLen);
503 if (readed != classinfoLen) {
504 debug_error("read class info string fail\n");
509 if ((classTag.classificationInfo[0] == 0xFE) && (classTag.classificationInfo[1] == 0xFF)) {
510 /* this char is UTF-16 */
511 unsigned int bytes_written = 0;
512 temp_text = mmfile_string_convert((const char *)&classTag.classificationInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
514 temp_text = mmfile_strdup((const char *)classTag.classificationInfo);
517 if (!formatContext->classification) {
518 formatContext->classification = temp_text;
520 mmfile_free(temp_text);
523 mmfile_free(classTag.classificationInfo);
524 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
526 return MMFILE_UTIL_SUCCESS;
529 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
530 mmfile_free(classTag.classificationInfo);
532 return MMFILE_UTIL_FAIL;
536 * The Location Information box
537 * --------------------+-------------------+-----------------------------------+------
538 * Field Type Details Value
539 * --------------------+-------------------+-----------------------------------+------
540 * BoxHeader.Size Unsigned int(32)
541 * BoxHeader.Type Unsigned int(32) 'loci'
542 * BoxHeader.Version Unsigned int(8) 0
543 * BoxHeader.Flags Bit(24) 0
545 * Language Unsigned int(5)[3] Packed ISO-639-2/T language code
546 * Name String Text of place name
547 * Role Unsigned int(8) Non-negative value indicating role
549 * Longitude Unsigned int(32) Fixed-point value of the longitude
550 * Latitude Unsigned int(32) Fixed-point value of the latitude
551 * Altitude Unsigned int(32) Fixed-point value of the Altitude
552 * Astronomical_body String Text of astronomical body
553 * Additional_notes String Text of additional location-related
555 * --------------------+-------------------+-----------------------------------+------
557 static int _get_char_position(unsigned char *src, char ch, int max)
560 for (i = 0; i < max; i++) {
561 if (*(src + i) == ch)
568 static int GetLocationFromLociTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
571 MMFILE_3GP_LOCATION_TAGBOX lociTag = {0, };
574 unsigned char *buffer = NULL;
575 unsigned char *p = NULL;
577 unsigned int bytes_written = 0;
578 unsigned int name_sz = 0;
579 unsigned int astro_sz = 0;
581 int ilong, ilati, ialti;
582 float flong, flati, falti;
585 if (!formatContext || !fp || !basic_header) {
586 debug_error("invalid param\n");
587 return MMFILE_UTIL_FAIL;
590 readed = mmfile_read(fp, (unsigned char *)&lociTag, 6); /*6 = version + flag + pad + language */
592 debug_error("read location tag header fail\n");
596 /*buffer len = name + role + ... + additional notes length */
597 bufferLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - 6;
599 debug_error("too small buffer\n");
603 buffer = mmfile_malloc(bufferLen);
605 debug_error("buffer malloc error\n");
609 readed = mmfile_read(fp, (unsigned char *)buffer, bufferLen);
610 if (readed != bufferLen) {
611 debug_error("read location tag fail\n");
617 pos = _get_char_position(p, '\0', readed - (1 + 4 + 4 + 4 + 2));
619 if (p[0] == 0xFE && p[1] == 0xFF) {
620 lociTag.name = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
622 lociTag.name = (unsigned char *)mmfile_strdup((const char *)p);
634 #ifdef __MMFILE_TEST_MODE__
635 debug_msg("long: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 0), *(p + 1), *(p + 2), *(p + 3));
636 debug_msg("lati: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 4), *(p + 5), *(p + 6), *(p + 7));
637 debug_msg("alti: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 8), *(p + 9), *(p + 10), *(p + 11));
640 ilong = mmfile_io_be_uint32(*(unsigned int *)p);
641 ilati = mmfile_io_be_uint32(*(unsigned int *)(p + 4));
642 ialti = mmfile_io_be_uint32(*(unsigned int *)(p + 8));
644 flong = (float)ilong / (1 << 16);
645 flati = (float)ilati / (1 << 16);
646 falti = (float)ialti / (1 << 16);
649 lociTag.longitude = flong;
651 lociTag.latitude = flati;
653 lociTag.altitude = falti;
657 /*astronomical body*/
658 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + 1));
660 if (p[0] == 0xFE && p[1] == 0xFF) {
661 lociTag.astronomical_body = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
663 lociTag.astronomical_body = (unsigned char *)mmfile_strdup((const char *)p);
672 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + astro_sz));
674 if (p[0] == 0xFE && p[1] == 0xFF) {
675 lociTag.additional_notes = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
677 lociTag.additional_notes = (unsigned char *)mmfile_strdup((const char *)p);
683 #ifdef __MMFILE_TEST_MODE__
684 debug_msg("** Location Information **\n");
685 debug_msg("Name : %s\n", lociTag.name);
686 debug_msg("Role : %d (0: shooting, 1: real, 2: fictional, other: reserved)\n", lociTag.role);
687 debug_msg("Longitude : %16.16f\n", lociTag.longitude);
688 debug_msg("Latitude : %16.16f\n", lociTag.latitude);
689 debug_msg("Altitude : %16.16f\n", lociTag.altitude);
690 debug_msg("Astronomical body: %s\n", lociTag.astronomical_body);
691 debug_msg("Additional notes : %s\n", lociTag.additional_notes);
694 formatContext->longitude = lociTag.longitude;
695 formatContext->latitude = lociTag.latitude;
696 formatContext->altitude = lociTag.altitude;
699 mmfile_free(lociTag.name);
700 mmfile_free(lociTag.astronomical_body);
701 mmfile_free(lociTag.additional_notes);
703 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
704 return MMFILE_UTIL_SUCCESS;
707 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
709 mmfile_free(lociTag.name);
710 mmfile_free(lociTag.astronomical_body);
711 mmfile_free(lociTag.additional_notes);
713 return MMFILE_UTIL_FAIL;
716 static int GetSAUTInfoFromSMTATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
718 MMFILE_M4A_SMTA_TAGBOX smtaTag = {0, };
721 if (!formatContext || !fp || !basic_header) {
722 debug_error("invalid param\n");
723 return MMFILE_UTIL_FAIL;
726 readed = mmfile_read(fp, (unsigned char *)&smtaTag, sizeof(MMFILE_M4A_SMTA_TAGBOX));
727 if (readed != sizeof(MMFILE_M4A_SMTA_TAGBOX)) {
728 debug_error("read smta tag header fail\n");
732 smtaTag.length = mmfile_io_be_uint32(smtaTag.length);
733 smtaTag.value = mmfile_io_be_uint32(smtaTag.value);
734 #ifdef __MMFILE_TEST_MODE__
735 debug_msg("Len : 0x%x", smtaTag.length);
736 debug_msg("Saut : 0x%x 0x%x 0x%x 0x%x", smtaTag.saut[0], smtaTag.saut[1], smtaTag.saut[2], smtaTag.saut[3]);
737 debug_msg("Value : 0x%x", smtaTag.value);
740 if (smtaTag.saut[0] == 's'
741 && smtaTag.saut[1] == 'a'
742 && smtaTag.saut[2] == 'u'
743 && smtaTag.saut[3] == 't') {
744 if (smtaTag.value == 0x01) {
745 #ifdef __MMFILE_TEST_MODE__
746 debug_msg("This has saut tag and valid value");
748 formatContext->smta = 1;
750 debug_error("This has saut tag and but invalid value");
754 debug_error("This hasn't saut tag and valid value");
758 return MMFILE_UTIL_SUCCESS;
761 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
763 return MMFILE_UTIL_FAIL;
766 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
768 unsigned int value = 0;
771 if (!formatContext || !fp || !basic_header) {
772 debug_error("invalid param\n");
773 return MMFILE_UTIL_FAIL;
776 readed = mmfile_read(fp, (unsigned char *)&value, sizeof(unsigned int));
777 if (readed != sizeof(unsigned int)) {
778 debug_error("read cdis tag header fail\n");
782 value = mmfile_io_be_uint32(value);
784 #ifdef __MMFILE_TEST_MODE__
785 debug_msg("Value : 0x%x", value);
789 #ifdef __MMFILE_TEST_MODE__
790 debug_msg("This has cdis tag and valid value");
792 formatContext->cdis = 1;
794 debug_error("This has cdis tag and but invalid value");
798 return MMFILE_UTIL_SUCCESS;
801 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
803 return MMFILE_UTIL_FAIL;
806 static int GetTagFromMetaBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
809 MMFILE_MP4_BASIC_BOX_HEADER hdlrBoxHeader = {0, };
810 MMFILE_MP4_BASIC_BOX_HEADER id3v2BoxHeader = {0, };
811 MMFILE_3GP_ID3V2_BOX id3v2Box = {0, };
812 AvFileContentInfo tagInfo = {0, };
813 unsigned char tagVersion = 0;
814 bool versionCheck = false;
816 unsigned int meta_version = 0;
817 MMFILE_3GP_HANDLER_BOX hdlrBox = {0, };
818 unsigned int encSize = 0;
820 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
825 readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
827 debug_error("read meta box version\n");
832 readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
833 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
834 debug_error("read hdlr box header\n");
838 if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
839 debug_warning("meta type is not hdlr\n");
843 hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
844 hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
846 readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
847 if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
848 debug_error("read hdlr box\n");
852 hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
855 * check tag type (ID3v2 or iTunes)
857 if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
858 #ifdef __MMFILE_TEST_MODE__
859 debug_msg("ID3v2 tag detected.\n");
863 #ifdef ENABLE_ITUNES_META
866 } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
867 mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
869 #ifdef __MMFILE_TEST_MODE__
870 debug_msg("Apple iTunes tag detected by mdir.\n");
873 #ifdef ENABLE_ITUNES_META
877 debug_warning("unknown meta type. 4CC:[%c%c%c%c]\n", ((char *)&hdlrBox.handler_type)[0],
878 ((char *)&hdlrBox.handler_type)[1],
879 ((char *)&hdlrBox.handler_type)[2],
880 ((char *)&hdlrBox.handler_type)[3]);
884 #ifdef ENABLE_ITUNES_META
885 if (!id3_meta && !iTunes_meta) {
887 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
888 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
889 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
891 const char *ilst_box = "ilst";
892 int buf_size = strlen(ilst_box);
894 unsigned char read_buf[buf_size + 1];
895 memset(read_buf, 0x00, buf_size + 1);
898 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR); /*+4 is hdlr size field */
900 readed = mmfile_read(fp, read_buf, buf_size); /* to find 'ilst' */
901 if (readed != buf_size) {
902 debug_error("read fail [%d]\n", readed);
906 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
907 #ifdef __MMFILE_TEST_MODE__
908 debug_msg("Apple iTunes tag detected by ilst.\n");
916 #ifdef ENABLE_ITUNES_META
919 * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
927 #define _ITUNES_READ_BUF_SZ 20
928 #define _ITUNES_TRACK_NUM_SZ 4
929 #define _ITUNES_GENRE_NUM_SZ 4
930 #define _ITUNES_COVER_TYPE_JPEG 13
931 #define _ITUNES_COVER_TYPE_PNG 14
933 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
935 int cover_sz = 0, cover_type = 0, cover_found = 0;
936 /* int track_found = 0; */ /* , track_num = 0; */
937 /* int genre_found = 0; */ /* , genre_index = 0; */
938 /* int artist_found = 0; */ /* , artist_sz = 0; */
939 int limit = basic_header->size - hdlrBoxHeader.size;
940 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
942 /* 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++) { */
943 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
944 readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
945 if (readed != _ITUNES_READ_BUF_SZ)
948 /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
949 but ffmpeg does not support strange cover image.
950 only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
953 * Artist : Added 2010.10.28
955 if (artist_found == 0 &&
956 read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
957 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
960 artist_offset = mmfile_tell(fp);
961 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
963 #ifdef __MMFILE_TEST_MODE__
964 debug_msg("----------------------------------- artist found, offset=[%lld], size=[%d]\n", artist_offset, artist_sz);
971 if (track_found == 0 &&
972 read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
973 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
976 track_offset = mmfile_tell(fp);
978 #ifdef __MMFILE_TEST_MODE__
979 debug_msg("----------------------------------- Track found, offset=[%lld]\n", track_offset);
984 * Genre : Added 2010.10.27
986 /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
987 if (genre_found == 0 &&
988 read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
989 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
992 genre_offset = mmfile_tell(fp);
994 #ifdef __MMFILE_TEST_MODE__
995 debug_msg("----------------------------------- genre found, offset=[%lld]\n", genre_offset);
1004 if (cover_found == 0 &&
1005 read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
1006 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1009 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
1010 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
1012 cover_offset = mmfile_tell(fp);
1014 #ifdef __MMFILE_TEST_MODE__
1015 debug_msg("----------------------------------- cover_found found, offset=[%lld]\n", cover_offset);
1019 mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR); /*FIXME: poor search*/
1022 /*ffmpeg extract artist, tracknum, excep cover image. see mov_read_udta_string()*/
1025 if (artist_sz > 0) {
1026 mmfile_seek(fp, artist_offset, SEEK_SET);
1028 if (formatContext->artist) {
1029 #ifdef __MMFILE_TEST_MODE__
1030 debug_msg("----------------------------------- previous artist was [%s] \n", formatContext->artist);
1032 free(formatContext->artist);
1034 #ifdef __MMFILE_TEST_MODE__
1035 debug_msg("----------------------------------- new artist will be allocated with size (len+1) [%d] \n", artist_sz + 1);
1037 formatContext->artist = mmfile_malloc(artist_sz + 1);
1039 if (formatContext->artist) {
1040 readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1041 formatContext->artist[artist_sz] = '\0';
1043 #ifdef __MMFILE_TEST_MODE__
1044 debug_msg("----------------------------------- new artist is [%s] \n", formatContext->artist);
1047 if (readed != artist_sz) {
1048 debug_error("failed to read. ret = %d, in = %d\n", readed, artist_sz);
1049 mmfile_free(formatContext->artist);
1056 mmfile_seek(fp, track_offset, SEEK_SET);
1057 readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1058 if (readed != _ITUNES_TRACK_NUM_SZ) {
1059 debug_error("failed to read. ret = %d, in = %d\n", readed, _ITUNES_TRACK_NUM_SZ);
1061 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1062 if (!formatContext->tagTrackNum) {
1063 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1064 snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1065 formatContext->tagTrackNum = mmfile_strdup((const char *)read_buf);
1071 mmfile_seek(fp, genre_offset, SEEK_SET);
1072 readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1073 if (readed != _ITUNES_GENRE_NUM_SZ) {
1074 debug_error("failed to read. ret = %d, in = %d\n", readed, _ITUNES_GENRE_NUM_SZ);
1076 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1077 #ifdef __MMFILE_TEST_MODE__
1078 debug_msg("genre index=[%d] \n", genre_index);
1080 if (genre_index > 0 && genre_index < GENRE_COUNT) {
1081 if (!formatContext->genre) {
1082 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1083 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1084 #ifdef __MMFILE_TEST_MODE__
1085 debug_msg("genre string=[%s] \n", read_buf);
1087 formatContext->genre = mmfile_strdup((const char *)read_buf);
1095 1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1096 Music Cover Art Image Profile
1097 - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1098 - RGB (screen standard)
1099 - Minimum size of 600 x 600 pixels
1100 - Images must be at least 72 dpi
1102 2)I found below info from google.
1103 cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1105 3)So, FIXME when cover image format is tif!
1109 mmfile_seek(fp, cover_offset, SEEK_SET);
1111 formatContext->artwork = mmfile_malloc(cover_sz);
1112 formatContext->artworkSize = cover_sz;
1113 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1114 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1115 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1116 formatContext->artworkMime = mmfile_strdup("image/png");
1117 /*} else if(cover_type == _ITUNES_COVER_TYPE_TIF) {
1118 formatContext->artworkMime = mmfile_strdup("image/tif");*/
1120 debug_warning("Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1121 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1124 if (formatContext->artwork) {
1125 readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1126 if (readed != cover_sz) {
1127 debug_error("failed to read. ret = %d, in = %d\n", readed, cover_sz);
1128 mmfile_free(formatContext->artwork);
1129 formatContext->artworkSize = 0;
1130 mmfile_free(formatContext->artworkMime);
1136 /*reset seek position*/
1137 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1139 return MMFILE_UTIL_SUCCESS;
1147 /* skip hdlr box name */
1148 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1151 readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1152 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1153 debug_error("read id3v2 box header\n");
1157 id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1158 id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1160 if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1161 debug_warning("meta type is not id3v2\n");
1165 readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1166 if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1167 debug_error("read id3v2 box\n");
1171 id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1173 id3v2Box.id3v2Data = mmfile_malloc(id3v2Len);
1174 if (!id3v2Box.id3v2Data) {
1175 debug_error("malloc id3tag data error\n");
1179 readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1180 if (readed != id3v2Len) {
1181 debug_error("read id3tag data error\n");
1186 if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1187 debug_error("it is not id3tag\n");
1191 if (id3v2Box.id3v2Data[3] == 0xFF || id3v2Box.id3v2Data[4] == 0xFF ||
1192 id3v2Box.id3v2Data[6] >= 0x80 || id3v2Box.id3v2Data[7] >= 0x80 ||
1193 id3v2Box.id3v2Data[8] >= 0x80 || id3v2Box.id3v2Data[9] >= 0x80) {
1194 debug_error("it is not valid id3tag\n");
1198 tagVersion = id3v2Box.id3v2Data[3];
1199 if (tagVersion > 4) {
1200 debug_error("tag vesion is too high\n");
1204 encSize = mmfile_io_le_uint32((unsigned int)&id3v2Box.id3v2Data[6]);
1205 tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1206 tagInfo.tagV2Info.tagLen += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
1207 tagInfo.tagV2Info.tagVersion = tagVersion;
1208 tagInfo.fileLen = id3v2Len;
1210 /* set id3v2 data to formatContext */
1211 switch (tagVersion) {
1213 versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data);
1217 versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data);
1221 versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data);
1226 debug_error("tag vesion is not support\n");
1227 versionCheck = false;
1232 if (versionCheck == false) {
1233 debug_error("tag parsing is fail\n");
1237 if (!formatContext->title) formatContext->title = mmfile_strdup((const char *)tagInfo.pTitle);
1238 if (!formatContext->artist) formatContext->artist = mmfile_strdup((const char *)tagInfo.pArtist);
1239 if (!formatContext->author) formatContext->author = mmfile_strdup((const char *)tagInfo.pAuthor);
1240 if (!formatContext->copyright) formatContext->copyright = mmfile_strdup((const char *)tagInfo.pCopyright);
1241 if (!formatContext->comment) formatContext->comment = mmfile_strdup((const char *)tagInfo.pComment);
1242 if (!formatContext->album) formatContext->album = mmfile_strdup((const char *)tagInfo.pAlbum);
1243 if (!formatContext->album_artist) formatContext->album_artist = mmfile_strdup((const char *)tagInfo.pAlbum_Artist);
1244 if (!formatContext->year) formatContext->year = mmfile_strdup((const char *)tagInfo.pYear);
1245 if (!formatContext->genre) formatContext->genre = mmfile_strdup((const char *)tagInfo.pGenre);
1246 if (!formatContext->tagTrackNum) formatContext->tagTrackNum = mmfile_strdup((const char *)tagInfo.pTrackNum);
1247 if (!formatContext->composer) formatContext->composer = mmfile_strdup((const char *)tagInfo.pComposer);
1248 if (!formatContext->classification) formatContext->classification = mmfile_strdup((const char *)tagInfo.pContentGroup);
1249 if (!formatContext->conductor) formatContext->conductor = mmfile_strdup((const char *)tagInfo.pConductor);
1251 formatContext->artwork = mmfile_malloc(tagInfo.imageInfo.imageLen);
1252 if ((tagInfo.imageInfo.imageLen > 0) && formatContext->artwork) {
1253 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1254 memcpy(formatContext->artwork, tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1257 mm_file_free_AvFileContentInfo(&tagInfo);
1258 mmfile_free(id3v2Box.id3v2Data);
1260 /*reset seek position*/
1261 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1263 return MMFILE_UTIL_SUCCESS;
1269 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1270 mmfile_free(id3v2Box.id3v2Data);
1271 mm_file_free_AvFileContentInfo(&tagInfo);
1273 return MMFILE_UTIL_FAIL;
1277 EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
1279 MMFileIOHandle *fp = NULL;
1283 ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1284 if (ret == MMFILE_UTIL_FAIL) {
1285 debug_error("error: mmfile_open\n");
1289 MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
1290 basic_header.start_offset = mmfile_tell(fp);
1292 while ((ret != MMFILE_UTIL_FAIL) && ((readed = mmfile_read(fp, (unsigned char *)&basic_header, MMFILE_MP4_BASIC_BOX_HEADER_LEN)) > 0)) {
1293 basic_header.size = mmfile_io_be_uint32(basic_header.size);
1294 basic_header.type = mmfile_io_le_uint32(basic_header.type);
1296 if (basic_header.size == 0) {
1297 debug_warning("header is invalid.\n");
1298 basic_header.size = readed;
1299 basic_header.type = 0;
1302 #ifdef __MMFILE_TEST_MODE__
1303 debug_msg("START_OFFSET:[%lld] SIZE:[%d Byte] 4CC:[%c%c%c%c]\n",
1304 basic_header.start_offset, basic_header.size,
1305 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
1306 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3]);
1309 switch (basic_header.type) {
1310 case FOURCC('m', 'o', 'o', 'v'): {
1311 #ifdef __MMFILE_TEST_MODE__
1312 debug_msg("MPEG4: [moov] SIZE: [%d]Byte\n", basic_header.size);
1316 case FOURCC('u', 'd', 't', 'a'): {
1317 #ifdef __MMFILE_TEST_MODE__
1318 debug_msg("MPEG4: [udat] SIZE: [%d]Byte\n", basic_header.size);
1322 /*/////////////////////////////////////////////////////////////// */
1323 /* Extracting Tag Data // */
1324 /*/////////////////////////////////////////////////////////////// */
1325 case FOURCC('t', 'i', 't', 'l'): {
1326 #ifdef __MMFILE_TEST_MODE__
1327 debug_msg("MPEG4: [titl] SIZE: [%d]Byte\n", basic_header.size);
1329 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
1332 case FOURCC('d', 's', 'c', 'p'): {
1333 #ifdef __MMFILE_TEST_MODE__
1334 debug_msg("MPEG4: [dscp] SIZE: [%d]Byte\n", basic_header.size);
1336 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
1339 case FOURCC('c', 'p', 'r', 't'): {
1340 #ifdef __MMFILE_TEST_MODE__
1341 debug_msg("MPEG4: [cprt] SIZE: [%d]Byte\n", basic_header.size);
1343 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
1346 case FOURCC('p', 'e', 'r', 'f'): {
1347 #ifdef __MMFILE_TEST_MODE__
1348 debug_msg("MPEG4: [perf] SIZE: [%d]Byte\n", basic_header.size);
1350 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
1353 case FOURCC('a', 'u', 't', 'h'): {
1354 #ifdef __MMFILE_TEST_MODE__
1355 debug_msg("MPEG4: [auth] SIZE: [%d]Byte\n", basic_header.size);
1357 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
1360 case FOURCC('g', 'n', 'r', 'e'): {
1361 #ifdef __MMFILE_TEST_MODE__
1362 debug_msg("MPEG4: [gnre] SIZE: [%d]Byte\n", basic_header.size);
1364 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
1367 case FOURCC('a', 'l', 'b', 'm'): {
1368 #ifdef __MMFILE_TEST_MODE__
1369 debug_msg("MPEG4: [albm] SIZE: [%d]Byte\n", basic_header.size);
1371 GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
1374 case FOURCC('y', 'r', 'r', 'c'): {
1375 #ifdef __MMFILE_TEST_MODE__
1376 debug_msg("MPEG4: [yrrc] SIZE: [%d]Byte\n", basic_header.size);
1378 GetYearFromYearTagBox(formatContext, fp, &basic_header);
1381 case FOURCC('r', 't', 'n', 'g'): {
1382 #ifdef __MMFILE_TEST_MODE__
1383 debug_msg("MPEG4: [rtng] SIZE: [%d]Byte\n", basic_header.size);
1385 GetRatingFromRatingTagBox(formatContext, fp, &basic_header); /* not use */
1388 case FOURCC('c', 'l', 's', 'f'): {
1389 #ifdef __MMFILE_TEST_MODE__
1390 debug_msg("MPEG4: [clsf] SIZE: [%d]Byte\n", basic_header.size);
1392 GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
1395 case FOURCC('k', 'y', 'w', 'd'): {
1396 #ifdef __MMFILE_TEST_MODE__
1397 debug_msg("MPEG4: [kywd] SIZE: [%d]Byte\n", basic_header.size);
1399 ret = mmfile_seek(fp, basic_header.start_offset + basic_header.size, SEEK_SET);
1402 case FOURCC('l', 'o', 'c', 'i'): {
1403 #ifdef __MMFILE_TEST_MODE__
1404 debug_msg("MPEG4: [loci] SIZE: [%d]Byte\n", basic_header.size);
1406 GetLocationFromLociTagBox(formatContext, fp, &basic_header);
1409 /* Check smta in user data field to be compatible with android */
1410 case FOURCC('s', 'm', 't', 'a'): {
1411 #ifdef __MMFILE_TEST_MODE__
1412 debug_msg("MPEG4: [smta] SIZE: [%d]Byte\n", basic_header.size);
1414 GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
1417 /* Check smta in user data field to be compatible with android */
1418 case FOURCC('c', 'd', 'i', 's'): {
1419 #ifdef __MMFILE_TEST_MODE__
1420 debug_msg("MPEG4: [smta] SIZE: [%d]Byte\n", basic_header.size);
1422 GetValueFromCDISTagBox(formatContext, fp, &basic_header);
1425 /*/////////////////////////////////////////////////////////////// */
1426 /* Extracting ID3 Tag Data // */
1427 /*/////////////////////////////////////////////////////////////// */
1428 case FOURCC('m', 'e', 't', 'a'): {
1429 #ifdef __MMFILE_TEST_MODE__
1430 debug_msg("MPEG4: [meta] SIZE: [%d]Byte\n", basic_header.size);
1432 GetTagFromMetaBox(formatContext, fp, &basic_header);
1436 #ifdef __MMFILE_TEST_MODE__
1437 debug_msg("4CC: Not Support.. so skip it\n");
1439 ret = mmfile_seek(fp, basic_header.start_offset + basic_header.size, SEEK_SET);
1444 if (ret == MMFILE_UTIL_FAIL) {
1445 debug_error("mmfile operation is error\n");
1450 basic_header.start_offset = mmfile_tell(fp);
1458 static char *get_string(const char *buf, int buf_size, int *bytes_written)
1462 char str[512] = {0, };
1465 for (i = 0; i < buf_size; i++) {
1469 if ((q - str) >= (int)sizeof(str) - 1)
1475 if (strlen(str) > 0) {
1476 *bytes_written = strlen(str);
1484 static bool is_numeric(const char *buf, int buf_size)
1489 for (idx = 0; idx < buf_size; idx++) {
1490 if (isdigit((int)buf[idx])) {
1501 char *rtrimN(char *pStr)
1504 pos = strlen(pStr) - 1;
1505 for (; pos >= 0; pos--) {
1506 if (pStr[pos] == 0x20) {
1513 return strdup(pStr);
1516 static bool make_characterset_array(char ***charset_array)
1518 char *locale = MMFileUtilGetLocale(NULL);
1520 *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
1522 if (*charset_array == NULL) {
1523 debug_error("calloc failed ");
1529 if (locale != NULL) {
1530 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
1532 debug_error("get locale failed");
1533 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
1536 (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
1537 (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
1538 (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
1543 static bool release_characterset_array(char **charset_array)
1547 for (i = 0; i < AV_ID3V2_MAX; i++) {
1548 if (charset_array[i] != NULL) {
1549 free(charset_array[i]);
1550 charset_array[i] = NULL;
1554 if (charset_array != NULL) {
1555 free(charset_array);
1556 charset_array = NULL;
1562 static void init_content_info(AvFileContentInfo *pInfo)
1564 pInfo->tagV2Info.bTitleMarked = false;
1565 pInfo->tagV2Info.bArtistMarked = false;
1566 pInfo->tagV2Info.bAlbumMarked = false;
1567 pInfo->tagV2Info.bAlbum_ArtistMarked = false;
1568 pInfo->tagV2Info.bYearMarked = false;
1569 pInfo->tagV2Info.bDescriptionMarked = false;
1570 pInfo->tagV2Info.bGenreMarked = false;
1571 pInfo->tagV2Info.bTrackNumMarked = false;
1572 pInfo->tagV2Info.bEncByMarked = false;
1573 pInfo->tagV2Info.bURLMarked = false;
1574 pInfo->tagV2Info.bCopyRightMarked = false;
1575 pInfo->tagV2Info.bOriginArtistMarked = false;
1576 pInfo->tagV2Info.bComposerMarked = false;
1577 pInfo->tagV2Info.bImageMarked = false;
1579 pInfo->tagV2Info.bRecDateMarked = false;
1580 pInfo->tagV2Info.bContentGroupMarked = false;
1582 pInfo->tagV2Info.bUnsyncLyricsMarked = false;
1583 pInfo->tagV2Info.bSyncLyricsMarked = false;
1584 pInfo->tagV2Info.bConductorMarked = false;
1585 pInfo->tagV2Info.bGenreUTF16 = false;
1587 pInfo->imageInfo.bURLInfo = false;
1588 pInfo->imageInfo.pImageBuf = NULL;
1589 pInfo->imageInfo.imageLen = 0;
1593 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo, unsigned char *buffer)
1595 const char *locale = MMFileUtilGetLocale(NULL);
1596 char *pFullStr = NULL;
1598 #ifdef __MMFILE_TEST_MODE__
1599 debug_msg("ID3tag v110--------------------------------------------------------------\n");
1602 if (pInfo->tagV2Info.bTitleMarked == false) {
1603 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
1604 if (pFullStr != NULL) {
1605 pInfo->pTitle = rtrimN(pFullStr);
1609 #ifdef __MMFILE_TEST_MODE__
1610 debug_msg("pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1614 if (pInfo->tagV2Info.bArtistMarked == false) {
1615 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
1616 if (pFullStr != NULL) {
1617 pInfo->pArtist = rtrimN(pFullStr);
1621 #ifdef __MMFILE_TEST_MODE__
1622 debug_msg("pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1626 if (pInfo->tagV2Info.bAlbumMarked == false) {
1627 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
1628 if (pFullStr != NULL) {
1629 pInfo->pAlbum = rtrimN(pFullStr);
1633 #ifdef __MMFILE_TEST_MODE__
1634 debug_msg("pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1638 if (pInfo->tagV2Info.bYearMarked == false) {
1640 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
1641 #ifdef __MMFILE_TEST_MODE__
1642 debug_msg("pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1645 if (pInfo->pYear == NULL) { /*Use same logic with ffmpeg*/
1646 pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
1647 #ifdef __MMFILE_TEST_MODE__
1648 debug_msg("pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1653 if (pInfo->tagV2Info.bDescriptionMarked == false) {
1654 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
1655 #ifdef __MMFILE_TEST_MODE__
1656 debug_msg("pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1659 if (pInfo->pComment == NULL) { /*Use same logic with ffmpeg*/
1660 pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
1661 #ifdef __MMFILE_TEST_MODE__
1662 debug_msg("pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1667 if (pInfo->tagV2Info.bTrackNumMarked == false) {
1668 pInfo->pTrackNum = mmfile_malloc(5);
1669 if (pInfo->pTrackNum != NULL) {
1670 pInfo->pTrackNum[4] = 0;
1671 snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
1672 pInfo->tracknumLen = strlen(pInfo->pTrackNum);
1673 #ifdef __MMFILE_TEST_MODE__
1674 debug_msg("pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1679 if (pInfo->tagV2Info.bGenreMarked == false) {
1680 pInfo->genre = buffer[127];
1681 #ifdef __MMFILE_TEST_MODE__
1682 debug_msg("pInfo->genre returned genre number (%d)\n", pInfo->genre);
1690 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
1692 unsigned long taglen = 0;
1693 unsigned long needToloopv2taglen;
1694 unsigned long oneFrameLen = 0;
1695 unsigned long v2numOfFrames = 0;
1696 unsigned long curPos = 0;
1698 unsigned char *pExtContent = NULL;
1699 unsigned long purelyFramelen = 0;
1700 unsigned int encodingOffSet = 0;
1701 int inx = 0, realCpyFrameNum = 0,
1702 /*checkImgMimeTypeMax = 0, */checkImgExtMax = 0,
1703 imgstartOffset = 0, tmp = 0;
1705 int textEncodingType = 0;
1707 char **charset_array = NULL;
1709 make_characterset_array(&charset_array);
1711 init_content_info(pInfo);
1713 taglen = pInfo->tagV2Info.tagLen;
1714 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
1715 curPos = MP3_TAGv2_HEADER_LEN;
1717 #ifdef __MMFILE_TEST_MODE__
1718 debug_msg("ID3tag v222--------------------------------------------------------------\n");
1720 if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
1722 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
1723 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
1724 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
1727 memcpy(CompTmp, &buffer[curPos], 3);
1730 oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
1731 oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
1732 | (unsigned long)buffer[5 + curPos];
1733 if (oneFrameLen > taglen - curPos)
1735 purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
1736 curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
1738 if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
1739 curPos += purelyFramelen;
1741 if (buffer[curPos - purelyFramelen] == 0x00) {
1743 textEncodingType = AV_ID3V2_ISO_8859;
1744 } else if (buffer[curPos - purelyFramelen] == 0x01) {
1746 textEncodingType = AV_ID3V2_UTF16;
1749 if (textEncodingType > AV_ID3V2_MAX) {
1750 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
1754 /*in order to deliver valid string to MP */
1755 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
1758 if (encodingOffSet < purelyFramelen) {
1759 realCpyFrameNum = purelyFramelen - encodingOffSet;
1760 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
1762 if (pExtContent == NULL) {
1763 debug_error("out of memory for pExtContent\n");
1767 memset(pExtContent, '\0', realCpyFrameNum + 3);
1769 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
1771 if (realCpyFrameNum > 0) {
1772 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
1773 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
1775 #ifdef __MMFILE_TEST_MODE__
1776 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1778 pInfo->tagV2Info.bTitleMarked = true;
1779 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
1780 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
1782 #ifdef __MMFILE_TEST_MODE__
1783 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1785 pInfo->tagV2Info.bArtistMarked = true;
1786 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
1787 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
1789 #ifdef __MMFILE_TEST_MODE__
1790 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
1792 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
1793 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
1794 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
1796 #ifdef __MMFILE_TEST_MODE__
1797 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
1799 pInfo->tagV2Info.bConductorMarked = true;
1800 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
1801 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
1803 #ifdef __MMFILE_TEST_MODE__
1804 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1806 pInfo->tagV2Info.bAlbumMarked = true;
1807 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
1808 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
1810 #ifdef __MMFILE_TEST_MODE__
1811 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1813 pInfo->tagV2Info.bYearMarked = true;
1814 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
1815 /*skip language data! */
1816 if (realCpyFrameNum > 4) {
1817 realCpyFrameNum -= 4;
1820 /*pExtContent[tmp+1] value should't have encoding value */
1821 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1822 if (pExtContent[tmp - 1] == 0x00)
1823 textEncodingType = AV_ID3V2_ISO_8859;
1825 textEncodingType = AV_ID3V2_UTF16;
1827 pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
1829 #ifdef __MMFILE_TEST_MODE__
1830 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1832 pInfo->tagV2Info.bDescriptionMarked = true;
1834 #ifdef __MMFILE_TEST_MODE__
1835 debug_msg("mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1839 #ifdef __MMFILE_TEST_MODE__
1840 debug_msg("mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1845 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
1846 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
1848 #ifdef __MMFILE_TEST_MODE__
1849 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
1852 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
1856 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
1859 sscanf(pInfo->pGenre, "%d", &int_genre);
1860 #ifdef __MMFILE_TEST_MODE__
1861 debug_msg("genre information is inteager [%d]\n", int_genre);
1864 /*Change int to string */
1865 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
1866 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
1867 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
1868 int tmp_genre_len = 0;
1870 memset(tmp_genre, 0, 6);
1871 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
1873 tmp_genre_len = strlen(tmp_genre);
1874 if (tmp_genre_len > 0) {
1875 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
1876 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
1877 if (pInfo->pGenre) {
1878 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
1879 pInfo->pGenre[tmp_genre_len] = 0;
1886 pInfo->tagV2Info.bGenreMarked = true;
1887 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
1888 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
1890 #ifdef __MMFILE_TEST_MODE__
1891 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1893 pInfo->tagV2Info.bTrackNumMarked = true;
1894 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
1895 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
1897 #ifdef __MMFILE_TEST_MODE__
1898 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
1900 pInfo->tagV2Info.bEncByMarked = true;
1901 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
1902 if (realCpyFrameNum > 4) {
1903 /*skip language data! */
1904 realCpyFrameNum -= 4;
1907 /*pExtContent[tmp+1] value should't have null value */
1908 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1909 if (pExtContent[tmp - 1] == 0x00)
1910 textEncodingType = AV_ID3V2_ISO_8859;
1912 textEncodingType = AV_ID3V2_UTF16;
1914 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
1916 #ifdef __MMFILE_TEST_MODE__
1917 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
1919 pInfo->tagV2Info.bURLMarked = true;
1921 #ifdef __MMFILE_TEST_MODE__
1922 debug_msg("mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1926 #ifdef __MMFILE_TEST_MODE__
1927 debug_msg("mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1931 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
1932 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
1934 #ifdef __MMFILE_TEST_MODE__
1935 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
1937 pInfo->tagV2Info.bCopyRightMarked = true;
1938 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
1939 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
1941 #ifdef __MMFILE_TEST_MODE__
1942 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
1944 pInfo->tagV2Info.bOriginArtistMarked = true;
1945 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
1946 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
1948 #ifdef __MMFILE_TEST_MODE__
1949 debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
1951 pInfo->tagV2Info.bComposerMarked = true;
1952 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
1953 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
1955 #ifdef __MMFILE_TEST_MODE__
1956 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
1958 pInfo->tagV2Info.bRecDateMarked = true;
1959 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
1960 if (pExtContent[0] != 0) {
1961 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
1962 pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
1964 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
1965 pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
1969 #ifdef __MMFILE_TEST_MODE__
1970 debug_msg("mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
1974 imgstartOffset += checkImgExtMax;
1976 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
1977 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
1979 imgstartOffset++;/*PictureType(1byte) */
1981 if (pExtContent[imgstartOffset] != 0x0) {
1984 int new_dis_len = 0;
1985 unsigned char jpg_sign[3] = {0xff, 0xd8, 0xff};
1986 unsigned char png_sign[8] = {0x80, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
1987 char *tmp_desc = NULL;
1990 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
1991 if (realCpyFrameNum < imgstartOffset + cur_pos) {
1992 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
1995 /*check end of image description*/
1996 if ((pExtContent[imgstartOffset + cur_pos + 1] == jpg_sign[0]) ||
1997 (pExtContent[imgstartOffset + cur_pos + 1] == png_sign[0])) {
1998 #ifdef __MMFILE_TEST_MODE__
1999 debug_msg("length of description (%d)", cur_pos);
2008 dis_len = cur_pos + 1;
2010 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2012 if(tmp_desc != NULL) {
2013 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2015 /*convert description*/
2016 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2017 mmfile_free(tmp_desc);
2019 #ifdef __MMFILE_TEST_MODE__
2020 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2022 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2025 imgstartOffset += cur_pos;
2027 pInfo->imageInfo.imgDesLen = 0;
2030 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2031 imgstartOffset++; /* endofDesceriptionType(1byte) */
2033 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2037 #ifdef __MMFILE_TEST_MODE__
2038 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2041 if (realCpyFrameNum - imgstartOffset > 0) {
2042 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2043 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2045 if (pInfo->imageInfo.pImageBuf != NULL) {
2046 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2047 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2050 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2051 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2053 #ifdef __MMFILE_TEST_MODE__
2054 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2059 /*checkImgMimeTypeMax = 0;*/
2063 pInfo->tagV2Info.bImageMarked = true;
2070 curPos += purelyFramelen;
2071 if (purelyFramelen != 0)
2072 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2075 if (pExtContent) _FREE_EX(pExtContent);
2076 memset(CompTmp, 0, 4);
2077 if (curPos < taglen) {
2078 needToloopv2taglen -= oneFrameLen;
2081 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2084 realCpyFrameNum = 0;
2085 textEncodingType = 0;
2091 release_characterset_array(charset_array);
2101 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2103 unsigned long taglen = 0;
2104 unsigned long needToloopv2taglen;
2105 unsigned long oneFrameLen = 0;
2106 unsigned long v2numOfFrames = 0;
2107 unsigned long curPos = 0;
2109 unsigned char *pExtContent = NULL;
2110 unsigned long purelyFramelen = 0;
2111 unsigned int encodingOffSet = 0;
2112 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2113 int textEncodingType = 0;
2114 char **charset_array = NULL;
2115 const char *MIME_PRFIX = "image/";
2117 make_characterset_array(&charset_array);
2119 init_content_info(pInfo);
2121 taglen = pInfo->tagV2Info.tagLen;
2122 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2123 curPos = MP3_TAGv2_HEADER_LEN;
2125 #ifdef __MMFILE_TEST_MODE__
2126 debug_msg("ID3tag v223--------------------------------------------------------------\n");
2129 /* check Extended Header */
2130 if (buffer[5] & 0x40) {
2131 /* if extended header exists, skip it*/
2132 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2134 #ifdef __MMFILE_TEST_MODE__
2135 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2138 curPos += extendedHeaderLen;
2142 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2144 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2145 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2146 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2149 memcpy(CompTmp, &buffer[curPos], 4);
2152 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2153 oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2154 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2156 #ifdef __MMFILE_TEST_MODE__
2157 debug_msg("----------------------------------------------------------------------------------------------------\n");
2160 if (oneFrameLen > taglen - curPos)
2163 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2164 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2166 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2167 curPos += purelyFramelen;
2169 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2171 #ifdef __MMFILE_TEST_MODE__
2172 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2174 textEncodingType = AV_ID3V2_UTF16;
2175 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2177 #ifdef __MMFILE_TEST_MODE__
2178 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2180 textEncodingType = AV_ID3V2_UTF16_BE;
2181 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2183 #ifdef __MMFILE_TEST_MODE__
2184 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2186 textEncodingType = AV_ID3V2_UTF16;
2187 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2189 #ifdef __MMFILE_TEST_MODE__
2190 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2192 textEncodingType = AV_ID3V2_UTF16_BE;
2194 if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2195 #ifdef __MMFILE_TEST_MODE__
2196 debug_msg("encodingOffset will be set to 1\n");
2201 #ifdef __MMFILE_TEST_MODE__
2202 debug_msg("Finding encodingOffset\n");
2205 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2208 textEncodingType = AV_ID3V2_ISO_8859;
2209 #ifdef __MMFILE_TEST_MODE__
2210 debug_msg("this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2214 if (encodingOffSet < purelyFramelen) {
2215 realCpyFrameNum = purelyFramelen - encodingOffSet;
2216 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2217 memset(pExtContent, '\0', realCpyFrameNum + 3);
2219 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2220 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2221 #ifdef __MMFILE_TEST_MODE__
2222 debug_msg("get the new text ecoding type\n");
2224 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2228 if (textEncodingType > AV_ID3V2_MAX) {
2229 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2233 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2234 if (realCpyFrameNum > 0) {
2235 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2236 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2238 #ifdef __MMFILE_TEST_MODE__
2239 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2241 pInfo->tagV2Info.bTitleMarked = true;
2243 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2244 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2246 #ifdef __MMFILE_TEST_MODE__
2247 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2249 pInfo->tagV2Info.bArtistMarked = true;
2250 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2251 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2253 #ifdef __MMFILE_TEST_MODE__
2254 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2256 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2257 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2258 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2260 #ifdef __MMFILE_TEST_MODE__
2261 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2263 pInfo->tagV2Info.bConductorMarked = true;
2264 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2265 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2267 #ifdef __MMFILE_TEST_MODE__
2268 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2270 pInfo->tagV2Info.bAlbumMarked = true;
2271 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2272 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2274 #ifdef __MMFILE_TEST_MODE__
2275 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2277 pInfo->tagV2Info.bYearMarked = true;
2278 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2279 if (realCpyFrameNum > 3) {
2280 realCpyFrameNum -= 3;
2283 /*pExtContent[tmp+1] value should't have encoding value */
2284 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2285 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2286 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2287 realCpyFrameNum -= 4;
2291 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2292 realCpyFrameNum -= 2;
2294 textEncodingType = AV_ID3V2_UTF16;
2295 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2296 realCpyFrameNum -= 2;
2298 textEncodingType = AV_ID3V2_UTF16_BE;
2299 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2300 realCpyFrameNum -= 3;
2302 textEncodingType = AV_ID3V2_UTF16;
2303 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2304 realCpyFrameNum -= 3;
2306 textEncodingType = AV_ID3V2_UTF16_BE;
2308 #ifdef __MMFILE_TEST_MODE__
2309 debug_msg("pInfo->pComment Never Get Here!!\n");
2313 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2317 textEncodingType = AV_ID3V2_ISO_8859;
2320 #ifdef __MMFILE_TEST_MODE__
2321 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2324 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2326 #ifdef __MMFILE_TEST_MODE__
2327 debug_msg("failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2329 pInfo->commentLen = 0;
2332 #ifdef __MMFILE_TEST_MODE__
2333 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2335 pInfo->commentLen = 0;
2339 #ifdef __MMFILE_TEST_MODE__
2340 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2342 pInfo->tagV2Info.bDescriptionMarked = true;
2343 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2346 int copy_start_pos = tmp;
2347 AvSynclyricsInfo *synclyrics_info = NULL;
2348 GList *synclyrics_info_list = NULL;
2350 if (realCpyFrameNum > 5) {
2351 realCpyFrameNum -= 5;
2354 /*pExtContent[tmp+1] value should't have encoding value */
2355 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2356 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2357 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2358 realCpyFrameNum -= 4;
2362 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2363 realCpyFrameNum -= 2;
2365 textEncodingType = AV_ID3V2_UTF16;
2366 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2367 realCpyFrameNum -= 2;
2369 textEncodingType = AV_ID3V2_UTF16_BE;
2370 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2371 realCpyFrameNum -= 3;
2373 textEncodingType = AV_ID3V2_UTF16;
2374 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2375 realCpyFrameNum -= 3;
2377 textEncodingType = AV_ID3V2_UTF16_BE;
2379 #ifdef __MMFILE_TEST_MODE__
2380 debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
2384 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2388 textEncodingType = AV_ID3V2_ISO_8859;
2391 #ifdef __MMFILE_TEST_MODE__
2392 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2395 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2396 #ifdef __MMFILE_TEST_MODE__
2397 debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
2399 pInfo->syncLyricsNum = 0;
2401 if (textEncodingType == AV_ID3V2_UTF16) {
2402 debug_warning("[AV_ID3V2_UTF16] not implemented\n");
2403 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
2404 debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
2406 for (idx = 0; idx < realCpyFrameNum; idx++) {
2407 if (pExtContent[tmp + idx] == 0x00) {
2408 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
2410 if (synclyrics_info != NULL) {
2411 if (textEncodingType == AV_ID3V2_UTF8) {
2412 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
2413 if (synclyrics_info->lyric_info != NULL) {
2414 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
2415 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
2416 synclyrics_info->lyric_info[copy_len + 1] = '\0';
2419 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);
2422 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];
2424 copy_start_pos = tmp + idx + 1;
2425 #ifdef __MMFILE_TEST_MODE__
2426 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);
2429 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
2434 pInfo->pSyncLyrics = synclyrics_info_list;
2435 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
2439 #ifdef __MMFILE_TEST_MODE__
2440 debug_msg("failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2442 pInfo->syncLyricsNum = 0;
2445 #ifdef __MMFILE_TEST_MODE__
2446 debug_msg("Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2448 pInfo->syncLyricsNum = 0;
2452 #ifdef __MMFILE_TEST_MODE__
2453 debug_msg("pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
2455 pInfo->tagV2Info.bSyncLyricsMarked = true;
2456 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
2457 char *lang_info = strndup((char *)pExtContent, 3);
2459 if (realCpyFrameNum > 3) {
2460 realCpyFrameNum -= 3;
2463 /*find start of lyrics */
2465 if (pExtContent[tmp] == 0x00) {
2466 if (pExtContent[tmp + 1] == 0x00) {
2467 realCpyFrameNum -= 2;
2477 /*pExtContent[tmp+1] value should't have encoding value */
2478 #ifdef __MMFILE_TEST_MODE__
2479 debug_msg("tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
2481 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2482 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2483 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2484 realCpyFrameNum -= 4;
2488 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2489 realCpyFrameNum -= 2;
2491 textEncodingType = AV_ID3V2_UTF16;
2492 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2493 realCpyFrameNum -= 2;
2495 textEncodingType = AV_ID3V2_UTF16_BE;
2496 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2497 realCpyFrameNum -= 3;
2499 textEncodingType = AV_ID3V2_UTF16;
2500 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2501 realCpyFrameNum -= 3;
2503 textEncodingType = AV_ID3V2_UTF16_BE;
2505 #ifdef __MMFILE_TEST_MODE__
2506 debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
2510 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2514 textEncodingType = AV_ID3V2_ISO_8859;
2517 #ifdef __MMFILE_TEST_MODE__
2518 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2521 char *char_set = NULL;
2522 if (textEncodingType == AV_ID3V2_ISO_8859) {
2523 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
2524 char_set = strdup("EUC-KR");
2526 char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
2528 _FREE_EX(lang_info);
2531 if (char_set == NULL) {
2532 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2534 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2538 #ifdef __MMFILE_TEST_MODE__
2539 debug_msg("failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2541 pInfo->unsynclyricsLen = 0;
2544 #ifdef __MMFILE_TEST_MODE__
2545 debug_msg("Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2547 pInfo->unsynclyricsLen = 0;
2551 #ifdef __MMFILE_TEST_MODE__
2552 debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
2554 pInfo->tagV2Info.bUnsyncLyricsMarked = true;
2555 mmfile_free(lang_info);
2556 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2557 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2559 #ifdef __MMFILE_TEST_MODE__
2560 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2563 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2567 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2570 sscanf(pInfo->pGenre, "%d", &int_genre);
2571 #ifdef __MMFILE_TEST_MODE__
2572 debug_msg("genre information is inteager [%d]\n", int_genre);
2575 /*Change int to string */
2576 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2577 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2578 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
2579 int tmp_genre_len = 0;
2581 memset(tmp_genre, 0, 6);
2582 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2584 tmp_genre_len = strlen(tmp_genre);
2585 if (tmp_genre_len > 0) {
2586 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2587 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2588 if (pInfo->pGenre) {
2589 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
2590 pInfo->pGenre[tmp_genre_len] = 0;
2597 pInfo->tagV2Info.bGenreMarked = true;
2598 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2599 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2601 #ifdef __MMFILE_TEST_MODE__
2602 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2604 pInfo->tagV2Info.bTrackNumMarked = true;
2605 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2606 pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2608 #ifdef __MMFILE_TEST_MODE__
2609 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2611 pInfo->tagV2Info.bEncByMarked = true;
2612 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2613 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2615 #ifdef __MMFILE_TEST_MODE__
2616 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2618 pInfo->tagV2Info.bURLMarked = true;
2619 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2620 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2622 #ifdef __MMFILE_TEST_MODE__
2623 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2625 pInfo->tagV2Info.bCopyRightMarked = true;
2626 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2627 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2629 #ifdef __MMFILE_TEST_MODE__
2630 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2632 pInfo->tagV2Info.bOriginArtistMarked = true;
2633 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2634 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2636 #ifdef __MMFILE_TEST_MODE__
2637 debug_msg("pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2639 pInfo->tagV2Info.bComposerMarked = true;
2640 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2641 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2643 #ifdef __MMFILE_TEST_MODE__
2644 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2646 pInfo->tagV2Info.bRecDateMarked = true;
2647 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2648 debug_msg("text encoding %d \n", textEncodingType);
2650 if (pExtContent[0] != '\0') {
2651 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
2652 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
2654 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
2655 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
2656 checkImgMimeTypeMax++;
2658 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
2660 pInfo->imageInfo.imgMimetypeLen = 0;
2661 #ifdef __MMFILE_TEST_MODE__
2662 debug_msg("APIC image's not included to MIME type\n");
2666 imgstartOffset += checkImgMimeTypeMax;
2668 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2669 pInfo->imageInfo.imgMimetypeLen = 0;
2670 debug_error("APIC NOT VALID");
2674 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2675 imgstartOffset++;/*endofMIME(1byte) */
2676 #ifdef __MMFILE_TEST_MODE__
2677 debug_msg("after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
2680 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2681 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2683 #ifdef __MMFILE_TEST_MODE__
2684 debug_msg("APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
2687 imgstartOffset++;/*PictureType(1byte) */
2688 #ifdef __MMFILE_TEST_MODE__
2689 debug_msg("after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
2692 if (pExtContent[imgstartOffset] != 0x0) {
2695 int new_dis_len = 0;
2696 unsigned char jpg_sign[3] = {0xff, 0xd8, 0xff};
2697 unsigned char png_sign[8] = {0x80, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
2698 char *tmp_desc = NULL;
2701 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2702 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2703 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2706 /*check end of image description*/
2707 if ((pExtContent[imgstartOffset + cur_pos + 1] == jpg_sign[0]) ||
2708 (pExtContent[imgstartOffset + cur_pos + 1] == png_sign[0])) {
2709 #ifdef __MMFILE_TEST_MODE__
2710 debug_msg("length of description (%d)", cur_pos);
2719 dis_len = cur_pos + 1;
2721 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2722 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2724 /*convert description*/
2725 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2726 #ifdef __MMFILE_TEST_MODE__
2727 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2729 mmfile_free(tmp_desc);
2731 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2732 imgstartOffset += cur_pos;
2734 pInfo->imageInfo.imgDesLen = 0;
2735 #ifdef __MMFILE_TEST_MODE__
2736 debug_msg("APIC image's not included to Description!!!\n");
2740 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2741 imgstartOffset++; /* endofDesceriptionType(1byte) */
2743 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2747 #ifdef __MMFILE_TEST_MODE__
2748 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2751 if (realCpyFrameNum - imgstartOffset > 0) {
2752 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2753 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2755 if (pInfo->imageInfo.pImageBuf != NULL) {
2756 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2757 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2760 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2761 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2763 #ifdef __MMFILE_TEST_MODE__
2764 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2767 #ifdef __MMFILE_TEST_MODE__
2768 debug_msg("pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
2771 #ifdef __MMFILE_TEST_MODE__
2772 debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
2773 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2777 #ifdef __MMFILE_TEST_MODE__
2778 debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
2779 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2783 checkImgMimeTypeMax = 0;
2786 pInfo->tagV2Info.bImageMarked = true;
2789 #ifdef __MMFILE_TEST_MODE__
2790 debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
2796 #ifdef __MMFILE_TEST_MODE__
2797 debug_msg("All of the pExtContent Values are NULL\n");
2801 curPos += purelyFramelen;
2802 if (purelyFramelen != 0)
2803 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2804 #ifdef __MMFILE_TEST_MODE__
2805 debug_msg("This Frame's size is Zero! purelyFramelen(%d)\n", purelyFramelen);
2809 if (pExtContent) _FREE_EX(pExtContent);
2810 memset(CompTmp, 0, 4);
2812 if (curPos < taglen) {
2813 needToloopv2taglen -= oneFrameLen;
2816 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2819 realCpyFrameNum = 0;
2820 textEncodingType = 0;
2826 release_characterset_array(charset_array);
2836 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
2838 unsigned long taglen = 0;
2839 unsigned long needToloopv2taglen;
2840 unsigned long oneFrameLen = 0;
2841 unsigned long v2numOfFrames = 0;
2842 unsigned long curPos = 0;
2844 unsigned char *pExtContent = NULL;
2845 unsigned long purelyFramelen = 0;
2846 unsigned int encodingOffSet = 0;
2847 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2848 int textEncodingType = 0;
2849 char **charset_array = NULL;
2850 const char *MIME_PRFIX = "image/";
2852 make_characterset_array(&charset_array);
2854 init_content_info(pInfo);
2856 taglen = pInfo->tagV2Info.tagLen;
2857 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2858 curPos = MP3_TAGv2_HEADER_LEN;
2860 #ifdef __MMFILE_TEST_MODE__
2861 debug_msg("ID3tag v224--------------------------------------------------------------\n");
2864 /* check Extended Header */
2865 if (buffer[5] & 0x40) {
2866 /* if extended header exists, skip it*/
2867 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2869 #ifdef __MMFILE_TEST_MODE__
2870 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2873 curPos += extendedHeaderLen;
2876 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2878 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2879 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2880 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2883 memcpy(CompTmp, &buffer[curPos], 4);
2886 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2887 oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
2888 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
2889 if (oneFrameLen > taglen - curPos)
2892 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2893 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2895 #ifdef __MMFILE_TEST_MODE__
2896 debug_msg("-----------------------------------------------------------------------------------\n");
2899 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2900 curPos += purelyFramelen;
2902 /*in case of UTF 16 encoding */
2903 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
2904 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2906 textEncodingType = AV_ID3V2_UTF16;
2907 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2909 textEncodingType = AV_ID3V2_UTF16_BE;
2910 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2912 textEncodingType = AV_ID3V2_UTF16;
2913 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2915 textEncodingType = AV_ID3V2_UTF16_BE;
2917 /*in case of UTF-16 BE encoding */
2918 if (buffer[curPos - purelyFramelen] == 0x02) {
2920 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2921 encodingOffSet++;/*null skip! */
2922 textEncodingType = AV_ID3V2_UTF16_BE;
2924 /*in case of UTF8 encoding */
2925 else if (buffer[curPos - purelyFramelen] == 0x03) {
2927 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2928 encodingOffSet++;/*null skip! */
2929 textEncodingType = AV_ID3V2_UTF8;
2931 /*in case of ISO-8859-1 encoding */
2933 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
2935 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2936 encodingOffSet++;/*less than 0x20 value skip! */
2937 textEncodingType = AV_ID3V2_ISO_8859;
2941 if (encodingOffSet < purelyFramelen) {
2942 realCpyFrameNum = purelyFramelen - encodingOffSet;
2943 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2944 memset(pExtContent, '\0', realCpyFrameNum + 3);
2946 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2947 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2948 #ifdef __MMFILE_TEST_MODE__
2949 debug_msg("get the new text ecoding type\n");
2951 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2955 if (textEncodingType > AV_ID3V2_MAX) {
2956 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2960 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2962 if (realCpyFrameNum > 0) {
2963 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2964 if (textEncodingType == AV_ID3V2_UTF8) {
2965 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2966 memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
2967 pInfo->pTitle[realCpyFrameNum] = '\0';
2968 /*string copy with '\0'*/
2969 pInfo->titleLen = realCpyFrameNum;
2970 _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
2972 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2975 #ifdef __MMFILE_TEST_MODE__
2976 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2978 pInfo->tagV2Info.bTitleMarked = true;
2980 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2981 if (textEncodingType == AV_ID3V2_UTF8) {
2982 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2983 memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
2984 pInfo->pArtist[realCpyFrameNum] = '\0';
2985 /*string copy with '\0'*/
2986 pInfo->artistLen = realCpyFrameNum;
2987 _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
2989 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2992 #ifdef __MMFILE_TEST_MODE__
2993 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2995 pInfo->tagV2Info.bArtistMarked = true;
2996 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2997 if (textEncodingType == AV_ID3V2_UTF8) {
2998 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2999 memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
3000 pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
3001 /*string copy with '\0'*/
3002 pInfo->album_artistLen = realCpyFrameNum;
3003 _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
3005 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3008 #ifdef __MMFILE_TEST_MODE__
3009 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3011 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3012 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3013 if (textEncodingType == AV_ID3V2_UTF8) {
3014 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3015 memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
3016 pInfo->pConductor[realCpyFrameNum] = '\0';
3017 /*string copy with '\0'*/
3018 pInfo->conductorLen = realCpyFrameNum;
3019 _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
3021 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3024 #ifdef __MMFILE_TEST_MODE__
3025 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3027 pInfo->tagV2Info.bConductorMarked = true;
3028 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3029 if (textEncodingType == AV_ID3V2_UTF8) {
3030 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3031 memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
3032 pInfo->pAlbum[realCpyFrameNum] = '\0';
3033 /*string copy with '\0'*/
3034 pInfo->albumLen = realCpyFrameNum;
3035 _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
3037 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3040 #ifdef __MMFILE_TEST_MODE__
3041 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3043 pInfo->tagV2Info.bAlbumMarked = true;
3044 } 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 */
3045 if (textEncodingType == AV_ID3V2_UTF8) {
3046 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3047 memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
3048 pInfo->pYear[realCpyFrameNum] = '\0';
3049 /*string copy with '\0'*/
3050 pInfo->yearLen = realCpyFrameNum;
3051 _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
3053 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3056 #ifdef __MMFILE_TEST_MODE__
3057 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3059 pInfo->tagV2Info.bYearMarked = true;
3060 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3061 if (realCpyFrameNum > 3) {
3062 realCpyFrameNum -= 3;
3065 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3066 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3067 realCpyFrameNum -= 4;
3071 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3072 realCpyFrameNum -= 2;
3074 textEncodingType = AV_ID3V2_UTF16;
3076 #ifdef __MMFILE_TEST_MODE__
3077 debug_msg("pInfo->pComment Never Get Here!!\n");
3080 } else if (textEncodingType == AV_ID3V2_UTF8) {
3081 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3085 textEncodingType = AV_ID3V2_UTF8;
3087 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3091 textEncodingType = AV_ID3V2_ISO_8859;
3094 #ifdef __MMFILE_TEST_MODE__
3095 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3098 if (textEncodingType == AV_ID3V2_UTF8) {
3099 pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3100 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
3101 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
3102 pInfo->pComment[realCpyFrameNum] = '\0';
3103 /*string copy with '\0'*/
3104 pInfo->commentLen = realCpyFrameNum;
3105 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
3107 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3110 #ifdef __MMFILE_TEST_MODE__
3111 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3117 #ifdef __MMFILE_TEST_MODE__
3118 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3120 pInfo->tagV2Info.bDescriptionMarked = true;
3121 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3124 int copy_start_pos = tmp;
3125 AvSynclyricsInfo *synclyrics_info = NULL;
3126 GList *synclyrics_info_list = NULL;
3128 if (realCpyFrameNum > 5) {
3129 realCpyFrameNum -= 5;
3132 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3133 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3134 realCpyFrameNum -= 4;
3138 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3139 realCpyFrameNum -= 2;
3141 textEncodingType = AV_ID3V2_UTF16;
3143 #ifdef __MMFILE_TEST_MODE__
3144 debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
3147 } else if (textEncodingType == AV_ID3V2_UTF8) {
3148 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3152 textEncodingType = AV_ID3V2_UTF8;
3154 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3158 textEncodingType = AV_ID3V2_ISO_8859;
3161 #ifdef __MMFILE_TEST_MODE__
3162 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3165 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3166 #ifdef __MMFILE_TEST_MODE__
3167 debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3169 pInfo->syncLyricsNum = 0;
3171 if (textEncodingType == AV_ID3V2_UTF16) {
3172 debug_warning("[AV_ID3V2_UTF16] not implemented\n");
3173 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3174 debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
3176 for (idx = 0; idx < realCpyFrameNum; idx++) {
3177 if (pExtContent[tmp + idx] == 0x00) {
3178 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3180 if (textEncodingType == AV_ID3V2_UTF8) {
3181 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3182 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3183 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3184 synclyrics_info->lyric_info[copy_len + 1] = '\0';
3186 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3189 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];
3191 copy_start_pos = tmp + idx + 1;
3192 #ifdef __MMFILE_TEST_MODE__
3193 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);
3196 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3200 pInfo->pSyncLyrics = synclyrics_info_list;
3201 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3205 #ifdef __MMFILE_TEST_MODE__
3206 debug_msg("SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3211 pInfo->tagV2Info.bSyncLyricsMarked = true;
3212 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3213 if (realCpyFrameNum > 3) {
3214 realCpyFrameNum -= 3;
3217 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3218 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3219 realCpyFrameNum -= 4;
3223 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3224 realCpyFrameNum -= 2;
3226 textEncodingType = AV_ID3V2_UTF16;
3228 #ifdef __MMFILE_TEST_MODE__
3229 debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
3232 } else if (textEncodingType == AV_ID3V2_UTF8) {
3233 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3237 textEncodingType = AV_ID3V2_UTF8;
3239 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3243 textEncodingType = AV_ID3V2_ISO_8859;
3246 #ifdef __MMFILE_TEST_MODE__
3247 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3250 if (textEncodingType == AV_ID3V2_UTF8) {
3251 pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3253 if (pInfo->pUnsyncLyrics != NULL) {
3254 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3255 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3256 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3257 /*string copy with '\0'*/
3258 pInfo->unsynclyricsLen = realCpyFrameNum;
3259 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3261 debug_error("out of memoryu for SyncLyrics\n");
3264 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3267 #ifdef __MMFILE_TEST_MODE__
3268 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3274 #ifdef __MMFILE_TEST_MODE__
3275 debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3277 pInfo->tagV2Info.bDescriptionMarked = true;
3278 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3279 if (textEncodingType == AV_ID3V2_UTF8) {
3280 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3281 memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3282 pInfo->pGenre[realCpyFrameNum] = '\0';
3283 /*string copy with '\0'*/
3284 pInfo->genreLen = realCpyFrameNum;
3285 _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3287 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3290 #ifdef __MMFILE_TEST_MODE__
3291 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3294 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3298 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3301 sscanf(pInfo->pGenre, "%d", &int_genre);
3302 #ifdef __MMFILE_TEST_MODE__
3303 debug_msg("genre information is inteager [%d]\n", int_genre);
3306 /*Change int to string */
3307 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3308 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3309 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3310 int tmp_genre_len = 0;
3312 memset(tmp_genre, 0, 6);
3313 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3315 tmp_genre_len = strlen(tmp_genre);
3316 if (tmp_genre_len > 0) {
3317 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3318 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3319 if (pInfo->pGenre) {
3320 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
3321 pInfo->pGenre[tmp_genre_len] = 0;
3328 pInfo->tagV2Info.bGenreMarked = true;
3329 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3330 if (textEncodingType == AV_ID3V2_UTF8) {
3331 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3332 memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3333 pInfo->pTrackNum[realCpyFrameNum] = '\0';
3334 /*string copy with '\0'*/
3335 pInfo->tracknumLen = realCpyFrameNum;
3336 _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3338 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3342 #ifdef __MMFILE_TEST_MODE__
3343 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3345 pInfo->tagV2Info.bTrackNumMarked = true;
3346 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3347 if (textEncodingType == AV_ID3V2_UTF8) {
3348 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3349 memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3350 pInfo->pEncBy[realCpyFrameNum] = '\0';
3351 /*string copy with '\0'*/
3352 pInfo->encbyLen = realCpyFrameNum;
3353 _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3355 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3358 #ifdef __MMFILE_TEST_MODE__
3359 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3361 pInfo->tagV2Info.bEncByMarked = true;
3362 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3363 if (textEncodingType == AV_ID3V2_UTF8) {
3364 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3365 memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3366 pInfo->pURL[realCpyFrameNum] = '\0';
3367 /*string copy with '\0'*/
3368 pInfo->urlLen = realCpyFrameNum;
3369 _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3371 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3374 #ifdef __MMFILE_TEST_MODE__
3375 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3377 pInfo->tagV2Info.bURLMarked = true;
3378 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3379 if (textEncodingType == AV_ID3V2_UTF8) {
3380 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3381 memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3382 pInfo->pCopyright[realCpyFrameNum] = '\0';
3383 /*string copy with '\0'*/
3384 pInfo->copyrightLen = realCpyFrameNum;
3385 _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3387 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3390 #ifdef __MMFILE_TEST_MODE__
3391 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3393 pInfo->tagV2Info.bCopyRightMarked = true;
3394 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3395 if (textEncodingType == AV_ID3V2_UTF8) {
3396 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3397 memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3398 pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3399 /*string copy with '\0'*/
3400 pInfo->originartistLen = realCpyFrameNum;
3401 _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3403 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3406 #ifdef __MMFILE_TEST_MODE__
3407 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3409 pInfo->tagV2Info.bOriginArtistMarked = true;
3410 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3411 if (textEncodingType == AV_ID3V2_UTF8) {
3412 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3413 memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3414 pInfo->pComposer[realCpyFrameNum] = '\0';
3415 /*string copy with '\0'*/
3416 pInfo->composerLen = realCpyFrameNum;
3417 _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3419 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3422 #ifdef __MMFILE_TEST_MODE__
3423 debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3425 pInfo->tagV2Info.bComposerMarked = true;
3426 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) { /*TYER(year) and TRDA are replaced by the TDRC */
3427 if (textEncodingType == AV_ID3V2_UTF8) {
3428 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3429 memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3430 pInfo->pRecDate[realCpyFrameNum] = '\0';
3431 /*string copy with '\0'*/
3432 pInfo->recdateLen = realCpyFrameNum;
3433 _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3435 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3438 #ifdef __MMFILE_TEST_MODE__
3439 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3441 pInfo->tagV2Info.bRecDateMarked = true;
3442 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3443 if (textEncodingType == AV_ID3V2_UTF8) {
3444 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3445 memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3446 pInfo->pContentGroup[realCpyFrameNum] = '\0';
3447 /*string copy with '\0'*/
3448 pInfo->contentGroupLen = realCpyFrameNum;
3449 _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3451 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3453 #ifdef __MMFILE_TEST_MODE__
3454 debug_msg("pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3456 pInfo->tagV2Info.bContentGroupMarked = true;
3457 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3458 if (pExtContent[0] != '\0') {
3459 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3460 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3462 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3463 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3464 checkImgMimeTypeMax++;
3466 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3468 pInfo->imageInfo.imgMimetypeLen = 0;
3471 imgstartOffset += checkImgMimeTypeMax;
3473 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3474 pInfo->imageInfo.imgMimetypeLen = 0;
3475 debug_error("APIC NOT VALID");
3479 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3480 imgstartOffset++;/*endofMIME(1byte) */
3482 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3483 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3485 imgstartOffset++;/*PictureType(1byte) */
3487 if (pExtContent[imgstartOffset] != 0x0) {
3490 int new_dis_len = 0;
3491 unsigned char jpg_sign[3] = {0xff, 0xd8, 0xff};
3492 unsigned char png_sign[8] = {0x80, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
3493 char *tmp_desc = NULL;
3496 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3497 if (realCpyFrameNum < imgstartOffset + cur_pos) {
3498 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3501 /*check end of image description*/
3502 if ((pExtContent[imgstartOffset + cur_pos + 1] == jpg_sign[0]) ||
3503 (pExtContent[imgstartOffset + cur_pos + 1] == png_sign[0])) {
3504 #ifdef __MMFILE_TEST_MODE__
3505 debug_msg("length of description (%d)", cur_pos);
3514 dis_len = cur_pos + 1;
3516 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3518 if(tmp_desc != NULL) {
3519 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3520 debug_msg("tmp_desc %s\n", tmp_desc);
3522 /*convert description*/
3523 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3524 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3525 mmfile_free(tmp_desc);
3527 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3530 imgstartOffset += cur_pos;
3532 pInfo->imageInfo.imgDesLen = 0;
3535 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3536 imgstartOffset++; /* endofDesceriptionType(1byte) */
3538 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
3542 #ifdef __MMFILE_TEST_MODE__
3543 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3546 if (realCpyFrameNum - imgstartOffset > 0) {
3547 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3548 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3550 if (pInfo->imageInfo.pImageBuf != NULL) {
3551 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3552 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3555 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3556 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3558 #ifdef __MMFILE_TEST_MODE__
3559 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3565 checkImgMimeTypeMax = 0;
3568 pInfo->tagV2Info.bImageMarked = true;
3570 #ifdef __MMFILE_TEST_MODE__
3571 debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3577 #ifdef __MMFILE_TEST_MODE__
3578 debug_msg("mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
3583 curPos += purelyFramelen;
3584 if (purelyFramelen != 0)
3585 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3588 if (pExtContent) _FREE_EX(pExtContent);
3589 memset(CompTmp, 0, 4);
3590 if (curPos < taglen) {
3591 needToloopv2taglen -= oneFrameLen;
3594 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3598 realCpyFrameNum = 0;
3599 textEncodingType = 0;
3605 release_characterset_array(charset_array);
3615 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3617 char *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
3618 bool bAdditionGenre = false /*, bMpegAudioFrame = false*/;
3619 int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
3621 char *pGenreForUTF16;
3623 unsigned char genre = pInfo->genre;
3625 /* for Genre Info */
3626 if (pInfo->tagV2Info.bGenreMarked == false) {
3627 if (pInfo->bV1tagFound == true) {
3628 #ifdef __MMFILE_TEST_MODE__
3629 debug_msg("Genre: %d\n", genre);
3634 if (MpegAudio_Genre[genre] != NULL) {
3635 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
3636 if (pInfo->genreLen > 0) {
3637 /* Give space for NULL character. Hence added "+1" */
3638 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3639 if (pInfo->pGenre) {
3640 strncpy(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen);
3641 pInfo->pGenre[pInfo->genreLen] = '\0';
3646 #ifdef __MMFILE_TEST_MODE__
3647 debug_msg("Genre was not Found.\n");
3650 } else if (pInfo->tagV2Info.bGenreMarked == true) {
3651 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
3652 pInfo->pGenre[pInfo->genreLen + 1] = '\0';
3653 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
3655 pGenreForUTF16 = (char *)pInfo->pGenre;
3657 if (WmConvert2LCode(mpegAudioGenre, sizeof(char) * AV_WM_LOCALCODE_SIZE_MAX * (pInfo->genreLen + 1), pGenreForUTF16)) {
3658 pInfo->genreLen = strlen(mpegAudioGenre);
3659 mpegAudioGenre[pInfo->genreLen] = '\0';
3663 #ifdef __MMFILE_TEST_MODE__
3664 debug_msg("pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
3666 if (pInfo->pGenre) {
3667 pInfo->genreLen = strlen(pInfo->pGenre);
3668 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3669 if (mpegAudioGenre != NULL) {
3670 mpegAudioGenre[pInfo->genreLen] = '\0';
3671 strncpy(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen);
3674 pInfo->genreLen = 0;
3678 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3681 if (mpegAudioGenre != NULL) {
3684 * (XXX) XXX is 0 - 148
3686 pInfo->genreLen = strlen(mpegAudioGenre);
3687 if (pInfo->genreLen >= 3 &&
3688 mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
3689 bAdditionGenre = true;
3690 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
3691 if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
3692 bAdditionGenre = false;
3698 if (bAdditionGenre == true) {
3699 idv2IntGenre = atoi(mpegAudioGenre + 1);
3701 if (idv2IntGenre > 147 || idv2IntGenre < 0)
3704 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
3705 pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
3706 if (pInfo->genreLen > 0) {
3707 /* Give space for NULL character. Hence added "+1" */
3708 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3709 if (pInfo->pGenre) {
3710 strncpy(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen);
3711 pInfo->pGenre[pInfo->genreLen] = 0;
3715 #ifdef __MMFILE_TEST_MODE__
3716 debug_msg("pInfo->pGenre = %s\n", pInfo->pGenre);
3718 } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
3723 /* Give space for NULL character. Hence added "+1" */
3724 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3725 if (pInfo->pGenre) {
3726 strncpy(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen);
3727 pInfo->pGenre[pInfo->genreLen] = '\0';
3729 #ifdef __MMFILE_TEST_MODE__
3730 debug_msg("pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
3733 #ifdef __MMFILE_TEST_MODE__
3734 debug_msg("Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
3738 #ifdef __MMFILE_TEST_MODE__
3739 debug_msg("mpegAudioGenre = %x\n", mpegAudioGenre);
3743 _FREE_EX(mpegAudioGenre);
3746 #ifdef __MMFILE_TEST_MODE__
3747 debug_msg("Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
3753 void mm_file_free_synclyrics_list(GList *synclyrics_list)
3757 AvSynclyricsInfo *synclyrics_info = NULL;
3759 if (synclyrics_list == NULL) {
3763 list_len = g_list_length(synclyrics_list);
3764 for (idx = 0; idx < list_len; idx++) {
3765 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
3767 free(synclyrics_info->lyric_info);
3768 synclyrics_info->lyric_info = NULL;
3770 free(synclyrics_info);
3771 synclyrics_info = NULL;
3774 if (synclyrics_list != NULL) {
3775 g_list_free(synclyrics_list);
3776 synclyrics_list = NULL;