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 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);
1761 memset(pExtContent, '\0', realCpyFrameNum + 3);
1763 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
1765 if (realCpyFrameNum > 0) {
1766 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
1767 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
1769 #ifdef __MMFILE_TEST_MODE__
1770 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
1772 pInfo->tagV2Info.bTitleMarked = true;
1773 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
1774 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
1776 #ifdef __MMFILE_TEST_MODE__
1777 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
1779 pInfo->tagV2Info.bArtistMarked = true;
1780 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
1781 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
1783 #ifdef __MMFILE_TEST_MODE__
1784 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
1786 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
1787 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
1788 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
1790 #ifdef __MMFILE_TEST_MODE__
1791 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
1793 pInfo->tagV2Info.bConductorMarked = true;
1794 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
1795 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
1797 #ifdef __MMFILE_TEST_MODE__
1798 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
1800 pInfo->tagV2Info.bAlbumMarked = true;
1801 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
1802 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
1804 #ifdef __MMFILE_TEST_MODE__
1805 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
1807 pInfo->tagV2Info.bYearMarked = true;
1808 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
1809 /*skip language data! */
1810 if (realCpyFrameNum > 4) {
1811 realCpyFrameNum -= 4;
1814 /*pExtContent[tmp+1] value should't have encoding value */
1815 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1816 if (pExtContent[tmp - 1] == 0x00)
1817 textEncodingType = AV_ID3V2_ISO_8859;
1819 textEncodingType = AV_ID3V2_UTF16;
1821 pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
1823 #ifdef __MMFILE_TEST_MODE__
1824 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
1826 pInfo->tagV2Info.bDescriptionMarked = true;
1828 #ifdef __MMFILE_TEST_MODE__
1829 debug_msg("mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1833 #ifdef __MMFILE_TEST_MODE__
1834 debug_msg("mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1839 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
1840 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
1842 #ifdef __MMFILE_TEST_MODE__
1843 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
1846 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
1850 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
1853 sscanf(pInfo->pGenre, "%d", &int_genre);
1854 #ifdef __MMFILE_TEST_MODE__
1855 debug_msg("genre information is inteager [%d]\n", int_genre);
1858 /*Change int to string */
1859 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
1860 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
1861 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
1862 int tmp_genre_len = 0;
1864 memset(tmp_genre, 0, 6);
1865 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
1867 tmp_genre_len = strlen(tmp_genre);
1868 if (tmp_genre_len > 0) {
1869 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
1870 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
1871 if (pInfo->pGenre) {
1872 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
1873 pInfo->pGenre[tmp_genre_len] = 0;
1880 pInfo->tagV2Info.bGenreMarked = true;
1881 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
1882 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
1884 #ifdef __MMFILE_TEST_MODE__
1885 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
1887 pInfo->tagV2Info.bTrackNumMarked = true;
1888 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
1889 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
1891 #ifdef __MMFILE_TEST_MODE__
1892 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
1894 pInfo->tagV2Info.bEncByMarked = true;
1895 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
1896 if (realCpyFrameNum > 4) {
1897 /*skip language data! */
1898 realCpyFrameNum -= 4;
1901 /*pExtContent[tmp+1] value should't have null value */
1902 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
1903 if (pExtContent[tmp - 1] == 0x00)
1904 textEncodingType = AV_ID3V2_ISO_8859;
1906 textEncodingType = AV_ID3V2_UTF16;
1908 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
1910 #ifdef __MMFILE_TEST_MODE__
1911 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
1913 pInfo->tagV2Info.bURLMarked = true;
1915 #ifdef __MMFILE_TEST_MODE__
1916 debug_msg("mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
1920 #ifdef __MMFILE_TEST_MODE__
1921 debug_msg("mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
1925 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
1926 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
1928 #ifdef __MMFILE_TEST_MODE__
1929 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
1931 pInfo->tagV2Info.bCopyRightMarked = true;
1932 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
1933 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
1935 #ifdef __MMFILE_TEST_MODE__
1936 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
1938 pInfo->tagV2Info.bOriginArtistMarked = true;
1939 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
1940 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
1942 #ifdef __MMFILE_TEST_MODE__
1943 debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
1945 pInfo->tagV2Info.bComposerMarked = true;
1946 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
1947 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
1949 #ifdef __MMFILE_TEST_MODE__
1950 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
1952 pInfo->tagV2Info.bRecDateMarked = true;
1953 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
1954 if (pExtContent[0] != 0) {
1955 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
1956 pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
1958 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
1959 pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
1963 #ifdef __MMFILE_TEST_MODE__
1964 debug_msg("mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
1968 imgstartOffset += checkImgExtMax;
1970 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
1971 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
1973 imgstartOffset++;/*PictureType(1byte) */
1975 if (pExtContent[imgstartOffset] != 0x0) {
1978 int new_dis_len = 0;
1979 char jpg_sign[3] = {0xff, 0xd8, 0xff};
1980 char png_sign[8] = {0x80, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
1981 char *tmp_desc = NULL;
1984 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
1985 if (realCpyFrameNum < imgstartOffset + cur_pos) {
1986 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
1989 /*check end of image description*/
1990 if ((pExtContent[imgstartOffset + cur_pos + 1] == jpg_sign[0]) ||
1991 (pExtContent[imgstartOffset + cur_pos + 1] == png_sign[0])) {
1992 #ifdef __MMFILE_TEST_MODE__
1993 debug_msg("length of description (%d)", cur_pos);
2002 dis_len = cur_pos + 1;
2004 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2006 if(tmp_desc != NULL) {
2007 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2009 /*convert description*/
2010 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2011 mmfile_free(tmp_desc);
2013 #ifdef __MMFILE_TEST_MODE__
2014 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2016 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2019 imgstartOffset += cur_pos;
2021 pInfo->imageInfo.imgDesLen = 0;
2024 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2025 imgstartOffset++; /* endofDesceriptionType(1byte) */
2027 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2031 #ifdef __MMFILE_TEST_MODE__
2032 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2035 if (realCpyFrameNum - imgstartOffset > 0) {
2036 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2037 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2039 if (pInfo->imageInfo.pImageBuf != NULL) {
2040 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2041 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2044 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2045 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2047 #ifdef __MMFILE_TEST_MODE__
2048 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2053 /*checkImgMimeTypeMax = 0;*/
2057 pInfo->tagV2Info.bImageMarked = true;
2064 curPos += purelyFramelen;
2065 if (purelyFramelen != 0)
2066 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2069 if (pExtContent) _FREE_EX(pExtContent);
2070 memset(CompTmp, 0, 4);
2071 if (curPos < taglen) {
2072 needToloopv2taglen -= oneFrameLen;
2075 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2078 realCpyFrameNum = 0;
2079 textEncodingType = 0;
2085 release_characterset_array(charset_array);
2095 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2097 unsigned long taglen = 0;
2098 unsigned long needToloopv2taglen;
2099 unsigned long oneFrameLen = 0;
2100 unsigned long v2numOfFrames = 0;
2101 unsigned long curPos = 0;
2103 unsigned char *pExtContent = NULL;
2104 unsigned long purelyFramelen = 0;
2105 unsigned int encodingOffSet = 0;
2106 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2107 int textEncodingType = 0;
2108 char **charset_array = NULL;
2109 const char *MIME_PRFIX = "image/";
2111 make_characterset_array(&charset_array);
2113 init_content_info(pInfo);
2115 taglen = pInfo->tagV2Info.tagLen;
2116 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2117 curPos = MP3_TAGv2_HEADER_LEN;
2119 #ifdef __MMFILE_TEST_MODE__
2120 debug_msg("ID3tag v223--------------------------------------------------------------\n");
2123 /* check Extended Header */
2124 if (buffer[5] & 0x40) {
2125 /* if extended header exists, skip it*/
2126 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2128 #ifdef __MMFILE_TEST_MODE__
2129 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2132 curPos += extendedHeaderLen;
2136 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2138 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2139 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2140 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2143 memcpy(CompTmp, &buffer[curPos], 4);
2146 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2147 oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2148 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2150 #ifdef __MMFILE_TEST_MODE__
2151 debug_msg("----------------------------------------------------------------------------------------------------\n");
2154 if (oneFrameLen > taglen - curPos)
2157 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2158 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2160 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2161 curPos += purelyFramelen;
2163 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2165 #ifdef __MMFILE_TEST_MODE__
2166 debug_msg("this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2168 textEncodingType = AV_ID3V2_UTF16;
2169 } else if (IS_ENCODEDBY_UTF16_R(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_BE;
2175 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
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;
2181 } else if (IS_ENCODEDBY_UTF16_R(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_BE;
2188 if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2189 #ifdef __MMFILE_TEST_MODE__
2190 debug_msg("encodingOffset will be set to 1\n");
2195 #ifdef __MMFILE_TEST_MODE__
2196 debug_msg("Finding encodingOffset\n");
2199 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2202 textEncodingType = AV_ID3V2_ISO_8859;
2203 #ifdef __MMFILE_TEST_MODE__
2204 debug_msg("this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2208 if (encodingOffSet < purelyFramelen) {
2209 realCpyFrameNum = purelyFramelen - encodingOffSet;
2210 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2211 memset(pExtContent, '\0', realCpyFrameNum + 3);
2213 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2214 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2215 #ifdef __MMFILE_TEST_MODE__
2216 debug_msg("get the new text ecoding type\n");
2218 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2222 if (textEncodingType > AV_ID3V2_MAX) {
2223 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2227 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2228 if (realCpyFrameNum > 0) {
2229 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2230 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2232 #ifdef __MMFILE_TEST_MODE__
2233 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2235 pInfo->tagV2Info.bTitleMarked = true;
2237 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2238 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2240 #ifdef __MMFILE_TEST_MODE__
2241 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2243 pInfo->tagV2Info.bArtistMarked = true;
2244 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2245 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2247 #ifdef __MMFILE_TEST_MODE__
2248 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2250 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2251 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2252 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2254 #ifdef __MMFILE_TEST_MODE__
2255 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2257 pInfo->tagV2Info.bConductorMarked = true;
2258 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2259 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2261 #ifdef __MMFILE_TEST_MODE__
2262 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2264 pInfo->tagV2Info.bAlbumMarked = true;
2265 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2266 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2268 #ifdef __MMFILE_TEST_MODE__
2269 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2271 pInfo->tagV2Info.bYearMarked = true;
2272 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2273 if (realCpyFrameNum > 3) {
2274 realCpyFrameNum -= 3;
2277 /*pExtContent[tmp+1] value should't have encoding value */
2278 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2279 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2280 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2281 realCpyFrameNum -= 4;
2285 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2286 realCpyFrameNum -= 2;
2288 textEncodingType = AV_ID3V2_UTF16;
2289 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2290 realCpyFrameNum -= 2;
2292 textEncodingType = AV_ID3V2_UTF16_BE;
2293 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2294 realCpyFrameNum -= 3;
2296 textEncodingType = AV_ID3V2_UTF16;
2297 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2298 realCpyFrameNum -= 3;
2300 textEncodingType = AV_ID3V2_UTF16_BE;
2302 #ifdef __MMFILE_TEST_MODE__
2303 debug_msg("pInfo->pComment Never Get Here!!\n");
2307 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2311 textEncodingType = AV_ID3V2_ISO_8859;
2314 #ifdef __MMFILE_TEST_MODE__
2315 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2318 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2320 #ifdef __MMFILE_TEST_MODE__
2321 debug_msg("failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2323 pInfo->commentLen = 0;
2326 #ifdef __MMFILE_TEST_MODE__
2327 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2329 pInfo->commentLen = 0;
2333 #ifdef __MMFILE_TEST_MODE__
2334 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2336 pInfo->tagV2Info.bDescriptionMarked = true;
2337 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2340 int copy_start_pos = tmp;
2341 AvSynclyricsInfo *synclyrics_info = NULL;
2342 GList *synclyrics_info_list = NULL;
2344 if (realCpyFrameNum > 5) {
2345 realCpyFrameNum -= 5;
2348 /*pExtContent[tmp+1] value should't have encoding value */
2349 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2350 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2351 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2352 realCpyFrameNum -= 4;
2356 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2357 realCpyFrameNum -= 2;
2359 textEncodingType = AV_ID3V2_UTF16;
2360 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2361 realCpyFrameNum -= 2;
2363 textEncodingType = AV_ID3V2_UTF16_BE;
2364 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2365 realCpyFrameNum -= 3;
2367 textEncodingType = AV_ID3V2_UTF16;
2368 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2369 realCpyFrameNum -= 3;
2371 textEncodingType = AV_ID3V2_UTF16_BE;
2373 #ifdef __MMFILE_TEST_MODE__
2374 debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
2378 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2382 textEncodingType = AV_ID3V2_ISO_8859;
2385 #ifdef __MMFILE_TEST_MODE__
2386 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2389 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2390 #ifdef __MMFILE_TEST_MODE__
2391 debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
2393 pInfo->syncLyricsNum = 0;
2395 if (textEncodingType == AV_ID3V2_UTF16) {
2396 debug_warning("[AV_ID3V2_UTF16] not implemented\n");
2397 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
2398 debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
2400 for (idx = 0; idx < realCpyFrameNum; idx++) {
2401 if (pExtContent[tmp + idx] == 0x00) {
2402 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
2404 if (synclyrics_info != NULL) {
2405 if (textEncodingType == AV_ID3V2_UTF8) {
2406 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
2407 if (synclyrics_info->lyric_info != NULL) {
2408 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
2409 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
2410 synclyrics_info->lyric_info[copy_len + 1] = '\0';
2413 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);
2416 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];
2418 copy_start_pos = tmp + idx + 1;
2419 #ifdef __MMFILE_TEST_MODE__
2420 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);
2423 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
2428 pInfo->pSyncLyrics = synclyrics_info_list;
2429 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
2433 #ifdef __MMFILE_TEST_MODE__
2434 debug_msg("failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2436 pInfo->syncLyricsNum = 0;
2439 #ifdef __MMFILE_TEST_MODE__
2440 debug_msg("Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2442 pInfo->syncLyricsNum = 0;
2446 #ifdef __MMFILE_TEST_MODE__
2447 debug_msg("pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
2449 pInfo->tagV2Info.bSyncLyricsMarked = true;
2450 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
2451 char *lang_info = strndup((char *)pExtContent, 3);
2453 if (realCpyFrameNum > 3) {
2454 realCpyFrameNum -= 3;
2457 /*find start of lyrics */
2459 if (pExtContent[tmp] == 0x00) {
2460 if (pExtContent[tmp + 1] == 0x00) {
2461 realCpyFrameNum -= 2;
2471 /*pExtContent[tmp+1] value should't have encoding value */
2472 #ifdef __MMFILE_TEST_MODE__
2473 debug_msg("tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
2475 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2476 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2477 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2478 realCpyFrameNum -= 4;
2482 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2483 realCpyFrameNum -= 2;
2485 textEncodingType = AV_ID3V2_UTF16;
2486 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2487 realCpyFrameNum -= 2;
2489 textEncodingType = AV_ID3V2_UTF16_BE;
2490 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2491 realCpyFrameNum -= 3;
2493 textEncodingType = AV_ID3V2_UTF16;
2494 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2495 realCpyFrameNum -= 3;
2497 textEncodingType = AV_ID3V2_UTF16_BE;
2499 #ifdef __MMFILE_TEST_MODE__
2500 debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
2504 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2508 textEncodingType = AV_ID3V2_ISO_8859;
2511 #ifdef __MMFILE_TEST_MODE__
2512 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2515 char *char_set = NULL;
2516 if (textEncodingType == AV_ID3V2_ISO_8859) {
2517 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
2518 char_set = strdup("EUC-KR");
2520 char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
2522 _FREE_EX(lang_info);
2525 if (char_set == NULL) {
2526 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2528 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
2532 #ifdef __MMFILE_TEST_MODE__
2533 debug_msg("failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%d)\n", tmp, purelyFramelen - encodingOffSet);
2535 pInfo->unsynclyricsLen = 0;
2538 #ifdef __MMFILE_TEST_MODE__
2539 debug_msg("Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2541 pInfo->unsynclyricsLen = 0;
2545 #ifdef __MMFILE_TEST_MODE__
2546 debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
2548 pInfo->tagV2Info.bUnsyncLyricsMarked = true;
2549 mmfile_free(lang_info);
2550 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2551 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2553 #ifdef __MMFILE_TEST_MODE__
2554 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2557 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2561 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2564 sscanf(pInfo->pGenre, "%d", &int_genre);
2565 #ifdef __MMFILE_TEST_MODE__
2566 debug_msg("genre information is inteager [%d]\n", int_genre);
2569 /*Change int to string */
2570 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2571 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2572 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
2573 int tmp_genre_len = 0;
2575 memset(tmp_genre, 0, 6);
2576 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2578 tmp_genre_len = strlen(tmp_genre);
2579 if (tmp_genre_len > 0) {
2580 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2581 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2582 if (pInfo->pGenre) {
2583 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
2584 pInfo->pGenre[tmp_genre_len] = 0;
2591 pInfo->tagV2Info.bGenreMarked = true;
2592 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2593 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2595 #ifdef __MMFILE_TEST_MODE__
2596 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2598 pInfo->tagV2Info.bTrackNumMarked = true;
2599 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2600 pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2602 #ifdef __MMFILE_TEST_MODE__
2603 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2605 pInfo->tagV2Info.bEncByMarked = true;
2606 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2607 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2609 #ifdef __MMFILE_TEST_MODE__
2610 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2612 pInfo->tagV2Info.bURLMarked = true;
2613 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2614 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2616 #ifdef __MMFILE_TEST_MODE__
2617 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2619 pInfo->tagV2Info.bCopyRightMarked = true;
2620 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2621 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2623 #ifdef __MMFILE_TEST_MODE__
2624 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2626 pInfo->tagV2Info.bOriginArtistMarked = true;
2627 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2628 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2630 #ifdef __MMFILE_TEST_MODE__
2631 debug_msg("pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2633 pInfo->tagV2Info.bComposerMarked = true;
2634 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2635 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2637 #ifdef __MMFILE_TEST_MODE__
2638 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2640 pInfo->tagV2Info.bRecDateMarked = true;
2641 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2642 debug_msg("text encoding %d \n", textEncodingType);
2644 if (pExtContent[0] != '\0') {
2645 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
2646 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
2648 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
2649 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
2650 checkImgMimeTypeMax++;
2652 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
2654 pInfo->imageInfo.imgMimetypeLen = 0;
2655 #ifdef __MMFILE_TEST_MODE__
2656 debug_msg("APIC image's not included to MIME type\n");
2660 imgstartOffset += checkImgMimeTypeMax;
2662 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
2663 pInfo->imageInfo.imgMimetypeLen = 0;
2664 debug_error("APIC NOT VALID");
2668 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2669 imgstartOffset++;/*endofMIME(1byte) */
2670 #ifdef __MMFILE_TEST_MODE__
2671 debug_msg("after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
2674 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2675 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2677 #ifdef __MMFILE_TEST_MODE__
2678 debug_msg("APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
2681 imgstartOffset++;/*PictureType(1byte) */
2682 #ifdef __MMFILE_TEST_MODE__
2683 debug_msg("after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
2686 if (pExtContent[imgstartOffset] != 0x0) {
2689 int new_dis_len = 0;
2690 char jpg_sign[3] = {0xff, 0xd8, 0xff};
2691 char png_sign[8] = {0x80, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
2692 char *tmp_desc = NULL;
2695 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2696 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2697 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2700 /*check end of image description*/
2701 if ((pExtContent[imgstartOffset + cur_pos + 1] == jpg_sign[0]) ||
2702 (pExtContent[imgstartOffset + cur_pos + 1] == png_sign[0])) {
2703 #ifdef __MMFILE_TEST_MODE__
2704 debug_msg("length of description (%d)", cur_pos);
2713 dis_len = cur_pos + 1;
2715 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2716 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2718 /*convert description*/
2719 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2720 #ifdef __MMFILE_TEST_MODE__
2721 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2723 mmfile_free(tmp_desc);
2725 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2726 imgstartOffset += cur_pos;
2728 pInfo->imageInfo.imgDesLen = 0;
2729 #ifdef __MMFILE_TEST_MODE__
2730 debug_msg("APIC image's not included to Description!!!\n");
2734 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2735 imgstartOffset++; /* endofDesceriptionType(1byte) */
2737 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2741 #ifdef __MMFILE_TEST_MODE__
2742 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2745 if (realCpyFrameNum - imgstartOffset > 0) {
2746 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2747 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2749 if (pInfo->imageInfo.pImageBuf != NULL) {
2750 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2751 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2754 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2755 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2757 #ifdef __MMFILE_TEST_MODE__
2758 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2761 #ifdef __MMFILE_TEST_MODE__
2762 debug_msg("pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
2765 #ifdef __MMFILE_TEST_MODE__
2766 debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
2767 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2771 #ifdef __MMFILE_TEST_MODE__
2772 debug_msg("pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
2773 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
2777 checkImgMimeTypeMax = 0;
2780 pInfo->tagV2Info.bImageMarked = true;
2783 #ifdef __MMFILE_TEST_MODE__
2784 debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
2790 #ifdef __MMFILE_TEST_MODE__
2791 debug_msg("All of the pExtContent Values are NULL\n");
2795 curPos += purelyFramelen;
2796 if (purelyFramelen != 0)
2797 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2798 #ifdef __MMFILE_TEST_MODE__
2799 debug_msg("This Frame's size is Zero! purelyFramelen(%d)\n", purelyFramelen);
2803 if (pExtContent) _FREE_EX(pExtContent);
2804 memset(CompTmp, 0, 4);
2806 if (curPos < taglen) {
2807 needToloopv2taglen -= oneFrameLen;
2810 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
2813 realCpyFrameNum = 0;
2814 textEncodingType = 0;
2820 release_characterset_array(charset_array);
2830 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
2832 unsigned long taglen = 0;
2833 unsigned long needToloopv2taglen;
2834 unsigned long oneFrameLen = 0;
2835 unsigned long v2numOfFrames = 0;
2836 unsigned long curPos = 0;
2838 unsigned char *pExtContent = NULL;
2839 unsigned long purelyFramelen = 0;
2840 unsigned int encodingOffSet = 0;
2841 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2842 int textEncodingType = 0;
2843 char **charset_array = NULL;
2844 const char *MIME_PRFIX = "image/";
2846 make_characterset_array(&charset_array);
2848 init_content_info(pInfo);
2850 taglen = pInfo->tagV2Info.tagLen;
2851 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2852 curPos = MP3_TAGv2_HEADER_LEN;
2854 #ifdef __MMFILE_TEST_MODE__
2855 debug_msg("ID3tag v224--------------------------------------------------------------\n");
2858 /* check Extended Header */
2859 if (buffer[5] & 0x40) {
2860 /* if extended header exists, skip it*/
2861 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2863 #ifdef __MMFILE_TEST_MODE__
2864 debug_msg("--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2867 curPos += extendedHeaderLen;
2870 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2872 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2873 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2874 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2877 memcpy(CompTmp, &buffer[curPos], 4);
2880 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2881 oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
2882 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
2883 if (oneFrameLen > taglen - curPos)
2886 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2887 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2889 #ifdef __MMFILE_TEST_MODE__
2890 debug_msg("-----------------------------------------------------------------------------------\n");
2893 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2894 curPos += purelyFramelen;
2896 /*in case of UTF 16 encoding */
2897 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
2898 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2900 textEncodingType = AV_ID3V2_UTF16;
2901 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2903 textEncodingType = AV_ID3V2_UTF16_BE;
2904 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2906 textEncodingType = AV_ID3V2_UTF16;
2907 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2909 textEncodingType = AV_ID3V2_UTF16_BE;
2911 /*in case of UTF-16 BE encoding */
2912 if (buffer[curPos - purelyFramelen] == 0x02) {
2914 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2915 encodingOffSet++;/*null skip! */
2916 textEncodingType = AV_ID3V2_UTF16_BE;
2918 /*in case of UTF8 encoding */
2919 else if (buffer[curPos - purelyFramelen] == 0x03) {
2921 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
2922 encodingOffSet++;/*null skip! */
2923 textEncodingType = AV_ID3V2_UTF8;
2925 /*in case of ISO-8859-1 encoding */
2927 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
2929 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2930 encodingOffSet++;/*less than 0x20 value skip! */
2931 textEncodingType = AV_ID3V2_ISO_8859;
2935 if (encodingOffSet < purelyFramelen) {
2936 realCpyFrameNum = purelyFramelen - encodingOffSet;
2937 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2938 memset(pExtContent, '\0', realCpyFrameNum + 3);
2940 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2941 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2942 #ifdef __MMFILE_TEST_MODE__
2943 debug_msg("get the new text ecoding type\n");
2945 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2949 if (textEncodingType > AV_ID3V2_MAX) {
2950 debug_msg("WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2954 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2956 if (realCpyFrameNum > 0) {
2957 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2958 if (textEncodingType == AV_ID3V2_UTF8) {
2959 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2960 memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
2961 pInfo->pTitle[realCpyFrameNum] = '\0';
2962 /*string copy with '\0'*/
2963 pInfo->titleLen = realCpyFrameNum;
2964 _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
2966 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2969 #ifdef __MMFILE_TEST_MODE__
2970 debug_msg("pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2972 pInfo->tagV2Info.bTitleMarked = true;
2974 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2975 if (textEncodingType == AV_ID3V2_UTF8) {
2976 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2977 memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
2978 pInfo->pArtist[realCpyFrameNum] = '\0';
2979 /*string copy with '\0'*/
2980 pInfo->artistLen = realCpyFrameNum;
2981 _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
2983 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2986 #ifdef __MMFILE_TEST_MODE__
2987 debug_msg("pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2989 pInfo->tagV2Info.bArtistMarked = true;
2990 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2991 if (textEncodingType == AV_ID3V2_UTF8) {
2992 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
2993 memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
2994 pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
2995 /*string copy with '\0'*/
2996 pInfo->album_artistLen = realCpyFrameNum;
2997 _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
2999 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3002 #ifdef __MMFILE_TEST_MODE__
3003 debug_msg("pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3005 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3006 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3007 if (textEncodingType == AV_ID3V2_UTF8) {
3008 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3009 memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
3010 pInfo->pConductor[realCpyFrameNum] = '\0';
3011 /*string copy with '\0'*/
3012 pInfo->conductorLen = realCpyFrameNum;
3013 _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
3015 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3018 #ifdef __MMFILE_TEST_MODE__
3019 debug_msg("pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3021 pInfo->tagV2Info.bConductorMarked = true;
3022 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3023 if (textEncodingType == AV_ID3V2_UTF8) {
3024 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3025 memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
3026 pInfo->pAlbum[realCpyFrameNum] = '\0';
3027 /*string copy with '\0'*/
3028 pInfo->albumLen = realCpyFrameNum;
3029 _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
3031 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3034 #ifdef __MMFILE_TEST_MODE__
3035 debug_msg("pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3037 pInfo->tagV2Info.bAlbumMarked = true;
3038 } 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 */
3039 if (textEncodingType == AV_ID3V2_UTF8) {
3040 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3041 memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
3042 pInfo->pYear[realCpyFrameNum] = '\0';
3043 /*string copy with '\0'*/
3044 pInfo->yearLen = realCpyFrameNum;
3045 _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
3047 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3050 #ifdef __MMFILE_TEST_MODE__
3051 debug_msg("pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3053 pInfo->tagV2Info.bYearMarked = true;
3054 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3055 if (realCpyFrameNum > 3) {
3056 realCpyFrameNum -= 3;
3059 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3060 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3061 realCpyFrameNum -= 4;
3065 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3066 realCpyFrameNum -= 2;
3068 textEncodingType = AV_ID3V2_UTF16;
3070 #ifdef __MMFILE_TEST_MODE__
3071 debug_msg("pInfo->pComment Never Get Here!!\n");
3074 } else if (textEncodingType == AV_ID3V2_UTF8) {
3075 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3079 textEncodingType = AV_ID3V2_UTF8;
3081 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3085 textEncodingType = AV_ID3V2_ISO_8859;
3088 #ifdef __MMFILE_TEST_MODE__
3089 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3092 if (textEncodingType == AV_ID3V2_UTF8) {
3093 pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3094 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
3095 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
3096 pInfo->pComment[realCpyFrameNum] = '\0';
3097 /*string copy with '\0'*/
3098 pInfo->commentLen = realCpyFrameNum;
3099 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
3101 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3104 #ifdef __MMFILE_TEST_MODE__
3105 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3111 #ifdef __MMFILE_TEST_MODE__
3112 debug_msg("pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3114 pInfo->tagV2Info.bDescriptionMarked = true;
3115 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3118 int copy_start_pos = tmp;
3119 AvSynclyricsInfo *synclyrics_info = NULL;
3120 GList *synclyrics_info_list = NULL;
3122 if (realCpyFrameNum > 5) {
3123 realCpyFrameNum -= 5;
3126 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3127 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3128 realCpyFrameNum -= 4;
3132 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3133 realCpyFrameNum -= 2;
3135 textEncodingType = AV_ID3V2_UTF16;
3137 #ifdef __MMFILE_TEST_MODE__
3138 debug_msg("pInfo->pSyncLyrics Never Get Here!!\n");
3141 } else if (textEncodingType == AV_ID3V2_UTF8) {
3142 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3146 textEncodingType = AV_ID3V2_UTF8;
3148 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3152 textEncodingType = AV_ID3V2_ISO_8859;
3155 #ifdef __MMFILE_TEST_MODE__
3156 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3159 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3160 #ifdef __MMFILE_TEST_MODE__
3161 debug_msg("failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3163 pInfo->syncLyricsNum = 0;
3165 if (textEncodingType == AV_ID3V2_UTF16) {
3166 debug_warning("[AV_ID3V2_UTF16] not implemented\n");
3167 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3168 debug_warning("[AV_ID3V2_UTF16_BE] not implemented\n");
3170 for (idx = 0; idx < realCpyFrameNum; idx++) {
3171 if (pExtContent[tmp + idx] == 0x00) {
3172 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3174 if (textEncodingType == AV_ID3V2_UTF8) {
3175 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3176 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3177 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3178 synclyrics_info->lyric_info[copy_len + 1] = '\0';
3180 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3183 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];
3185 copy_start_pos = tmp + idx + 1;
3186 #ifdef __MMFILE_TEST_MODE__
3187 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);
3190 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3194 pInfo->pSyncLyrics = synclyrics_info_list;
3195 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3199 #ifdef __MMFILE_TEST_MODE__
3200 debug_msg("SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3205 pInfo->tagV2Info.bSyncLyricsMarked = true;
3206 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3207 if (realCpyFrameNum > 3) {
3208 realCpyFrameNum -= 3;
3211 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3212 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3213 realCpyFrameNum -= 4;
3217 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3218 realCpyFrameNum -= 2;
3220 textEncodingType = AV_ID3V2_UTF16;
3222 #ifdef __MMFILE_TEST_MODE__
3223 debug_msg("pInfo->pUnsyncLyrics Never Get Here!!\n");
3226 } else if (textEncodingType == AV_ID3V2_UTF8) {
3227 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3231 textEncodingType = AV_ID3V2_UTF8;
3233 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3237 textEncodingType = AV_ID3V2_ISO_8859;
3240 #ifdef __MMFILE_TEST_MODE__
3241 debug_msg("tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3244 if (textEncodingType == AV_ID3V2_UTF8) {
3245 pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3246 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3247 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3248 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3249 /*string copy with '\0'*/
3250 pInfo->unsynclyricsLen = realCpyFrameNum;
3251 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3253 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3256 #ifdef __MMFILE_TEST_MODE__
3257 debug_msg("Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3263 #ifdef __MMFILE_TEST_MODE__
3264 debug_msg("pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3266 pInfo->tagV2Info.bDescriptionMarked = true;
3267 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3268 if (textEncodingType == AV_ID3V2_UTF8) {
3269 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3270 memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3271 pInfo->pGenre[realCpyFrameNum] = '\0';
3272 /*string copy with '\0'*/
3273 pInfo->genreLen = realCpyFrameNum;
3274 _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3276 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3279 #ifdef __MMFILE_TEST_MODE__
3280 debug_msg("pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3283 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3287 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3290 sscanf(pInfo->pGenre, "%d", &int_genre);
3291 #ifdef __MMFILE_TEST_MODE__
3292 debug_msg("genre information is inteager [%d]\n", int_genre);
3295 /*Change int to string */
3296 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3297 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3298 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3299 int tmp_genre_len = 0;
3301 memset(tmp_genre, 0, 6);
3302 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3304 tmp_genre_len = strlen(tmp_genre);
3305 if (tmp_genre_len > 0) {
3306 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3307 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3308 if (pInfo->pGenre) {
3309 strncpy(pInfo->pGenre, tmp_genre, tmp_genre_len);
3310 pInfo->pGenre[tmp_genre_len] = 0;
3317 pInfo->tagV2Info.bGenreMarked = true;
3318 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3319 if (textEncodingType == AV_ID3V2_UTF8) {
3320 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3321 memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3322 pInfo->pTrackNum[realCpyFrameNum] = '\0';
3323 /*string copy with '\0'*/
3324 pInfo->tracknumLen = realCpyFrameNum;
3325 _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3327 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3331 #ifdef __MMFILE_TEST_MODE__
3332 debug_msg("pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3334 pInfo->tagV2Info.bTrackNumMarked = true;
3335 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3336 if (textEncodingType == AV_ID3V2_UTF8) {
3337 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3338 memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3339 pInfo->pEncBy[realCpyFrameNum] = '\0';
3340 /*string copy with '\0'*/
3341 pInfo->encbyLen = realCpyFrameNum;
3342 _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3344 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3347 #ifdef __MMFILE_TEST_MODE__
3348 debug_msg("pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3350 pInfo->tagV2Info.bEncByMarked = true;
3351 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3352 if (textEncodingType == AV_ID3V2_UTF8) {
3353 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3354 memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3355 pInfo->pURL[realCpyFrameNum] = '\0';
3356 /*string copy with '\0'*/
3357 pInfo->urlLen = realCpyFrameNum;
3358 _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3360 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3363 #ifdef __MMFILE_TEST_MODE__
3364 debug_msg("pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3366 pInfo->tagV2Info.bURLMarked = true;
3367 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3368 if (textEncodingType == AV_ID3V2_UTF8) {
3369 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3370 memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3371 pInfo->pCopyright[realCpyFrameNum] = '\0';
3372 /*string copy with '\0'*/
3373 pInfo->copyrightLen = realCpyFrameNum;
3374 _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3376 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3379 #ifdef __MMFILE_TEST_MODE__
3380 debug_msg("pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3382 pInfo->tagV2Info.bCopyRightMarked = true;
3383 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3384 if (textEncodingType == AV_ID3V2_UTF8) {
3385 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3386 memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3387 pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3388 /*string copy with '\0'*/
3389 pInfo->originartistLen = realCpyFrameNum;
3390 _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3392 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3395 #ifdef __MMFILE_TEST_MODE__
3396 debug_msg("pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3398 pInfo->tagV2Info.bOriginArtistMarked = true;
3399 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3400 if (textEncodingType == AV_ID3V2_UTF8) {
3401 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3402 memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3403 pInfo->pComposer[realCpyFrameNum] = '\0';
3404 /*string copy with '\0'*/
3405 pInfo->composerLen = realCpyFrameNum;
3406 _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3408 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3411 #ifdef __MMFILE_TEST_MODE__
3412 debug_msg("pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3414 pInfo->tagV2Info.bComposerMarked = true;
3415 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) { /*TYER(year) and TRDA are replaced by the TDRC */
3416 if (textEncodingType == AV_ID3V2_UTF8) {
3417 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3418 memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3419 pInfo->pRecDate[realCpyFrameNum] = '\0';
3420 /*string copy with '\0'*/
3421 pInfo->recdateLen = realCpyFrameNum;
3422 _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3424 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3427 #ifdef __MMFILE_TEST_MODE__
3428 debug_msg("pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3430 pInfo->tagV2Info.bRecDateMarked = true;
3431 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3432 if (textEncodingType == AV_ID3V2_UTF8) {
3433 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3434 memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3435 pInfo->pContentGroup[realCpyFrameNum] = '\0';
3436 /*string copy with '\0'*/
3437 pInfo->contentGroupLen = realCpyFrameNum;
3438 _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3440 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3442 #ifdef __MMFILE_TEST_MODE__
3443 debug_msg("pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3445 pInfo->tagV2Info.bContentGroupMarked = true;
3446 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3447 if (pExtContent[0] != '\0') {
3448 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3449 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3451 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3452 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3453 checkImgMimeTypeMax++;
3455 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3457 pInfo->imageInfo.imgMimetypeLen = 0;
3460 imgstartOffset += checkImgMimeTypeMax;
3462 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3463 pInfo->imageInfo.imgMimetypeLen = 0;
3464 debug_error("APIC NOT VALID");
3468 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3469 imgstartOffset++;/*endofMIME(1byte) */
3471 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3472 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3474 imgstartOffset++;/*PictureType(1byte) */
3476 if (pExtContent[imgstartOffset] != 0x0) {
3479 int new_dis_len = 0;
3480 char jpg_sign[3] = {0xff, 0xd8, 0xff};
3481 char png_sign[8] = {0x80, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
3482 char *tmp_desc = NULL;
3485 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3486 if (realCpyFrameNum < imgstartOffset + cur_pos) {
3487 debug_error("End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3490 /*check end of image description*/
3491 if ((pExtContent[imgstartOffset + cur_pos + 1] == jpg_sign[0]) ||
3492 (pExtContent[imgstartOffset + cur_pos + 1] == png_sign[0])) {
3493 #ifdef __MMFILE_TEST_MODE__
3494 debug_msg("length of description (%d)", cur_pos);
3503 dis_len = cur_pos + 1;
3505 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3507 if(tmp_desc != NULL) {
3508 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3509 debug_msg("tmp_desc %s\n", tmp_desc);
3511 /*convert description*/
3512 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3513 debug_msg("new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3514 mmfile_free(tmp_desc);
3516 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3519 imgstartOffset += cur_pos;
3521 pInfo->imageInfo.imgDesLen = 0;
3524 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3525 imgstartOffset++; /* endofDesceriptionType(1byte) */
3527 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
3531 #ifdef __MMFILE_TEST_MODE__
3532 debug_msg("after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3535 if (realCpyFrameNum - imgstartOffset > 0) {
3536 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3537 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3539 if (pInfo->imageInfo.pImageBuf != NULL) {
3540 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3541 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3544 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3545 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3547 #ifdef __MMFILE_TEST_MODE__
3548 debug_msg("No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3554 checkImgMimeTypeMax = 0;
3557 pInfo->tagV2Info.bImageMarked = true;
3559 #ifdef __MMFILE_TEST_MODE__
3560 debug_msg("CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3566 #ifdef __MMFILE_TEST_MODE__
3567 debug_msg("mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
3572 curPos += purelyFramelen;
3573 if (purelyFramelen != 0)
3574 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3577 if (pExtContent) _FREE_EX(pExtContent);
3578 memset(CompTmp, 0, 4);
3579 if (curPos < taglen) {
3580 needToloopv2taglen -= oneFrameLen;
3583 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3587 realCpyFrameNum = 0;
3588 textEncodingType = 0;
3594 release_characterset_array(charset_array);
3604 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
3606 char *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
3607 bool bAdditionGenre = false /*, bMpegAudioFrame = false*/;
3608 int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
3610 char *pGenreForUTF16;
3612 unsigned char genre = pInfo->genre;
3614 /* for Genre Info */
3615 if (pInfo->tagV2Info.bGenreMarked == false) {
3616 if (pInfo->bV1tagFound == true) {
3617 #ifdef __MMFILE_TEST_MODE__
3618 debug_msg("Genre: %d\n", genre);
3623 if (MpegAudio_Genre[genre] != NULL) {
3624 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
3625 if (pInfo->genreLen > 0) {
3626 /* Give space for NULL character. Hence added "+1" */
3627 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3628 if (pInfo->pGenre) {
3629 strncpy(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen);
3630 pInfo->pGenre[pInfo->genreLen] = '\0';
3635 #ifdef __MMFILE_TEST_MODE__
3636 debug_msg("Genre was not Found.\n");
3639 } else if (pInfo->tagV2Info.bGenreMarked == true) {
3640 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
3641 pInfo->pGenre[pInfo->genreLen + 1] = '\0';
3642 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
3644 pGenreForUTF16 = (char *)pInfo->pGenre;
3646 if (WmConvert2LCode(mpegAudioGenre, sizeof(char) * AV_WM_LOCALCODE_SIZE_MAX * (pInfo->genreLen + 1), pGenreForUTF16)) {
3647 pInfo->genreLen = strlen(mpegAudioGenre);
3648 mpegAudioGenre[pInfo->genreLen] = '\0';
3652 #ifdef __MMFILE_TEST_MODE__
3653 debug_msg("pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
3655 if (pInfo->pGenre) {
3656 pInfo->genreLen = strlen(pInfo->pGenre);
3657 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3658 if (mpegAudioGenre != NULL) {
3659 mpegAudioGenre[pInfo->genreLen] = '\0';
3660 strncpy(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen);
3663 pInfo->genreLen = 0;
3667 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3670 if (mpegAudioGenre != NULL) {
3673 * (XXX) XXX is 0 - 148
3675 pInfo->genreLen = strlen(mpegAudioGenre);
3676 if (pInfo->genreLen >= 3 &&
3677 mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
3678 bAdditionGenre = true;
3679 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
3680 if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
3681 bAdditionGenre = false;
3687 if (bAdditionGenre == true) {
3688 idv2IntGenre = atoi(mpegAudioGenre + 1);
3690 if (idv2IntGenre > 147 || idv2IntGenre < 0)
3693 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
3694 pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
3695 if (pInfo->genreLen > 0) {
3696 /* Give space for NULL character. Hence added "+1" */
3697 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3698 if (pInfo->pGenre) {
3699 strncpy(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen);
3700 pInfo->pGenre[pInfo->genreLen] = 0;
3704 #ifdef __MMFILE_TEST_MODE__
3705 debug_msg("pInfo->pGenre = %s\n", pInfo->pGenre);
3707 } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
3712 /* Give space for NULL character. Hence added "+1" */
3713 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
3714 if (pInfo->pGenre) {
3715 strncpy(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen);
3716 pInfo->pGenre[pInfo->genreLen] = '\0';
3718 #ifdef __MMFILE_TEST_MODE__
3719 debug_msg("pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
3722 #ifdef __MMFILE_TEST_MODE__
3723 debug_msg("Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
3727 #ifdef __MMFILE_TEST_MODE__
3728 debug_msg("mpegAudioGenre = %x\n", mpegAudioGenre);
3732 _FREE_EX(mpegAudioGenre);
3735 #ifdef __MMFILE_TEST_MODE__
3736 debug_msg("Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
3742 void mm_file_free_synclyrics_list(GList *synclyrics_list)
3746 AvSynclyricsInfo *synclyrics_info = NULL;
3748 if (synclyrics_list == NULL) {
3752 list_len = g_list_length(synclyrics_list);
3753 for (idx = 0; idx < list_len; idx++) {
3754 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
3756 free(synclyrics_info->lyric_info);
3757 synclyrics_info->lyric_info = NULL;
3759 free(synclyrics_info);
3760 synclyrics_info = NULL;
3763 if (synclyrics_list != NULL) {
3764 g_list_free(synclyrics_list);
3765 synclyrics_list = NULL;