4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Haejeong Kim <backto.kim@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
28 #include <iniparser.h>
32 #include "mm_file_debug.h"
33 #include "mm_file_utils.h"
35 #define ENABLE_ITUNES_META /*All itunes metadata extracted by ffmpeg. see mov_read_udta_string() but Some cover art not support. */
36 #define INVALID_UINT_VALUE 0xFFFFFFFF
37 #define INVALID_UINT8_VALUE 0xFF
39 typedef struct _mmfilemp4basicboxheader {
42 long long start_offset; /*huge file*/
43 } MMFILE_MP4_BASIC_BOX_HEADER;
45 typedef struct _mmfilemp4ftpybox {
46 unsigned int major_brand;
47 unsigned short major_version;
48 unsigned short minor_version;
49 unsigned int *compatiable_brands;
53 eMMFILE_3GP_TAG_TITLE = 0x01,
54 eMMFILE_3GP_TAG_CAPTION = 0x02,
55 eMMFILE_3GP_TAG_COPYRIGHT = 0x03,
56 eMMFILE_3GP_TAG_PERFORMER = 0x04,
57 eMMFILE_3GP_TAG_AUTHOR = 0x05,
58 eMMFILE_3GP_TAG_GENRE = 0x06,
59 } eMMFILE_3GP_TEXT_TAG;
61 typedef struct _mmfile3gptagtextbox {
62 unsigned char version;
63 unsigned char flag[3];
64 unsigned char language[2];
66 } MMFILE_3GP_TEXT_TAGBOX;
68 typedef struct _mmfile3gptagyearbox {
69 unsigned char version;
70 unsigned char flag[3];
72 } MMFILE_3GP_YEAR_TAGBOX;
74 typedef struct _mmfile3gptagalbumbox {
75 unsigned char version;
76 unsigned char flag[3];
77 unsigned char language[2];
78 unsigned char *albumtile;
79 unsigned char trackNumber;
80 } MMFILE_3GP_ALBUM_TAGBOX;
82 typedef struct _mmfile3gpratingbox {
83 unsigned char version;
84 unsigned char flag[3];
85 unsigned int ratingEntity;
86 unsigned int ratingCriteria;
87 unsigned char language[2];
88 unsigned char *ratingInfo;
89 } MMFILE_3GP_RATING_TAGBOX;
91 typedef struct _mmfile3gpclsfbox {
92 unsigned char version;
93 unsigned char flag[3];
94 unsigned int classificationEntity;
95 unsigned int classificationTable;
96 unsigned char language[2];
97 unsigned char *classificationInfo;
98 } MMFILE_3GP_CLASSIFICATION_TAGBOX;
100 typedef struct _mmfile3gphdlrbox {
101 unsigned int version;
102 unsigned int pre_defined;
103 unsigned int handler_type;
104 unsigned int reserved[3];
105 unsigned char *boxname;
106 } MMFILE_3GP_HANDLER_BOX;
108 typedef struct _mmfileidv2box {
109 unsigned char version;
110 unsigned char flag[3];
111 unsigned char language[2];
112 unsigned char *id3v2Data;
113 } MMFILE_3GP_ID3V2_BOX;
115 typedef struct _mmfilelocibox {
116 unsigned char version;
117 unsigned char flag[3];
118 unsigned char language[2];
124 unsigned char *astronomical_body;
125 unsigned char *additional_notes;
126 } MMFILE_3GP_LOCATION_TAGBOX;
128 typedef struct _mmfilesmtabox {
131 unsigned char saut[4];
133 } MMFILE_M4A_SMTA_TAGBOX;
135 typedef struct _mmfilesa3dbox {
137 uint8_t ambisonic_type;
138 uint32_t ambisonic_order;
139 uint8_t ambisonic_channel_ordering;
140 uint8_t ambisonic_normalization;
141 uint32_t num_channels;
142 uint32_t channel_map[49]; /* Up to 6th order */
143 } __attribute__((aligned(1), packed)) MMFILE_MP4A_SA3D_TAGBOX;
146 PROJECTION_TYPE_RECT = 0, /* Rectangular, Google's RFC value */
147 PROJECTION_TYPE_EQUI = 1, /* Equirectangular, Google's RFC value */
148 PROJECTION_TYPE_CBMP = 2, /* Cubemap, Google's RFC value */
149 PROJECTION_TYPE_MESH = 3, /* Mesh, Google's RFC value, unsupported */
150 PROJECTION_TYPE_UNKNOWN = INVALID_UINT_VALUE,
151 } SPHERICAL_VIDEO2_PROJECTION_TYPE;
153 #define MMFILE_MP4_BASIC_BOX_HEADER_LEN 8
154 #define MMFILE_MP4_MOVIE_HEADER_BOX_LEN 96
155 #define MMFILE_MP4_HDLR_BOX_LEN 24
156 #define MMFILE_MP4_STSZ_BOX_LEN 20
157 #define MMFILE_MP4_MP4VBOX_LEN 80
158 #define MMFILE_MP4_MP4ABOX_LEN 28
159 #define MMFILE_3GP_TEXT_TAGBOX_LEN 6
160 #define MMFILE_3GP_YEAR_TAGBOX_LEN 6
161 #define MMFILE_3GP_ALBUM_TAGBOX_LEN 6
162 #define MMFILE_3GP_RATING_TAGBOX_LEN 14
163 #define MMFILE_3GP_CLASS_TAGBOX_LEN 14
164 #define MMFILE_3GP_HANDLER_BOX_LEN 24
165 #define MMFILE_3GP_ID3V2_BOX_LEN 6
166 #define MMFILE_SYNC_LYRIC_INFO_MIN_LEN 5
169 #define FOURCC(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
171 /*#define MIN(a, b) (((a) < (b)) ? (a):(b))*/
173 #define GENRE_COUNT 149
175 static const char *MpegAudio_Genre[GENRE_COUNT] = {"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal",
176 "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial",
177 "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
178 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
179 "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
180 "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
181 "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
182 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
183 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
184 "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic",
185 "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove",
186 "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
187 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore",
188 "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian", "Heavy Metal", "Black Metal", "Crossover",
189 "Contemporary", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "Synthpop", "Unknown"
192 static unsigned char gTagJPEGHeader[] = {0xff, 0xd8, 0xff };
193 static unsigned char gTagPNGHeader[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
195 static int GetJunkCounterLimit(void);
197 static int GetStringFromTextTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header, eMMFILE_3GP_TEXT_TAG eTag)
199 int ret = MMFILE_UTIL_FAIL; /*fail*/
200 MMFILE_3GP_TEXT_TAGBOX texttag = {0, };
203 char *temp_text = NULL;
205 if (!formatContext || !fp || !basic_header) {
206 debug_error(DEBUG, "invalid param\n");
207 return MMFILE_UTIL_FAIL;
210 textBytes = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_TEXT_TAGBOX_LEN;
212 readed = mmfile_read(fp, (unsigned char *)&texttag, MMFILE_3GP_TEXT_TAGBOX_LEN);
213 if (readed != MMFILE_3GP_TEXT_TAGBOX_LEN) {
214 debug_error(DEBUG, "read text tag header fail\n");
215 ret = MMFILE_UTIL_FAIL;
219 if (textBytes <= 1) { /* there exist only 00(null) */
220 debug_error(DEBUG, "Text is NULL\n");
224 texttag.text = mmfile_malloc(textBytes);
226 debug_error(DEBUG, "malloc fail for text box\n");
227 ret = MMFILE_UTIL_FAIL;
231 readed = mmfile_read(fp, (unsigned char *)texttag.text, textBytes);
232 if (readed != textBytes) {
233 debug_error(DEBUG, "read text fail\n");
234 ret = MMFILE_UTIL_FAIL;
239 if ((texttag.text[0] == 0xFE) && (texttag.text[1] == 0xFF)) {
240 /* this char is UTF-16 */
241 unsigned int bytes_written = 0;
242 temp_text = mmfile_string_convert((const char *)&texttag.text[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
244 temp_text = mmfile_strdup((const char *)texttag.text);
248 case eMMFILE_3GP_TAG_TITLE: {
249 if (!formatContext->title) {
250 formatContext->title = g_strdup(temp_text);
254 case eMMFILE_3GP_TAG_CAPTION: {
255 if (!formatContext->description) {
256 formatContext->description = g_strdup(temp_text);
260 case eMMFILE_3GP_TAG_COPYRIGHT: {
261 if (!formatContext->copyright) {
262 formatContext->copyright = g_strdup(temp_text);
266 case eMMFILE_3GP_TAG_PERFORMER: {
267 if (!formatContext->artist) {
268 formatContext->artist = g_strdup(temp_text);
272 case eMMFILE_3GP_TAG_AUTHOR: {
273 if (!formatContext->author) {
274 formatContext->author = g_strdup(temp_text);
278 case eMMFILE_3GP_TAG_GENRE: {
279 if (!formatContext->genre) {
280 formatContext->genre = g_strdup(temp_text);
285 debug_warning(DEBUG, "Not supported Text Tag type[%d]\n", eTag);
290 mmfile_free(texttag.text);
292 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
296 return MMFILE_UTIL_SUCCESS;
299 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
301 mmfile_free(texttag.text);
306 static int GetYearFromYearTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
308 #define MAX_YEAR_BUFFER 10
310 MMFILE_3GP_YEAR_TAGBOX yearbox = {0, };
311 char temp_year[MAX_YEAR_BUFFER] = {0, };
313 if (!formatContext || !fp || !basic_header) {
314 debug_error(DEBUG, "invalid param\n");
315 return MMFILE_UTIL_FAIL;
318 readed = mmfile_read(fp, (unsigned char *)&yearbox, MMFILE_3GP_YEAR_TAGBOX_LEN);
319 if (readed != MMFILE_3GP_YEAR_TAGBOX_LEN) {
320 debug_error(DEBUG, "read yeartag header fail\n");
324 if (!formatContext->year) {
325 yearbox.year = mmfile_io_be_int16(yearbox.year);
326 snprintf(temp_year, MAX_YEAR_BUFFER, "%d", yearbox.year);
327 temp_year[MAX_YEAR_BUFFER - 1] = '\0';
328 formatContext->year = mmfile_strdup((const char *)temp_year);
331 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
332 return MMFILE_UTIL_SUCCESS;
335 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
337 return MMFILE_UTIL_FAIL;
340 static int GetAlbumFromAlbumTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
342 int albumTitleLen = 0;
343 char *temp_text = NULL;
346 MMFILE_3GP_ALBUM_TAGBOX albumbox = {0, };
348 if (!formatContext || !fp || !basic_header) {
349 debug_error(DEBUG, "invalid param\n");
350 return MMFILE_UTIL_FAIL;
353 readed = mmfile_read(fp, (unsigned char *)&albumbox, MMFILE_3GP_ALBUM_TAGBOX_LEN);
354 if (readed != MMFILE_3GP_ALBUM_TAGBOX_LEN) {
355 debug_error(DEBUG, "read albumtag header fail\n");
359 albumTitleLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ALBUM_TAGBOX_LEN - 1; /* 1: track number */
360 if (albumTitleLen > 1) { /* there exist only 00(null) */
361 debug_msg(RELEASE, "albumTitleLen=%d\n", albumTitleLen);
363 albumbox.albumtile = mmfile_malloc(albumTitleLen + 1); /* 1: for null char */
364 if (!albumbox.albumtile) {
365 debug_error(DEBUG, "malloc fail for album title text\n");
369 readed = mmfile_read(fp, (unsigned char *)albumbox.albumtile, albumTitleLen);
370 if (readed != albumTitleLen) {
371 debug_error(DEBUG, "read album title fail\n");
375 if (albumbox.albumtile[albumTitleLen - 1] == '\0') { /* there exist track number */
379 readed = mmfile_read(fp, (unsigned char *)&(albumbox.albumtile[albumTitleLen]), 1);
381 debug_error(DEBUG, "read album title fail\n");
384 albumbox.albumtile[albumTitleLen] = '\0';
388 if ((albumbox.albumtile[0] == 0xFE) && (albumbox.albumtile[1] == 0xFF)) {
389 /* this char is UTF-16 */
390 unsigned int bytes_written = 0;
391 temp_text = mmfile_string_convert((const char *)&albumbox.albumtile[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
393 temp_text = mmfile_strdup((const char *)albumbox.albumtile);
396 if (!formatContext->album)
397 formatContext->album = temp_text;
401 debug_msg(RELEASE, "formatContext->album=%s, strlen=%d\n", formatContext->album, strlen(formatContext->album));
405 readed = mmfile_read(fp, (unsigned char *)&albumbox.trackNumber, 1);
407 debug_error(DEBUG, "read track number fail\n");
411 if (formatContext->tagTrackNum == 0) {
412 char tracknum[10] = {0, };
413 snprintf(tracknum, 10, "%d", albumbox.trackNumber);
415 formatContext->tagTrackNum = mmfile_strdup((const char *)tracknum);
419 mmfile_free(albumbox.albumtile);
420 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
422 return MMFILE_UTIL_SUCCESS;
425 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
426 mmfile_free(albumbox.albumtile);
428 return MMFILE_UTIL_FAIL;
431 static int GetRatingFromRatingTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
434 int ratinginfoLen = 0;
435 char *temp_text = NULL;
437 MMFILE_3GP_RATING_TAGBOX ratingTag = {0, };
439 if (!formatContext || !fp || !basic_header) {
440 debug_error(DEBUG, "invalid param\n");
441 return MMFILE_UTIL_FAIL;
444 readed = mmfile_read(fp, (unsigned char *)&ratingTag, MMFILE_3GP_RATING_TAGBOX_LEN);
445 if (readed != MMFILE_3GP_RATING_TAGBOX_LEN) {
446 debug_error(DEBUG, "read rating tag header fail\n");
450 ratinginfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_RATING_TAGBOX_LEN;
452 if (ratinginfoLen == 1) {
453 debug_error(DEBUG, "Rating Text is NULL\n");
457 ratingTag.ratingInfo = mmfile_malloc(ratinginfoLen);
458 if (!ratingTag.ratingInfo) {
459 debug_error(DEBUG, "rating info error\n");
463 readed = mmfile_read(fp, (unsigned char *)ratingTag.ratingInfo, ratinginfoLen);
464 if (readed != ratinginfoLen) {
465 debug_error(DEBUG, "read rating info string fail\n");
470 if ((ratingTag.ratingInfo[0] == 0xFE) && (ratingTag.ratingInfo[1] == 0xFF)) {
471 /* this char is UTF-16 */
472 unsigned int bytes_written = 0;
473 temp_text = mmfile_string_convert((const char *)&ratingTag.ratingInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
475 temp_text = mmfile_strdup((const char *)ratingTag.ratingInfo);
478 if (!formatContext->rating) {
479 formatContext->rating = temp_text;
481 mmfile_free(temp_text);
484 mmfile_free(ratingTag.ratingInfo);
485 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
487 return MMFILE_UTIL_SUCCESS;
490 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
491 mmfile_free(ratingTag.ratingInfo);
493 return MMFILE_UTIL_FAIL;
497 static int GetClassficationFromClsfTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
499 int classinfoLen = 0;
501 char *temp_text = NULL;
502 MMFILE_3GP_CLASSIFICATION_TAGBOX classTag = {0, };
504 if (!formatContext || !fp || !basic_header) {
505 debug_error(DEBUG, "invalid param\n");
506 return MMFILE_UTIL_FAIL;
509 readed = mmfile_read(fp, (unsigned char *)&classTag, MMFILE_3GP_CLASS_TAGBOX_LEN);
510 if (readed != MMFILE_3GP_CLASS_TAGBOX_LEN) {
511 debug_error(DEBUG, "read classification tag header fail\n");
516 classinfoLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_CLASS_TAGBOX_LEN;
517 if (classinfoLen == 1) {
518 debug_error(DEBUG, "Classification Text is NULL\n");
522 classTag.classificationInfo = mmfile_malloc(classinfoLen);
523 if (!classTag.classificationInfo) {
524 debug_error(DEBUG, "class info error\n");
528 readed = mmfile_read(fp, (unsigned char *)classTag.classificationInfo, classinfoLen);
529 if (readed != classinfoLen) {
530 debug_error(DEBUG, "read class info string fail\n");
535 if ((classTag.classificationInfo[0] == 0xFE) && (classTag.classificationInfo[1] == 0xFF)) {
536 /* this char is UTF-16 */
537 unsigned int bytes_written = 0;
538 temp_text = mmfile_string_convert((const char *)&classTag.classificationInfo[2], readed - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
540 temp_text = mmfile_strdup((const char *)classTag.classificationInfo);
543 if (!formatContext->classification) {
544 formatContext->classification = temp_text;
546 mmfile_free(temp_text);
549 mmfile_free(classTag.classificationInfo);
550 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
552 return MMFILE_UTIL_SUCCESS;
555 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
556 mmfile_free(classTag.classificationInfo);
558 return MMFILE_UTIL_FAIL;
562 * The Location Information box
563 * --------------------+-------------------+-----------------------------------+------
564 * Field Type Details Value
565 * --------------------+-------------------+-----------------------------------+------
566 * BoxHeader.Size Unsigned int(32)
567 * BoxHeader.Type Unsigned int(32) 'loci'
568 * BoxHeader.Version Unsigned int(8) 0
569 * BoxHeader.Flags Bit(24) 0
571 * Language Unsigned int(5)[3] Packed ISO-639-2/T language code
572 * Name String Text of place name
573 * Role Unsigned int(8) Non-negative value indicating role
575 * Longitude Unsigned int(32) Fixed-point value of the longitude
576 * Latitude Unsigned int(32) Fixed-point value of the latitude
577 * Altitude Unsigned int(32) Fixed-point value of the Altitude
578 * Astronomical_body String Text of astronomical body
579 * Additional_notes String Text of additional location-related
581 * --------------------+-------------------+-----------------------------------+------
583 static int _get_char_position(unsigned char *src, char ch, int max)
586 for (i = 0; i < max; i++) {
587 if (*(src + i) == ch)
594 static int GetLocationFromLociTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
597 MMFILE_3GP_LOCATION_TAGBOX lociTag = {0, };
600 unsigned char *buffer = NULL;
601 unsigned char *p = NULL;
603 unsigned int bytes_written = 0;
604 unsigned int name_sz = 0;
605 unsigned int astro_sz = 0;
607 int ilong, ilati, ialti;
608 float flong, flati, falti;
611 if (!formatContext || !fp || !basic_header) {
612 debug_error(DEBUG, "invalid param\n");
613 return MMFILE_UTIL_FAIL;
616 readed = mmfile_read(fp, (unsigned char *)&lociTag, 6); /*6 = version + flag + pad + language */
618 debug_error(DEBUG, "read location tag header fail\n");
622 /*buffer len = name + role + ... + additional notes length */
623 bufferLen = basic_header->size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - 6;
625 debug_error(DEBUG, "too small buffer\n");
629 buffer = mmfile_malloc(bufferLen);
631 debug_error(DEBUG, "buffer malloc error\n");
635 readed = mmfile_read(fp, (unsigned char *)buffer, bufferLen);
636 if (readed != bufferLen) {
637 debug_error(DEBUG, "read location tag fail\n");
643 pos = _get_char_position(p, '\0', readed - (1 + 4 + 4 + 4 + 2));
645 if (p[0] == 0xFE && p[1] == 0xFF) {
646 lociTag.name = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
648 lociTag.name = (unsigned char *)mmfile_strdup((const char *)p);
660 debug_msg(RELEASE, "long: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 0), *(p + 1), *(p + 2), *(p + 3));
661 debug_msg(RELEASE, "lati: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 4), *(p + 5), *(p + 6), *(p + 7));
662 debug_msg(RELEASE, "alti: 0x%02X 0x%02X 0x%02X 0x%02X \n", *(p + 8), *(p + 9), *(p + 10), *(p + 11));
664 ilong = mmfile_io_be_uint32(*(unsigned int *)p);
665 ilati = mmfile_io_be_uint32(*(unsigned int *)(p + 4));
666 ialti = mmfile_io_be_uint32(*(unsigned int *)(p + 8));
668 flong = (float)ilong / (1 << 16);
669 flati = (float)ilati / (1 << 16);
670 falti = (float)ialti / (1 << 16);
673 lociTag.longitude = flong;
675 lociTag.latitude = flati;
677 lociTag.altitude = falti;
681 /*astronomical body*/
682 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + 1));
684 if (p[0] == 0xFE && p[1] == 0xFF) {
685 lociTag.astronomical_body = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
687 lociTag.astronomical_body = (unsigned char *)mmfile_strdup((const char *)p);
696 pos = _get_char_position(p, '\0', readed - (name_sz + 1 + 4 + 4 + 4 + astro_sz));
698 if (p[0] == 0xFE && p[1] == 0xFF) {
699 lociTag.additional_notes = (unsigned char *)mmfile_string_convert((const char *)(p + 2), pos - 2, "UTF-8", "UTF-16", NULL, (unsigned int *)&bytes_written);
701 lociTag.additional_notes = (unsigned char *)mmfile_strdup((const char *)p);
707 debug_msg(RELEASE, "** Location Information **\n");
708 debug_msg(RELEASE, "Name : %s\n", lociTag.name);
709 debug_msg(RELEASE, "Role : %d (0: shooting, 1: real, 2: fictional, other: reserved)\n", lociTag.role);
710 debug_msg(RELEASE, "Longitude : %16.16f\n", lociTag.longitude);
711 debug_msg(RELEASE, "Latitude : %16.16f\n", lociTag.latitude);
712 debug_msg(RELEASE, "Altitude : %16.16f\n", lociTag.altitude);
713 debug_msg(RELEASE, "Astronomical body: %s\n", lociTag.astronomical_body);
714 debug_msg(RELEASE, "Additional notes : %s\n", lociTag.additional_notes);
716 formatContext->longitude = lociTag.longitude;
717 formatContext->latitude = lociTag.latitude;
718 formatContext->altitude = lociTag.altitude;
721 mmfile_free(lociTag.name);
722 mmfile_free(lociTag.astronomical_body);
723 mmfile_free(lociTag.additional_notes);
725 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
726 return MMFILE_UTIL_SUCCESS;
729 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
731 mmfile_free(lociTag.name);
732 mmfile_free(lociTag.astronomical_body);
733 mmfile_free(lociTag.additional_notes);
735 return MMFILE_UTIL_FAIL;
738 static int GetSAUTInfoFromSMTATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
740 MMFILE_M4A_SMTA_TAGBOX smtaTag = {0, };
743 if (!formatContext || !fp || !basic_header) {
744 debug_error(DEBUG, "invalid param\n");
745 return MMFILE_UTIL_FAIL;
748 readed = mmfile_read(fp, (unsigned char *)&smtaTag, sizeof(MMFILE_M4A_SMTA_TAGBOX));
749 if (readed != sizeof(MMFILE_M4A_SMTA_TAGBOX)) {
750 debug_error(DEBUG, "read smta tag header fail\n");
754 smtaTag.length = mmfile_io_be_uint32(smtaTag.length);
755 smtaTag.value = mmfile_io_be_uint32(smtaTag.value);
757 debug_msg(RELEASE, "Len : 0x%x", smtaTag.length);
758 debug_msg(RELEASE, "Saut : 0x%x 0x%x 0x%x 0x%x", smtaTag.saut[0], smtaTag.saut[1], smtaTag.saut[2], smtaTag.saut[3]);
759 debug_msg(RELEASE, "Value : 0x%x", smtaTag.value);
761 if (smtaTag.saut[0] == 's'
762 && smtaTag.saut[1] == 'a'
763 && smtaTag.saut[2] == 'u'
764 && smtaTag.saut[3] == 't') {
765 if (smtaTag.value == 0x01) {
766 debug_msg(RELEASE, "This has saut tag and valid value");
767 formatContext->smta = 1;
769 debug_error(DEBUG, "This has saut tag and but invalid value");
773 debug_error(DEBUG, "This hasn't saut tag and valid value");
777 return MMFILE_UTIL_SUCCESS;
780 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
782 return MMFILE_UTIL_FAIL;
785 static int GetSA3DInfoFromMP4ATagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
787 if (!formatContext || !fp || !basic_header) {
788 debug_error(DEBUG, "invalid param\n");
789 return MMFILE_UTIL_FAIL;
792 unsigned char *buffer;
794 bool is_SA3D_present = false;
796 MMFILE_MP4A_SA3D_TAGBOX sa3dTag = {0, };
798 formatContext->ambisonicType = MMFILE_AMBISONIC_TYPE_UNKNOWN;
799 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_UNKNOWN;
800 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_UNKNOWN;
802 mmfile_seek(fp, basic_header->start_offset, SEEK_SET);
804 buffer = calloc(basic_header->size + 1, sizeof(unsigned char));
806 debug_error(DEBUG, "calloc failed ");
810 readed = mmfile_read(fp, buffer, basic_header->size);
811 if (readed != (int)basic_header->size) {
812 debug_error(DEBUG, "read mp4a box failed\n");
816 for (i = 0; i + 3 < basic_header->size; ++i)
817 if (buffer[i] == 'S' && buffer[i + 1] == 'A' && buffer[i + 2] == '3' && buffer[i + 3] == 'D') {
818 debug_warning(DEBUG, "SA3D data found at offset %d bytes\n", i);
819 is_SA3D_present = true;
823 if (!is_SA3D_present) {
824 debug_warning(DEBUG, "No SA3D box found");
828 mmfile_seek(fp, basic_header->start_offset + i + 4, SEEK_SET);
830 readed = mmfile_read(fp, (unsigned char *)&sa3dTag, sizeof(MMFILE_MP4A_SA3D_TAGBOX));
831 if (readed != sizeof(MMFILE_MP4A_SA3D_TAGBOX)) {
832 debug_error(DEBUG, "read SA3D tag header fail\n");
836 sa3dTag.ambisonic_order = mmfile_io_be_uint32(sa3dTag.ambisonic_order);
837 sa3dTag.num_channels = mmfile_io_be_uint32(sa3dTag.num_channels);
838 for (i = 0; i < sa3dTag.num_channels; ++i)
839 sa3dTag.channel_map[i] = mmfile_io_be_uint32(sa3dTag.channel_map[i]);
841 debug_msg(RELEASE, "sa3dTag.version = %d", sa3dTag.version);
842 debug_msg(RELEASE, "sa3dTag.ambisonic_type = %d", sa3dTag.ambisonic_type);
843 debug_msg(RELEASE, "sa3dTag.ambisonic_order = %d", sa3dTag.ambisonic_order);
844 debug_msg(RELEASE, "sa3dTag.ambisonic_channel_ordering = %d", sa3dTag.ambisonic_channel_ordering);
845 debug_msg(RELEASE, "sa3dTag.ambisonic_normalization = %d", sa3dTag.ambisonic_normalization);
846 debug_msg(RELEASE, "sa3dTag.num_channels = %d", sa3dTag.num_channels);
847 for (i = 0; i < sa3dTag.num_channels; ++i)
848 debug_msg(RELEASE, "sa3dTag.channel_map[%d] = %d", i, sa3dTag.channel_map[i]);
850 if (sa3dTag.version != RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
851 debug_error(DEBUG, "SA3D tag box version is unsupported\n");
854 if (sa3dTag.ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
855 formatContext->ambisonicType = MMFILE_AMBISONIC_TYPE_PERIPHONIC;
857 switch (sa3dTag.ambisonic_order) {
858 case MMFILE_AMBISONIC_ORDER_FOA: {
859 if (sa3dTag.num_channels == 4) {
860 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_FOA;
862 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
863 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
864 (sa3dTag.channel_map[0] == 0) &&
865 (sa3dTag.channel_map[1] == 1) &&
866 (sa3dTag.channel_map[2] == 2) &&
867 (sa3dTag.channel_map[3] == 3))
868 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
870 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
871 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
872 (sa3dTag.channel_map[0] == 0) &&
873 (sa3dTag.channel_map[1] == 3) &&
874 (sa3dTag.channel_map[2] == 1) &&
875 (sa3dTag.channel_map[3] == 2))
876 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
878 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
884 case MMFILE_AMBISONIC_ORDER_SOA: {
885 if (sa3dTag.num_channels == 9) {
886 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_SOA;
888 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
889 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
890 (sa3dTag.channel_map[0] == 0) &&
891 (sa3dTag.channel_map[1] == 1) &&
892 (sa3dTag.channel_map[2] == 2) &&
893 (sa3dTag.channel_map[3] == 3) &&
894 (sa3dTag.channel_map[4] == 4) &&
895 (sa3dTag.channel_map[5] == 5) &&
896 (sa3dTag.channel_map[6] == 6) &&
897 (sa3dTag.channel_map[7] == 7) &&
898 (sa3dTag.channel_map[8] == 8))
899 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
901 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
902 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
903 (sa3dTag.channel_map[0] == 0) &&
904 (sa3dTag.channel_map[1] == 3) &&
905 (sa3dTag.channel_map[2] == 1) &&
906 (sa3dTag.channel_map[3] == 2) &&
907 (sa3dTag.channel_map[4] == 6) &&
908 (sa3dTag.channel_map[5] == 7) &&
909 (sa3dTag.channel_map[6] == 5) &&
910 (sa3dTag.channel_map[7] == 8) &&
911 (sa3dTag.channel_map[8] == 4))
912 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
914 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
921 case MMFILE_AMBISONIC_ORDER_TOA: {
922 if (sa3dTag.num_channels == 16) {
923 formatContext->ambisonicOrder = MMFILE_AMBISONIC_ORDER_TOA;
925 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN) &&
926 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D) &&
927 (sa3dTag.channel_map[0] == 0) &&
928 (sa3dTag.channel_map[1] == 1) &&
929 (sa3dTag.channel_map[2] == 2) &&
930 (sa3dTag.channel_map[3] == 3) &&
931 (sa3dTag.channel_map[4] == 4) &&
932 (sa3dTag.channel_map[5] == 5) &&
933 (sa3dTag.channel_map[6] == 6) &&
934 (sa3dTag.channel_map[7] == 7) &&
935 (sa3dTag.channel_map[8] == 8) &&
936 (sa3dTag.channel_map[9] == 9) &&
937 (sa3dTag.channel_map[10] == 10) &&
938 (sa3dTag.channel_map[11] == 11) &&
939 (sa3dTag.channel_map[12] == 12) &&
940 (sa3dTag.channel_map[13] == 13) &&
941 (sa3dTag.channel_map[14] == 14) &&
942 (sa3dTag.channel_map[15] == 15))
943 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMBIX;
945 if ((sa3dTag.ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA) &&
946 (sa3dTag.ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA) &&
947 (sa3dTag.channel_map[0] == 0) &&
948 (sa3dTag.channel_map[1] == 3) &&
949 (sa3dTag.channel_map[2] == 1) &&
950 (sa3dTag.channel_map[3] == 2) &&
951 (sa3dTag.channel_map[4] == 6) &&
952 (sa3dTag.channel_map[5] == 7) &&
953 (sa3dTag.channel_map[6] == 5) &&
954 (sa3dTag.channel_map[7] == 8) &&
955 (sa3dTag.channel_map[8] == 4) &&
956 (sa3dTag.channel_map[9] == 12) &&
957 (sa3dTag.channel_map[10] == 13) &&
958 (sa3dTag.channel_map[11] == 11) &&
959 (sa3dTag.channel_map[12] == 14) &&
960 (sa3dTag.channel_map[13] == 10) &&
961 (sa3dTag.channel_map[14] == 15) &&
962 (sa3dTag.channel_map[15] == 9))
963 formatContext->ambisonicFormat = MMFILE_AMBISONIC_FORMAT_AMB;
965 debug_error(DEBUG, "Incorrect metadata: ambisonic order and channels number do not correspond\n");
973 debug_warning(DEBUG, "Ambisonic order or format is not supported: ambix or amb formats up to 3rd order were expected.\n");
979 debug_msg(RELEASE, "formatContext->ambisonic_type = %d", formatContext->ambisonicType);
980 debug_msg(RELEASE, "formatContext->ambisonic_order = %d", formatContext->ambisonicOrder);
981 debug_msg(RELEASE, "formatContext->ambisonic_format = %d", formatContext->ambisonicFormat);
984 return MMFILE_UTIL_SUCCESS;
987 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
989 return MMFILE_UTIL_FAIL;
992 static int ParseSt3dData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset)
994 uint8_t stereo_mode = INVALID_UINT8_VALUE;
995 unsigned int readed = 0;
997 mmfile_seek(fp, start_offset, SEEK_SET);
999 readed = mmfile_read(fp, (unsigned char *)&stereo_mode, sizeof(uint8_t));
1000 if (readed != sizeof(uint8_t)) {
1001 debug_error(DEBUG, "read st3d tag header fail\n");
1002 return MMFILE_UTIL_FAIL;
1005 formatContext->stereoModeV2 = stereo_mode;
1007 return MMFILE_UTIL_SUCCESS;
1010 static int ParseSvhdData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset, unsigned int box_size)
1012 unsigned int readed = 0;
1014 formatContext->metadataSourceV2 = (char *)calloc(1, box_size);
1015 if (!formatContext->metadataSourceV2) {
1016 debug_error(DEBUG, "Calloc failed");
1017 return MMFILE_UTIL_FAIL;
1020 mmfile_seek(fp, start_offset, SEEK_SET);
1021 readed = mmfile_read(fp, (unsigned char *)formatContext->metadataSourceV2, box_size);
1022 if (readed != box_size) {
1023 debug_error(DEBUG, "read svhd tag header fail\n");
1024 if (formatContext->metadataSourceV2)
1025 free(formatContext->metadataSourceV2);
1026 return MMFILE_UTIL_FAIL;
1029 return MMFILE_UTIL_SUCCESS;
1032 static int ParseProjData(MMFileFormatContext *formatContext, MMFileIOHandle *fp, long long start_offset)
1034 unsigned int readed = 0;
1035 typedef struct proj_box_data_s {
1039 } __attribute__((aligned(1), packed)) proj_box_data;
1041 typedef struct prhd_box_data_s {
1042 uint32_t projection_pose_yaw;
1043 uint32_t projection_pose_pitch;
1044 uint32_t projection_pose_roll;
1047 typedef struct equi_box_data_s {
1048 uint32_t projection_bounds_top;
1049 uint32_t projection_bounds_bottom;
1050 uint32_t projection_bounds_left;
1051 uint32_t projection_bounds_right;
1054 typedef struct cbmp_box_data_s {
1060 proj_box_data proj_data;
1061 proj_data.proj_type = INVALID_UINT_VALUE;
1063 prhd_box_data prhd_data;
1064 prhd_data.projection_pose_yaw = INVALID_UINT_VALUE;
1065 prhd_data.projection_pose_pitch = INVALID_UINT_VALUE;
1066 prhd_data.projection_pose_roll = INVALID_UINT_VALUE;
1068 equi_box_data equi_data;
1069 equi_data.projection_bounds_top = INVALID_UINT_VALUE;
1070 equi_data.projection_bounds_bottom = INVALID_UINT_VALUE;
1071 equi_data.projection_bounds_left = INVALID_UINT_VALUE;
1072 equi_data.projection_bounds_right = INVALID_UINT_VALUE;
1074 cbmp_box_data cbmp_data;
1075 cbmp_data.layout = INVALID_UINT_VALUE;
1076 cbmp_data.padding = INVALID_UINT_VALUE;
1078 mmfile_seek(fp, start_offset, SEEK_SET);
1080 readed = mmfile_read(fp, (unsigned char *)&proj_data, sizeof(proj_box_data));
1081 if (readed != sizeof(proj_box_data)) {
1082 debug_error(DEBUG, "read of proj box failed\n");
1083 return MMFILE_UTIL_FAIL;
1086 formatContext->projTypeV2 = mmfile_io_be_uint32(proj_data.proj_type);
1088 debug_error(DEBUG, "formatContext->projTypeV2 = %d\n", formatContext->projTypeV2);
1089 debug_error(DEBUG, "proj_data.version = %d\n", proj_data.version);
1090 debug_error(DEBUG, "proj_data.flags = %d\n", ((uint32_t)proj_data.flags[0] << 16) +
1091 ((uint32_t)proj_data.flags[1] << 8) + (uint32_t)proj_data.flags[2]);
1093 mmfile_seek(fp, sizeof(proj_box_data), SEEK_CUR);
1094 readed = mmfile_read(fp, (unsigned char *)&prhd_data, sizeof(prhd_box_data));
1095 if (readed != sizeof(prhd_box_data)) {
1096 debug_error(DEBUG, "read of prhd box failed\n");
1097 return MMFILE_UTIL_FAIL;
1100 formatContext->poseYawV2 = mmfile_io_be_uint32(prhd_data.projection_pose_yaw);
1101 formatContext->posePitchV2 = mmfile_io_be_uint32(prhd_data.projection_pose_pitch);
1102 formatContext->poseRollV2 = mmfile_io_be_uint32(prhd_data.projection_pose_roll);
1104 debug_error(DEBUG, "formatContext->poseYawV2 = %d\n", formatContext->poseYawV2);
1105 debug_error(DEBUG, "formatContext->posePitchV2 = %d\n", formatContext->posePitchV2);
1106 debug_error(DEBUG, "formatContext->poseRollV2 = %d\n", formatContext->poseRollV2);
1108 if (formatContext->projTypeV2 == PROJECTION_TYPE_EQUI) {
1109 debug_msg(RELEASE, "Projection type is Equirectangular");
1110 mmfile_seek(fp, 8, SEEK_CUR); /* 8 = 4 (for size) + 4 (fourcc) */
1111 readed = mmfile_read(fp, (unsigned char *)&equi_data, sizeof(equi_box_data));
1112 if (readed != sizeof(equi_box_data)) {
1113 debug_error(DEBUG, "read of equi box failed\n");
1114 return MMFILE_UTIL_FAIL;
1117 formatContext->equiBoundsTopV2 = mmfile_io_be_uint32(equi_data.projection_bounds_top);
1118 formatContext->equiBoundsBottomV2 = mmfile_io_be_uint32(equi_data.projection_bounds_bottom);
1119 formatContext->equiBoundsLeftV2 = mmfile_io_be_uint32(equi_data.projection_bounds_left);
1120 formatContext->equiBoundsRightV2 = mmfile_io_be_uint32(equi_data.projection_bounds_right);
1122 debug_error(DEBUG, "formatContext->equiBoundsTopV2 = %d\n", formatContext->equiBoundsTopV2);
1123 debug_error(DEBUG, "formatContext->equiBoundsBottomV2 = %d\n", formatContext->equiBoundsBottomV2);
1124 debug_error(DEBUG, "formatContext->equiBoundsLeftV2 = %d\n", formatContext->equiBoundsLeftV2);
1125 debug_error(DEBUG, "formatContext->equiBoundsRightV2 = %d\n", formatContext->equiBoundsRightV2);
1127 } else if (formatContext->projTypeV2 == PROJECTION_TYPE_CBMP) {
1128 debug_msg(RELEASE, "Projection type is Cubemap");
1129 mmfile_seek(fp, 8, SEEK_CUR); /* 8 = 4 (for size) + 4 (fourcc) */
1130 readed = mmfile_read(fp, (unsigned char *)&cbmp_data, sizeof(cbmp_box_data));
1131 if (readed != sizeof(cbmp_box_data)) {
1132 debug_error(DEBUG, "read of cbmp box failed\n");
1133 return MMFILE_UTIL_FAIL;
1136 formatContext->cbmpLayoutV2 = mmfile_io_be_uint32(cbmp_data.layout);
1137 formatContext->cbmpPaddingV2 = mmfile_io_be_uint32(cbmp_data.padding);
1139 debug_error(DEBUG, "formatContext->cbmpLayoutV2 = %d\n", formatContext->cbmpLayoutV2);
1140 debug_error(DEBUG, "formatContext->cbmpPaddingV2 = %d\n", formatContext->cbmpPaddingV2);
1143 debug_msg(RELEASE, "Projection type is %d (unknown)", proj_data.proj_type);
1144 return MMFILE_UTIL_FAIL;
1147 return MMFILE_UTIL_SUCCESS;
1150 static int GetVideoV2MetadataFromAvc1TagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1152 if (!formatContext || !fp || !basic_header) {
1153 debug_error(DEBUG, "invalid param\n");
1154 return MMFILE_UTIL_FAIL;
1157 unsigned char *buffer;
1161 formatContext->stereoModeV2 = INVALID_UINT_VALUE;
1162 formatContext->metadataSourceV2 = NULL;
1163 formatContext->projTypeV2 = INVALID_UINT_VALUE;
1164 formatContext->poseYawV2 = INVALID_UINT_VALUE;
1165 formatContext->posePitchV2 = INVALID_UINT_VALUE;
1166 formatContext->poseRollV2 = INVALID_UINT_VALUE;
1167 formatContext->cbmpLayoutV2 = INVALID_UINT_VALUE;
1168 formatContext->cbmpPaddingV2 = INVALID_UINT_VALUE;
1169 formatContext->equiBoundsTopV2 = INVALID_UINT_VALUE;
1170 formatContext->equiBoundsBottomV2 = INVALID_UINT_VALUE;
1171 formatContext->equiBoundsLeftV2 = INVALID_UINT_VALUE;
1172 formatContext->equiBoundsRightV2 = INVALID_UINT_VALUE;
1174 mmfile_seek(fp, basic_header->start_offset, SEEK_SET);
1176 buffer = calloc(basic_header->size + 1, sizeof(unsigned char));
1178 debug_error(DEBUG, "calloc failed ");
1182 readed = mmfile_read(fp, buffer, basic_header->size);
1183 if (readed != (int)basic_header->size) {
1184 debug_error(DEBUG, "read st3d box failed\n");
1188 for (i = 0; i + 3 < basic_header->size; ++i) {
1189 if ((buffer[i] == 's' && buffer[i + 1] == 't' && buffer[i + 2] == '3' && buffer[i + 3] == 'd') && (formatContext->stereoModeV2 == INVALID_UINT_VALUE)) {
1190 debug_warning(DEBUG, "st3d data found at offset %lld\n", basic_header->start_offset + i);
1191 ParseSt3dData(formatContext, fp, basic_header->start_offset + i + 4);
1192 debug_msg(RELEASE, "formatContext->stereoModeV2 = %d", formatContext->stereoModeV2);
1194 if (buffer[i] == 's' && buffer[i + 1] == 'v' && buffer[i + 2] == '3' && buffer[i + 3] == 'd') {
1195 debug_warning(DEBUG, "sv3d data found at offset %lld\n", basic_header->start_offset + i);
1196 formatContext->isSpherical = true;
1198 if (buffer[i] == 's' && buffer[i + 1] == 'v' && buffer[i + 2] == 'h' && buffer[i + 3] == 'd') {
1199 debug_warning(DEBUG, "svhd data found at offset %lld\n", basic_header->start_offset + i);
1200 ParseSvhdData(formatContext, fp, basic_header->start_offset + i + 4, mmfile_io_be_uint32(*((uint32_t*)(buffer - 4 + i))));
1201 debug_msg(RELEASE, "formatContext->metadataSourceV2 = %s (length = %d)", formatContext->metadataSourceV2, strlen(formatContext->metadataSourceV2));
1203 if (buffer[i] == 'p' && buffer[i + 1] == 'r' && buffer[i + 2] == 'o' && buffer[i + 3] == 'j') {
1204 debug_warning(DEBUG, "proj data found at offset %lld\n", basic_header->start_offset + i);
1205 ParseProjData(formatContext, fp, basic_header->start_offset + i + 4);
1209 return MMFILE_UTIL_SUCCESS;
1212 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1214 return MMFILE_UTIL_FAIL;
1217 static int GetValueFromCDISTagBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1219 unsigned int value = 0;
1222 if (!formatContext || !fp || !basic_header) {
1223 debug_error(DEBUG, "invalid param\n");
1224 return MMFILE_UTIL_FAIL;
1227 readed = mmfile_read(fp, (unsigned char *)&value, sizeof(unsigned int));
1228 if (readed != sizeof(unsigned int)) {
1229 debug_error(DEBUG, "read cdis tag header fail\n");
1233 value = mmfile_io_be_uint32(value);
1235 debug_msg(RELEASE, "Value : 0x%x", value);
1237 if (value == 0x01) {
1238 debug_msg(RELEASE, "This has cdis tag and valid value");
1239 formatContext->cdis = 1;
1241 debug_error(DEBUG, "This has cdis tag and but invalid value");
1245 return MMFILE_UTIL_SUCCESS;
1248 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1250 return MMFILE_UTIL_FAIL;
1253 static int GetTagFromMetaBox(MMFileFormatContext *formatContext, MMFileIOHandle *fp, MMFILE_MP4_BASIC_BOX_HEADER *basic_header)
1256 MMFILE_MP4_BASIC_BOX_HEADER hdlrBoxHeader = {0, };
1257 MMFILE_MP4_BASIC_BOX_HEADER id3v2BoxHeader = {0, };
1258 MMFILE_3GP_ID3V2_BOX id3v2Box = {0, };
1259 AvFileContentInfo tagInfo = {0, };
1260 unsigned char tagVersion = 0;
1261 bool versionCheck = false;
1263 unsigned int meta_version = 0;
1264 MMFILE_3GP_HANDLER_BOX hdlrBox = {0, };
1265 unsigned int encSize = 0;
1267 #ifdef ENABLE_ITUNES_META /* We don't support itunes meta now. so this is not defined yet */
1268 int iTunes_meta = 0;
1272 readed = mmfile_read(fp, (unsigned char *)&meta_version, 4);
1274 debug_error(DEBUG, "read meta box version\n");
1279 readed = mmfile_read(fp, (unsigned char *)&hdlrBoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1280 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1281 debug_error(DEBUG, "read hdlr box header\n");
1285 if (hdlrBoxHeader.type != FOURCC('h', 'd', 'l', 'r')) {
1286 debug_warning(DEBUG, "meta type is not hdlr\n");
1290 hdlrBoxHeader.size = mmfile_io_be_uint32(hdlrBoxHeader.size);
1291 hdlrBoxHeader.type = mmfile_io_le_uint32(hdlrBoxHeader.type);
1293 readed = mmfile_read(fp, (unsigned char *)&hdlrBox, MMFILE_3GP_HANDLER_BOX_LEN);
1294 if (readed != MMFILE_3GP_HANDLER_BOX_LEN) {
1295 debug_error(DEBUG, "read hdlr box\n");
1299 hdlrBox.handler_type = mmfile_io_le_uint32(hdlrBox.handler_type);
1302 * check tag type (ID3v2 or iTunes)
1304 if (hdlrBox.handler_type == FOURCC('I', 'D', '3', '2')) {
1305 debug_msg(RELEASE, "ID3v2 tag detected.\n");
1308 #ifdef ENABLE_ITUNES_META
1311 } else if (hdlrBox.handler_type == FOURCC('m', 'd', 'i', 'r') &&
1312 mmfile_io_le_uint32(hdlrBox.reserved[0]) == FOURCC('a', 'p', 'p', 'l')) {
1314 debug_msg(RELEASE, "Apple iTunes tag detected by mdir.\n");
1316 #ifdef ENABLE_ITUNES_META
1320 debug_warning(DEBUG, "unknown meta type. 4CC:[%c%c%c%c]\n", ((char *)&hdlrBox.handler_type)[0],
1321 ((char *)&hdlrBox.handler_type)[1],
1322 ((char *)&hdlrBox.handler_type)[2],
1323 ((char *)&hdlrBox.handler_type)[3]);
1324 /*goto exception; */
1327 #ifdef ENABLE_ITUNES_META
1328 if (!id3_meta && !iTunes_meta) {
1330 APPLE meta data for iTunes reader = 'mdir.' so if handler type is 'mdir', this content may has itunes meta.
1331 most of contents has 'mdir' + 'appl'. but some contents just has 'mdir'
1332 but 'ilst' is meta for iTunes. so find 'ilst' is more correct to check if this contents has iTunes meta or not.*/
1334 const char *ilst_box = "ilst";
1335 int buf_size = strlen(ilst_box);
1337 unsigned char read_buf[buf_size + 1];
1338 memset(read_buf, 0x00, buf_size + 1);
1341 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN + 4, SEEK_CUR); /*+4 is hdlr size field */
1343 readed = mmfile_read(fp, read_buf, buf_size); /* to find 'ilst' */
1344 if (readed != buf_size) {
1345 debug_error(DEBUG, "read fail [%d]\n", readed);
1349 if (read_buf[0] == 'i' && read_buf[1] == 'l' && read_buf[2] == 's' && read_buf[3] == 't') {
1350 debug_msg(RELEASE, "Apple iTunes tag detected by ilst.\n");
1356 #ifdef ENABLE_ITUNES_META
1359 * iTunes (Cover[?ovr] & Track[trkn] only extract!) + Genre/Artist : Added 2010.10.27,28
1367 #define _ITUNES_READ_BUF_SZ 20
1368 #define _ITUNES_TRACK_NUM_SZ 4
1369 #define _ITUNES_GENRE_NUM_SZ 4
1370 #define _ITUNES_COVER_TYPE_JPEG 13
1371 #define _ITUNES_COVER_TYPE_PNG 14
1373 unsigned char read_buf[_ITUNES_READ_BUF_SZ];
1375 int cover_sz = 0, cover_type = 0, cover_found = 0;
1376 /* int track_found = 0; */ /* , track_num = 0; */
1377 /* int genre_found = 0; */ /* , genre_index = 0; */
1378 /* int artist_found = 0; */ /* , artist_sz = 0; */
1379 int limit = basic_header->size - hdlrBoxHeader.size;
1380 long long cover_offset = 0; /*, track_offset =0, genre_offset = 0, artist_offset = 0; */
1382 /* for (i = 0, cover_found = 0, track_found = 0, genre_found = 0, artist_found = 0; i < limit && (cover_found == 0 || track_found == 0 || genre_found == 0 || artist_found == 0) ; i++) { */
1383 for (i = 0; (i < limit) && (cover_found == 0) ; i++) {
1384 readed = mmfile_read(fp, read_buf, _ITUNES_READ_BUF_SZ);
1385 if (readed != _ITUNES_READ_BUF_SZ)
1388 /*ffmpeg extract artist, tracknum, genre and cover image. see mov_read_udta_string().
1389 but ffmpeg does not support strange cover image.
1390 only support covr type 0xd(JPEG), 0xe(PNG), 0x1b(BMP). but we support other type*/
1393 * Artist : Added 2010.10.28
1395 if (artist_found == 0 &&
1396 read_buf[0] == 0xa9 && read_buf[1] == 'A' && read_buf[2] == 'R' && read_buf[3] == 'T' &&
1397 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1400 artist_offset = mmfile_tell(fp);
1401 artist_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 16; /* atom len(4)+data(4)+atom verion(1)+flag(3)+null(4) = 16 */
1403 debug_msg(RELEASE, "----------------------------------- artist found, offset=[%lld], size=[%d]\n", artist_offset, artist_sz);
1409 if (track_found == 0 &&
1410 read_buf[0] == 't' && read_buf[1] == 'r' && read_buf[2] == 'k' && read_buf[3] == 'n' &&
1411 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1414 track_offset = mmfile_tell(fp);
1416 debug_msg(RELEASE, "----------------------------------- Track found, offset=[%lld]\n", track_offset);
1420 * Genre : Added 2010.10.27
1422 /*ffmpeg extract genre but only (0xa9,'g','e','n'). see mov_read_udta_string()*/
1423 if (genre_found == 0 &&
1424 read_buf[0] == 'g' && read_buf[1] == 'n' && read_buf[2] == 'r' && read_buf[3] == 'e' &&
1425 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1428 genre_offset = mmfile_tell(fp);
1430 debug_msg(RELEASE, "----------------------------------- genre found, offset=[%lld]\n", genre_offset);
1438 if (cover_found == 0 &&
1439 read_buf[0] == 'c' && read_buf[1] == 'o' && read_buf[2] == 'v' && read_buf[3] == 'r' &&
1440 read_buf[8] == 'd' && read_buf[9] == 'a' && read_buf[10] == 't' && read_buf[11] == 'a') {
1443 cover_sz = mmfile_io_be_uint32(*(int *)(read_buf + 4)) - 12;
1444 cover_type = mmfile_io_be_uint32(*(int *)(read_buf + 12));
1446 cover_offset = mmfile_tell(fp);
1448 debug_msg(RELEASE, "----------------------------------- cover_found found, offset=[%lld]\n", cover_offset);
1451 mmfile_seek(fp, -(_ITUNES_READ_BUF_SZ - 1), SEEK_CUR); /*FIXME: poor search*/
1454 /*ffmpeg extract artist, tracknum, excep cover image. see mov_read_udta_string()*/
1457 if (artist_sz > 0) {
1458 mmfile_seek(fp, artist_offset, SEEK_SET);
1460 if (formatContext->artist) {
1461 debug_msg(RELEASE, "----------------------------------- previous artist was [%s] \n", formatContext->artist);
1462 free(formatContext->artist);
1465 debug_msg(RELEASE, "----------------------------------- new artist will be allocated with size (len+1) [%d] \n", artist_sz + 1);
1466 formatContext->artist = mmfile_malloc(artist_sz + 1);
1468 if (formatContext->artist) {
1469 readed = mmfile_read(fp, (unsigned char *)formatContext->artist, artist_sz);
1470 formatContext->artist[artist_sz] = '\0';
1472 debug_msg(RELEASE, "----------------------------------- new artist is [%s] \n", formatContext->artist);
1474 if (readed != artist_sz) {
1475 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, artist_sz);
1476 mmfile_free(formatContext->artist);
1483 mmfile_seek(fp, track_offset, SEEK_SET);
1484 readed = mmfile_read(fp, read_buf, _ITUNES_TRACK_NUM_SZ);
1485 if (readed != _ITUNES_TRACK_NUM_SZ) {
1486 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, _ITUNES_TRACK_NUM_SZ);
1488 track_num = mmfile_io_be_uint32(*(int *)read_buf);
1489 if (!formatContext->tagTrackNum) {
1490 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1491 snprintf((char *)read_buf, sizeof(read_buf), "%d", track_num);
1492 formatContext->tagTrackNum = mmfile_strdup((const char *)read_buf);
1498 mmfile_seek(fp, genre_offset, SEEK_SET);
1499 readed = mmfile_read(fp, read_buf, _ITUNES_GENRE_NUM_SZ);
1500 if (readed != _ITUNES_GENRE_NUM_SZ) {
1501 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, _ITUNES_GENRE_NUM_SZ);
1503 genre_index = mmfile_io_be_uint16(*(int *)read_buf);
1504 debug_msg(RELEASE, "genre index=[%d] \n", genre_index);
1506 if (genre_index > 0 && genre_index < GENRE_COUNT) {
1507 if (!formatContext->genre) {
1508 memset(read_buf, 0x00, _ITUNES_READ_BUF_SZ);
1509 snprintf((char *)read_buf, sizeof(read_buf), "%s", MpegAudio_Genre[genre_index - 1]);
1510 debug_msg(RELEASE, "genre string=[%s] \n", read_buf);
1511 formatContext->genre = mmfile_strdup((const char *)read_buf);
1519 1) below spec is in "iTunes Package Asset Specification 4.3" published by apple.
1520 Music Cover Art Image Profile
1521 - TIFF with ".tif" extension (32-bit uncompressed), JPEG with ".jpg" extension (quality unconstrained), or PNG with ".png" extension
1522 - RGB (screen standard)
1523 - Minimum size of 600 x 600 pixels
1524 - Images must be at least 72 dpi
1526 2)I found below info from google.
1527 cover image flag : JPEG (13, 0xd), PNG (14, 0xe)
1529 3)So, FIXME when cover image format is tif!
1533 mmfile_seek(fp, cover_offset, SEEK_SET);
1535 formatContext->artwork = mmfile_malloc(cover_sz);
1536 formatContext->artworkSize = cover_sz;
1537 if (cover_type == _ITUNES_COVER_TYPE_JPEG) {
1538 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1539 } else if (cover_type == _ITUNES_COVER_TYPE_PNG) {
1540 formatContext->artworkMime = mmfile_strdup("image/png");
1541 /*} else if(cover_type == _ITUNES_COVER_TYPE_TIF) {
1542 formatContext->artworkMime = mmfile_strdup("image/tif");*/
1544 debug_warning(DEBUG, "Not proper cover image type, but set to jpeg. cover_type[%d]", cover_type);
1545 formatContext->artworkMime = mmfile_strdup("image/jpeg");
1548 if (formatContext->artwork) {
1549 readed = mmfile_read(fp, formatContext->artwork, cover_sz);
1550 if (readed != cover_sz) {
1551 debug_error(DEBUG, "failed to read. ret = %d, in = %d\n", readed, cover_sz);
1552 mmfile_free(formatContext->artwork);
1553 formatContext->artworkSize = 0;
1554 mmfile_free(formatContext->artworkMime);
1560 /*reset seek position*/
1561 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1563 return MMFILE_UTIL_SUCCESS;
1571 /* skip hdlr box name */
1572 mmfile_seek(fp, hdlrBoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_HANDLER_BOX_LEN, SEEK_CUR);
1575 readed = mmfile_read(fp, (unsigned char *)&id3v2BoxHeader, MMFILE_MP4_BASIC_BOX_HEADER_LEN);
1576 if (readed != MMFILE_MP4_BASIC_BOX_HEADER_LEN) {
1577 debug_error(DEBUG, "read id3v2 box header\n");
1581 id3v2BoxHeader.size = mmfile_io_be_uint32(id3v2BoxHeader.size);
1582 id3v2BoxHeader.type = mmfile_io_le_uint32(id3v2BoxHeader.type);
1584 if (id3v2BoxHeader.type != FOURCC('I', 'D', '3', '2')) {
1585 debug_warning(DEBUG, "meta type is not id3v2\n");
1589 readed = mmfile_read(fp, (unsigned char *)&id3v2Box, MMFILE_3GP_ID3V2_BOX_LEN);
1590 if (readed != MMFILE_3GP_ID3V2_BOX_LEN) {
1591 debug_error(DEBUG, "read id3v2 box\n");
1595 id3v2Len = id3v2BoxHeader.size - MMFILE_MP4_BASIC_BOX_HEADER_LEN - MMFILE_3GP_ID3V2_BOX_LEN;
1597 id3v2Box.id3v2Data = mmfile_malloc(id3v2Len);
1598 if (!id3v2Box.id3v2Data) {
1599 debug_error(DEBUG, "malloc id3tag data error\n");
1603 readed = mmfile_read(fp, (unsigned char *)id3v2Box.id3v2Data, id3v2Len);
1604 if (readed != id3v2Len) {
1605 debug_error(DEBUG, "read id3tag data error\n");
1610 if (!IS_ID3V2_TAG(id3v2Box.id3v2Data)) {
1611 debug_error(DEBUG, "it is not id3tag\n");
1615 if (id3v2Box.id3v2Data[3] == 0xFF || id3v2Box.id3v2Data[4] == 0xFF ||
1616 id3v2Box.id3v2Data[6] >= 0x80 || id3v2Box.id3v2Data[7] >= 0x80 ||
1617 id3v2Box.id3v2Data[8] >= 0x80 || id3v2Box.id3v2Data[9] >= 0x80) {
1618 debug_error(DEBUG, "it is not valid id3tag\n");
1622 tagVersion = id3v2Box.id3v2Data[3];
1623 if (tagVersion > 4) {
1624 debug_error(DEBUG, "tag vesion is too high\n");
1628 encSize = mmfile_io_le_uint32((unsigned int)&id3v2Box.id3v2Data[6]);
1629 tagInfo.tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
1630 tagInfo.tagV2Info.tagLen += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
1631 tagInfo.tagV2Info.tagVersion = tagVersion;
1632 tagInfo.fileLen = id3v2Len;
1634 /* set id3v2 data to formatContext */
1635 switch (tagVersion) {
1637 versionCheck = mm_file_id3tag_parse_v222(&tagInfo, id3v2Box.id3v2Data);
1641 versionCheck = mm_file_id3tag_parse_v223(&tagInfo, id3v2Box.id3v2Data);
1645 versionCheck = mm_file_id3tag_parse_v224(&tagInfo, id3v2Box.id3v2Data);
1650 debug_error(DEBUG, "tag vesion is not support\n");
1651 versionCheck = false;
1656 if (versionCheck == false) {
1657 debug_error(DEBUG, "tag parsing is fail\n");
1661 if (!formatContext->title) formatContext->title = mmfile_strdup((const char *)tagInfo.pTitle);
1662 if (!formatContext->artist) formatContext->artist = mmfile_strdup((const char *)tagInfo.pArtist);
1663 if (!formatContext->author) formatContext->author = mmfile_strdup((const char *)tagInfo.pAuthor);
1664 if (!formatContext->copyright) formatContext->copyright = mmfile_strdup((const char *)tagInfo.pCopyright);
1665 if (!formatContext->comment) formatContext->comment = mmfile_strdup((const char *)tagInfo.pComment);
1666 if (!formatContext->album) formatContext->album = mmfile_strdup((const char *)tagInfo.pAlbum);
1667 if (!formatContext->album_artist) formatContext->album_artist = mmfile_strdup((const char *)tagInfo.pAlbum_Artist);
1668 if (!formatContext->year) formatContext->year = mmfile_strdup((const char *)tagInfo.pYear);
1669 if (!formatContext->genre) formatContext->genre = mmfile_strdup((const char *)tagInfo.pGenre);
1670 if (!formatContext->tagTrackNum) formatContext->tagTrackNum = mmfile_strdup((const char *)tagInfo.pTrackNum);
1671 if (!formatContext->composer) formatContext->composer = mmfile_strdup((const char *)tagInfo.pComposer);
1672 if (!formatContext->classification) formatContext->classification = mmfile_strdup((const char *)tagInfo.pContentGroup);
1673 if (!formatContext->conductor) formatContext->conductor = mmfile_strdup((const char *)tagInfo.pConductor);
1675 formatContext->artwork = mmfile_malloc(tagInfo.imageInfo.imageLen);
1676 if ((tagInfo.imageInfo.imageLen > 0) && formatContext->artwork) {
1677 formatContext->artworkSize = tagInfo.imageInfo.imageLen;
1678 memcpy(formatContext->artwork, tagInfo.imageInfo.pImageBuf, tagInfo.imageInfo.imageLen);
1681 mm_file_free_AvFileContentInfo(&tagInfo);
1682 mmfile_free(id3v2Box.id3v2Data);
1684 /*reset seek position*/
1685 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1687 return MMFILE_UTIL_SUCCESS;
1693 mmfile_seek(fp, basic_header->start_offset + basic_header->size, SEEK_SET);
1694 mmfile_free(id3v2Box.id3v2Data);
1695 mm_file_free_AvFileContentInfo(&tagInfo);
1697 return MMFILE_UTIL_FAIL;
1700 int mm_file_get_int_value_from_xml_string(const char* xml_str, const char* param_name, int* value)
1702 char *value_start, *value_end, *endptr;
1703 const short value_length_max = 12;
1704 char init_view_ret[value_length_max];
1705 int value_length = 0;
1707 if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1708 debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
1709 return MMFILE_UTIL_FAIL;
1712 value_start = strstr(xml_str, param_name) + strlen(param_name);
1713 while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1716 value_end = strchr(value_start, '<');
1718 debug_error(DEBUG, "error: incorrect XML\n");
1719 return MMFILE_UTIL_FAIL;
1722 value_length = value_end - value_start;
1723 while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1727 if (value_start[i] == '+' || value_start[i] == '-')
1729 while (i < value_length) {
1730 if (value_start[i] < '0' || value_start[i] > '9') {
1731 debug_error(DEBUG, "error: incorrect value, integer was expected\n");
1732 return MMFILE_UTIL_FAIL;
1737 if (value_length >= value_length_max || value_length < 1) {
1738 debug_error(DEBUG, "error: empty XML value or incorrect range\n");
1739 return MMFILE_UTIL_FAIL;
1742 memset(init_view_ret, 0x00, sizeof(init_view_ret));
1743 SAFE_STRLCPY(init_view_ret, value_start, sizeof(init_view_ret));
1745 *value = strtol(init_view_ret, &endptr, 10);
1746 if (endptr == init_view_ret) {
1747 debug_error(DEBUG, "error: no digits were found\n");
1748 return MMFILE_UTIL_FAIL;
1751 return MMFILE_UTIL_SUCCESS;
1754 int mm_file_get_string_value_from_xml_string(const char* xml_str, const char* param_name, char** value)
1756 char *value_start, *value_end;
1757 const short value_length_max = 256;
1758 int value_length = 0;
1760 if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1761 debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
1762 return MMFILE_UTIL_FAIL;
1765 value_start = strstr(xml_str, param_name) + strlen(param_name);
1766 while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1769 value_end = strchr(value_start, '<');
1771 debug_error(DEBUG, "error: incorrect XML\n");
1772 return MMFILE_UTIL_FAIL;
1775 value_length = value_end - value_start;
1776 while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1779 if (value_length >= value_length_max || value_length < 1) {
1780 debug_error(DEBUG, "error: empty XML value or incorrect range\n");
1781 return MMFILE_UTIL_FAIL;
1784 *value = (char*)calloc(value_length, sizeof(char));
1785 if (*value == NULL) {
1786 debug_error(DEBUG, "error: calloc failed\n");
1787 return MMFILE_UTIL_FAIL;
1789 strncpy(*value, value_start, value_length);
1791 return MMFILE_UTIL_SUCCESS;
1794 int mm_file_get_bool_value_from_xml_string(const char* xml_str, const char* param_name, bool* value)
1796 char *value_start, *value_end;
1797 int value_length = 0;
1799 if (!xml_str || !param_name || !strstr(xml_str, param_name)) {
1800 debug_error(DEBUG, "error: incorrect or non-existing parameter\n");
1801 return MMFILE_UTIL_FAIL;
1804 value_start = strstr(xml_str, param_name) + strlen(param_name);
1805 while ((value_start[0] == ' ') || (value_start[0] == '\t'))
1808 value_end = strchr(value_start, '<');
1810 debug_error(DEBUG, "error: incorrect XML\n");
1811 return MMFILE_UTIL_FAIL;
1814 value_length = value_end - value_start;
1815 while ((value_length >= 1) && ((value_start[value_length - 1] == ' ') || (value_start[value_length - 1] == '\t')))
1818 if (value_length < 1) {
1819 debug_error(DEBUG, "error: empty XML value or incorrect range\n");
1820 return MMFILE_UTIL_FAIL;
1823 *value = strstr(value_start, "true") ? true : false;
1825 return MMFILE_UTIL_SUCCESS;
1828 static int g_junk_counter_limit = 0;
1829 static int GetJunkCounterLimit(void)
1831 dictionary *dict = NULL;
1834 dict = iniparser_load(MM_FILE_INI_PATH);
1836 debug_error(DEBUG, "%s load failed", MM_FILE_INI_PATH);
1840 data = iniparser_getint(dict, "mm-file-config:junk_counter_limit", 0);
1841 debug_msg(DEBUG, "mm-file-config:junk_counter_limit= %u", data);
1843 iniparser_freedict(dict);
1848 static int ParseSpatialVideoMetadataFromXMLString(const char *xmlStr, MMFileFormatContext *formatContext)
1850 const char is_spherical_str[] = "<GSpherical:Spherical>";
1851 const char is_stitched_str[] = "<GSpherical:Stitched>";
1852 const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
1853 const char projection_type_str[] = "<GSpherical:ProjectionType>";
1854 const char stereo_mode_str[] = "<GSpherical:StereoMode>";
1855 const char source_count_str[] = "<GSpherical:SourceCount>";
1856 const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
1857 const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
1858 const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
1859 const char timestamp_str[] = "<GSpherical:Timestamp>";
1860 const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
1861 const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
1862 const char cropped_area_image_width_str[] = "<GSpherical:CroppedAreaImageWidthPixels>";
1863 const char cropped_area_image_height_str[] = "<GSpherical:CroppedAreaImageHeightPixels>";
1864 const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
1865 const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
1867 mm_file_get_bool_value_from_xml_string(xmlStr, is_spherical_str, (bool*)&formatContext->isSpherical);
1868 mm_file_get_bool_value_from_xml_string(xmlStr, is_stitched_str, (bool*)&formatContext->isStitched);
1870 debug_msg(RELEASE, "isSpherical = %d", formatContext->isSpherical);
1871 debug_msg(RELEASE, "isStitched = %d", formatContext->isStitched);
1873 if (formatContext->isSpherical && formatContext->isStitched) {
1874 mm_file_get_string_value_from_xml_string(xmlStr, stitching_software_str, &formatContext->stitchingSoftware);
1875 mm_file_get_string_value_from_xml_string(xmlStr, projection_type_str, &formatContext->projectionType);
1876 mm_file_get_string_value_from_xml_string(xmlStr, stereo_mode_str, &formatContext->stereoMode);
1877 mm_file_get_int_value_from_xml_string(xmlStr, source_count_str, &formatContext->sourceCount);
1878 mm_file_get_int_value_from_xml_string(xmlStr, init_view_heading_str, &formatContext->initViewHeading);
1879 mm_file_get_int_value_from_xml_string(xmlStr, init_view_pitch_str, &formatContext->initViewPitch);
1880 mm_file_get_int_value_from_xml_string(xmlStr, init_view_roll_str, &formatContext->initViewRoll);
1881 mm_file_get_int_value_from_xml_string(xmlStr, timestamp_str, &formatContext->timestamp);
1882 mm_file_get_int_value_from_xml_string(xmlStr, full_pano_width_str, &formatContext->fullPanoWidth);
1883 mm_file_get_int_value_from_xml_string(xmlStr, full_pano_height_str, &formatContext->fullPanoHeight);
1884 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_width_str, &formatContext->croppedAreaImageWidth);
1885 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_image_height_str, &formatContext->croppedAreaImageHeight);
1886 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_left_str, &formatContext->croppedAreaLeft);
1887 mm_file_get_int_value_from_xml_string(xmlStr, cropped_area_top_str, &formatContext->croppedAreaTop);
1889 debug_msg(RELEASE, "stitchingSoftware = %s", formatContext->stitchingSoftware);
1890 debug_msg(RELEASE, "projectionType = %s", formatContext->projectionType);
1891 debug_msg(RELEASE, "stereoMode = %s", formatContext->stereoMode);
1892 debug_msg(RELEASE, "sourceCount %d", formatContext->sourceCount);
1893 debug_msg(RELEASE, "initViewHeading = %d", formatContext->initViewHeading);
1894 debug_msg(RELEASE, "initViewPitch = %d", formatContext->initViewPitch);
1895 debug_msg(RELEASE, "initViewRoll = %d", formatContext->initViewRoll);
1896 debug_msg(RELEASE, "timestamp = %d", formatContext->timestamp);
1897 debug_msg(RELEASE, "fullPanoWidthPixels = %d", formatContext->fullPanoWidth);
1898 debug_msg(RELEASE, "fullPanoHeightPixels = %d", formatContext->fullPanoHeight);
1899 debug_msg(RELEASE, "croppedAreaImageWidth = %d", formatContext->croppedAreaImageWidth);
1900 debug_msg(RELEASE, "croppedAreaImageHeight = %d", formatContext->croppedAreaImageHeight);
1901 debug_msg(RELEASE, "croppedAreaLeft = %d", formatContext->croppedAreaLeft);
1902 debug_msg(RELEASE, "croppedAreaTop = %d", formatContext->croppedAreaTop);
1905 return MMFILE_UTIL_SUCCESS;
1908 #define BIG_CONTENT_BOX_SIZE_LEN 8
1909 EXPORT_API int MMFileUtilGetMetaDataFromMP4(MMFileFormatContext *formatContext)
1911 MMFileIOHandle *fp = NULL;
1914 unsigned long long chunk_size = 0;
1915 long long moov_end = 0;
1916 MMFILE_MP4_BASIC_BOX_HEADER basic_header = {0, };
1917 int junk_counter = 0;
1919 ret = mmfile_open(&fp, formatContext->uriFileName, MMFILE_RDONLY);
1920 if (ret == MMFILE_UTIL_FAIL) {
1921 debug_error(DEBUG, "error: mmfile_open\n");
1925 basic_header.start_offset = mmfile_tell(fp);
1927 if (g_junk_counter_limit == 0)
1928 g_junk_counter_limit = GetJunkCounterLimit();
1930 while ((ret != MMFILE_UTIL_FAIL) && ((readed = mmfile_read(fp, (unsigned char *)&basic_header, MMFILE_MP4_BASIC_BOX_HEADER_LEN)) == MMFILE_MP4_BASIC_BOX_HEADER_LEN)) {
1931 basic_header.size = mmfile_io_be_uint32(basic_header.size);
1932 basic_header.type = mmfile_io_le_uint32(basic_header.type);
1934 if (basic_header.size == 0) {
1935 debug_warning(DEBUG, "header is invalid.\n");
1936 basic_header.size = readed;
1937 basic_header.type = 0;
1938 chunk_size = basic_header.size;
1940 if ((moov_end != 0) && (moov_end < basic_header.start_offset)) {
1941 debug_msg(DEBUG, "found junk data but moov data already was extracted, so junk counter will be increase: %d", junk_counter);
1944 /* stop the loop for junk case. */
1945 if ((g_junk_counter_limit > 0) && (junk_counter > g_junk_counter_limit)) {
1946 debug_msg(DEBUG, "stop the loop by junk-data checker");
1947 ret = MMFILE_UTIL_FAIL;
1951 } else if (basic_header.size == 1) {
1953 unsigned char temp[BIG_CONTENT_BOX_SIZE_LEN] = {0, };
1954 unsigned long long size = 0;
1956 mmfile_read(fp, (unsigned char *)&temp, BIG_CONTENT_BOX_SIZE_LEN);
1958 for (i = 0; i < BIG_CONTENT_BOX_SIZE_LEN; i++)
1959 size |= (unsigned long long)temp[i] << (BIG_CONTENT_BOX_SIZE_LEN - 1 - i) * BIG_CONTENT_BOX_SIZE_LEN;
1963 chunk_size = basic_header.size;
1967 switch (basic_header.type) {
1968 case FOURCC('m', 'o', 'o', 'v'): {
1969 debug_msg(RELEASE, "MPEG4: [moov] SIZE: [%lld]Byte\n", chunk_size);
1970 moov_end = basic_header.start_offset + chunk_size;
1973 case FOURCC('u', 'd', 't', 'a'): {
1974 debug_msg(RELEASE, "MPEG4: [udat] SIZE: [%lld]Byte\n", chunk_size);
1977 /*/////////////////////////////////////////////////////////////// */
1978 /* Extracting Tag Data // */
1979 /*/////////////////////////////////////////////////////////////// */
1980 case FOURCC('t', 'i', 't', 'l'): {
1981 debug_msg(RELEASE, "MPEG4: [titl] SIZE: [%lld]Byte\n", chunk_size);
1982 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_TITLE);
1985 case FOURCC('d', 's', 'c', 'p'): {
1986 debug_msg(RELEASE, "MPEG4: [dscp] SIZE: [%lld]Byte\n", chunk_size);
1987 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_CAPTION);
1990 case FOURCC('c', 'p', 'r', 't'): {
1991 debug_msg(RELEASE, "MPEG4: [cprt] SIZE: [%lld]Byte\n", chunk_size);
1992 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_COPYRIGHT);
1995 case FOURCC('p', 'e', 'r', 'f'): {
1996 debug_msg(RELEASE, "MPEG4: [perf] SIZE: [%lld]Byte\n", chunk_size);
1997 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_PERFORMER);
2000 case FOURCC('a', 'u', 't', 'h'): {
2001 debug_msg(RELEASE, "MPEG4: [auth] SIZE: [%lld]Byte\n", chunk_size);
2002 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_AUTHOR);
2005 case FOURCC('g', 'n', 'r', 'e'): {
2006 debug_msg(RELEASE, "MPEG4: [gnre] SIZE: [%lld]Byte\n", chunk_size);
2007 GetStringFromTextTagBox(formatContext, fp, &basic_header, eMMFILE_3GP_TAG_GENRE);
2010 case FOURCC('a', 'l', 'b', 'm'): {
2011 debug_msg(RELEASE, "MPEG4: [albm] SIZE: [%lld]Byte\n", chunk_size);
2012 GetAlbumFromAlbumTagBox(formatContext, fp, &basic_header);
2015 case FOURCC('y', 'r', 'r', 'c'): {
2016 debug_msg(RELEASE, "MPEG4: [yrrc] SIZE: [%lld]Byte\n", chunk_size);
2017 GetYearFromYearTagBox(formatContext, fp, &basic_header);
2020 case FOURCC('r', 't', 'n', 'g'): {
2021 debug_msg(RELEASE, "MPEG4: [rtng] SIZE: [%lld]Byte\n", chunk_size);
2022 GetRatingFromRatingTagBox(formatContext, fp, &basic_header); /* not use */
2025 case FOURCC('c', 'l', 's', 'f'): {
2026 debug_msg(RELEASE, "MPEG4: [clsf] SIZE: [%lld]Byte\n", chunk_size);
2027 GetClassficationFromClsfTagBox(formatContext, fp, &basic_header);
2030 case FOURCC('k', 'y', 'w', 'd'): {
2031 debug_msg(RELEASE, "MPEG4: [kywd] SIZE: [%lld]Byte\n", chunk_size);
2032 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2035 case FOURCC('l', 'o', 'c', 'i'): {
2036 debug_msg(RELEASE, "MPEG4: [loci] SIZE: [%lld]Byte\n", chunk_size);
2037 GetLocationFromLociTagBox(formatContext, fp, &basic_header);
2040 /* Check smta in user data field (moov) to be compatible with android */
2041 case FOURCC('s', 'm', 't', 'a'): {
2042 debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
2043 GetSAUTInfoFromSMTATagBox(formatContext, fp, &basic_header);
2046 /* Check cdis in user data field (moov) to be compatible with android */
2047 case FOURCC('c', 'd', 'i', 's'): {
2048 debug_msg(RELEASE, "MPEG4: [smta] SIZE: [%lld]Byte\n", chunk_size);
2049 GetValueFromCDISTagBox(formatContext, fp, &basic_header);
2052 /*/////////////////////////////////////////////////////////////// */
2053 /* Extracting ID3 Tag Data // */
2054 /*/////////////////////////////////////////////////////////////// */
2055 case FOURCC('m', 'e', 't', 'a'): {
2056 debug_msg(RELEASE, "MPEG4: [meta] SIZE: [%lld]Byte\n", chunk_size);
2057 GetTagFromMetaBox(formatContext, fp, &basic_header);
2061 case FOURCC('t', 'r', 'a', 'k'): {
2062 debug_msg(RELEASE, "MPEG4: [trak] SIZE: [%lld]Byte\n", chunk_size);
2065 case FOURCC('u', 'u', 'i', 'd'): {
2066 unsigned long uuid[4] = {0, };
2068 debug_msg(RELEASE, "MPEG4: [uuid] SIZE: [%lld]Byte\n", chunk_size);
2070 mmfile_read(fp, (unsigned char *)uuid, sizeof(uuid));
2072 if (mmfile_io_be_uint32(uuid[0]) == 0xffcc8263
2073 && mmfile_io_be_uint32(uuid[1]) == 0xf8554a93
2074 && mmfile_io_be_uint32(uuid[2]) == 0x8814587a
2075 && mmfile_io_be_uint32(uuid[3]) == 0x02521fdd) {
2077 str = (char *)malloc(basic_header.size);
2080 memset(str, 0, basic_header.size);
2081 mmfile_read(fp, (unsigned char *)str, basic_header.size);
2083 /* The block is superseded */
2084 if (strstr(str, "<GSpherical:Spherical>true</GSpherical:Spherical>"))
2085 formatContext->is_360 = 1;
2087 formatContext->is_360 = 0;
2088 /* Image can be stitched even if it is not spherical */
2089 if (formatContext->is_360 == 1) {
2090 if (strstr(str, "<GSpherical:Stitched>true</GSpherical:Stitched>"))
2091 formatContext->stitched = MMFILE_360_STITCHED;
2093 formatContext->stitched = MMFILE_360_NON_STITCHED;
2095 /* Image can be stitched or non-stitched. Usage of some 3rd value is superfluous */
2096 formatContext->stitched = MMFILE_360_NONE;
2100 debug_msg(RELEASE, "Extracting tags from UUID XML string %s\n", str);
2102 ParseSpatialVideoMetadataFromXMLString(str, formatContext);
2105 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2109 case FOURCC('m', 'd', 'i', 'a'): {
2110 debug_msg(RELEASE, "MPEG4: [mdia] SIZE: [%lld]Byte\n", chunk_size);
2113 case FOURCC('m', 'i', 'n', 'f'): {
2114 debug_msg(RELEASE, "MPEG4: [minf] SIZE: [%lld]Byte\n", chunk_size);
2117 case FOURCC('s', 't', 'b', 'l'): {
2118 debug_msg(RELEASE, "MPEG4: [stbl] SIZE: [%lld]Byte\n", chunk_size);
2121 case FOURCC('s', 't', 's', 'd'): {
2122 debug_msg(RELEASE, "MPEG4: [stsd] SIZE: [%lld]Byte\n", chunk_size);
2125 case FOURCC('m', 'p', '4', 'a'): {
2126 debug_msg(RELEASE, "MPEG4: [mp4a] SIZE: [%lld]Byte\n", chunk_size);
2127 GetSA3DInfoFromMP4ATagBox(formatContext, fp, &basic_header);
2128 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2131 case FOURCC('a', 'v', 'c', '1'): {
2132 debug_msg(RELEASE, "MPEG4: [avc1] SIZE: [%lld]Byte (offset: %lld)\n", chunk_size, basic_header.start_offset);
2133 GetVideoV2MetadataFromAvc1TagBox(formatContext, fp, &basic_header);
2137 debug_msg(RELEASE, "4CC: Not Support [%c%c%c%c]. So skip it. Size [%lld Byte]\n",
2138 ((char *)&basic_header.type)[0], ((char *)&basic_header.type)[1],
2139 ((char *)&basic_header.type)[2], ((char *)&basic_header.type)[3], chunk_size);
2140 ret = mmfile_seek(fp, basic_header.start_offset + chunk_size, SEEK_SET);
2145 if (ret == MMFILE_UTIL_FAIL) {
2146 debug_error(DEBUG, "mmfile operation is error\n");
2151 basic_header.start_offset = mmfile_tell(fp);
2159 static char *get_string(const char *buf, int buf_size, int *bytes_written)
2163 char str[512] = {0, };
2166 for (i = 0; i < buf_size; i++) {
2170 if ((q - str) >= (int)sizeof(str) - 1)
2176 if (strlen(str) > 0) {
2177 *bytes_written = strlen(str);
2185 static bool is_numeric(const char *buf, int buf_size)
2190 for (idx = 0; idx < buf_size; idx++) {
2191 if (isdigit((int)buf[idx])) {
2202 char *rtrimN(char *pStr)
2205 pos = strlen(pStr) - 1;
2206 for (; pos >= 0; pos--) {
2207 if (pStr[pos] == 0x20) {
2214 return strdup(pStr);
2217 bool safe_atoi(char *buffer, int *si)
2223 const long sl = strtol(buffer, &end, 10);
2225 if (end == buffer) {
2226 debug_error(RELEASE, "not a decimal number");
2228 } else if ('\0' != *end) {
2229 debug_error(RELEASE, "extra characters at end of input: %s", end);
2231 } else if ((LONG_MIN == sl || LONG_MAX == sl) && (ERANGE == errno)) {
2232 debug_error(RELEASE, "out of range of type long");
2234 } else if (sl > INT_MAX) {
2235 debug_error(RELEASE, "greater than INT_MAX");
2237 } else if (sl < INT_MIN) {
2238 debug_error(RELEASE, "less than INT_MIN");
2246 static bool make_characterset_array(char ***charset_array)
2248 char *locale = MMFileUtilGetLocale(NULL);
2250 *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
2252 if (*charset_array == NULL) {
2253 debug_error(DEBUG, "calloc failed ");
2259 if (locale != NULL) {
2260 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
2262 debug_error(DEBUG, "get locale failed");
2263 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
2266 (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
2267 (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
2268 (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
2273 static bool release_characterset_array(char **charset_array)
2277 for (i = 0; i < AV_ID3V2_MAX; i++) {
2278 if (charset_array[i] != NULL) {
2279 free(charset_array[i]);
2280 charset_array[i] = NULL;
2284 if (charset_array != NULL) {
2285 free(charset_array);
2286 charset_array = NULL;
2292 static void init_content_info(AvFileContentInfo *pInfo)
2294 pInfo->tagV2Info.bTitleMarked = false;
2295 pInfo->tagV2Info.bArtistMarked = false;
2296 pInfo->tagV2Info.bAlbumMarked = false;
2297 pInfo->tagV2Info.bAlbum_ArtistMarked = false;
2298 pInfo->tagV2Info.bYearMarked = false;
2299 pInfo->tagV2Info.bDescriptionMarked = false;
2300 pInfo->tagV2Info.bGenreMarked = false;
2301 pInfo->tagV2Info.bTrackNumMarked = false;
2302 pInfo->tagV2Info.bEncByMarked = false;
2303 pInfo->tagV2Info.bURLMarked = false;
2304 pInfo->tagV2Info.bCopyRightMarked = false;
2305 pInfo->tagV2Info.bOriginArtistMarked = false;
2306 pInfo->tagV2Info.bComposerMarked = false;
2307 pInfo->tagV2Info.bImageMarked = false;
2309 pInfo->tagV2Info.bRecDateMarked = false;
2310 pInfo->tagV2Info.bContentGroupMarked = false;
2312 pInfo->tagV2Info.bUnsyncLyricsMarked = false;
2313 pInfo->tagV2Info.bSyncLyricsMarked = false;
2314 pInfo->tagV2Info.bConductorMarked = false;
2315 pInfo->tagV2Info.bGenreUTF16 = false;
2317 pInfo->imageInfo.bURLInfo = false;
2318 pInfo->imageInfo.pImageBuf = NULL;
2319 pInfo->imageInfo.imageLen = 0;
2323 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo, unsigned char *buffer)
2325 const char *locale = MMFileUtilGetLocale(NULL);
2326 char *pFullStr = NULL;
2328 debug_msg(RELEASE, "ID3tag v110--------------------------------------------------------------\n");
2330 if (pInfo->tagV2Info.bTitleMarked == false) {
2331 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
2332 if (pFullStr != NULL) {
2333 pInfo->pTitle = rtrimN(pFullStr);
2337 debug_msg(RELEASE, "pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2340 if (pInfo->tagV2Info.bArtistMarked == false) {
2341 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
2342 if (pFullStr != NULL) {
2343 pInfo->pArtist = rtrimN(pFullStr);
2347 debug_msg(RELEASE, "pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2350 if (pInfo->tagV2Info.bAlbumMarked == false) {
2351 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
2352 if (pFullStr != NULL) {
2353 pInfo->pAlbum = rtrimN(pFullStr);
2357 debug_msg(RELEASE, "pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2360 if (pInfo->tagV2Info.bYearMarked == false) {
2362 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
2364 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2366 if (pInfo->pYear == NULL) { /*Use same logic with ffmpeg*/
2367 pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
2368 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2372 if (pInfo->tagV2Info.bDescriptionMarked == false) {
2373 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
2374 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2376 if (pInfo->pComment == NULL) { /*Use same logic with ffmpeg*/
2377 pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
2378 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2382 if (pInfo->tagV2Info.bTrackNumMarked == false) {
2383 pInfo->pTrackNum = mmfile_malloc(5);
2384 if (pInfo->pTrackNum != NULL) {
2385 pInfo->pTrackNum[4] = 0;
2386 snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
2387 pInfo->tracknumLen = strlen(pInfo->pTrackNum);
2389 debug_msg(RELEASE, "pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2393 if (pInfo->tagV2Info.bGenreMarked == false) {
2394 pInfo->genre = buffer[127];
2395 debug_msg(RELEASE, "pInfo->genre returned genre number (%d)\n", pInfo->genre);
2402 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
2404 unsigned long taglen = 0;
2405 unsigned long needToloopv2taglen;
2406 unsigned long oneFrameLen = 0;
2407 unsigned long v2numOfFrames = 0;
2408 unsigned long curPos = 0;
2410 unsigned char *pExtContent = NULL;
2411 unsigned long purelyFramelen = 0;
2412 unsigned int encodingOffSet = 0;
2413 int inx = 0, realCpyFrameNum = 0,
2414 /*checkImgMimeTypeMax = 0, */checkImgExtMax = 0,
2415 imgstartOffset = 0, tmp = 0;
2417 int textEncodingType = 0;
2419 char **charset_array = NULL;
2421 make_characterset_array(&charset_array);
2423 init_content_info(pInfo);
2425 taglen = pInfo->tagV2Info.tagLen;
2426 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2427 curPos = MP3_TAGv2_HEADER_LEN;
2429 debug_msg(RELEASE, "ID3tag v222--------------------------------------------------------------\n");
2431 if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
2433 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
2434 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2435 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
2438 memcpy(CompTmp, &buffer[curPos], 3);
2441 oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
2442 oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
2443 | (unsigned long)buffer[5 + curPos];
2444 if (oneFrameLen > taglen - curPos)
2446 purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
2447 curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
2449 if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2450 curPos += purelyFramelen;
2452 if (buffer[curPos - purelyFramelen] == 0x00) {
2454 textEncodingType = AV_ID3V2_ISO_8859;
2455 } else if (buffer[curPos - purelyFramelen] == 0x01) {
2457 textEncodingType = AV_ID3V2_UTF16;
2460 /*in order to deliver valid string to MP */
2461 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2464 if (encodingOffSet < purelyFramelen) {
2465 realCpyFrameNum = purelyFramelen - encodingOffSet;
2466 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2468 if (pExtContent == NULL) {
2469 debug_error(DEBUG, "out of memory for pExtContent\n");
2473 memset(pExtContent, '\0', realCpyFrameNum + 3);
2475 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2477 if (realCpyFrameNum > 0) {
2478 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2479 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2480 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2481 pInfo->tagV2Info.bTitleMarked = true;
2482 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2483 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2484 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2485 pInfo->tagV2Info.bArtistMarked = true;
2486 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2487 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2488 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2489 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2490 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2491 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2492 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2493 pInfo->tagV2Info.bConductorMarked = true;
2494 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2495 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2496 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2497 pInfo->tagV2Info.bAlbumMarked = true;
2498 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2499 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2500 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2501 pInfo->tagV2Info.bYearMarked = true;
2502 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2503 /*skip language data! */
2504 if (realCpyFrameNum > 4) {
2505 realCpyFrameNum -= 4;
2508 /*pExtContent[tmp+1] value should't have encoding value */
2509 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
2510 if (pExtContent[tmp - 1] == 0x00)
2511 textEncodingType = AV_ID3V2_ISO_8859;
2513 textEncodingType = AV_ID3V2_UTF16;
2515 pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2516 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2517 pInfo->tagV2Info.bDescriptionMarked = true;
2519 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2522 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2526 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2527 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2528 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2530 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2534 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2537 ret = safe_atoi(pInfo->pGenre, &int_genre);
2539 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
2541 /*Change int to string */
2542 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2543 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2544 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
2545 int tmp_genre_len = 0;
2547 memset(tmp_genre, 0, 6);
2548 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2550 tmp_genre_len = strlen(tmp_genre);
2551 if (tmp_genre_len > 0) {
2552 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2553 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2554 if (pInfo->pGenre) {
2555 SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
2560 debug_error(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
2565 pInfo->tagV2Info.bGenreMarked = true;
2566 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2567 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2568 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2569 pInfo->tagV2Info.bTrackNumMarked = true;
2570 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2571 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2572 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2573 pInfo->tagV2Info.bEncByMarked = true;
2574 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2575 if (realCpyFrameNum > 4) {
2576 /*skip language data! */
2577 realCpyFrameNum -= 4;
2580 /*pExtContent[tmp+1] value should't have null value */
2581 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
2582 if (pExtContent[tmp - 1] == 0x00)
2583 textEncodingType = AV_ID3V2_ISO_8859;
2585 textEncodingType = AV_ID3V2_UTF16;
2587 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2588 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2589 pInfo->tagV2Info.bURLMarked = true;
2591 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2594 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2597 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2598 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2599 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2600 pInfo->tagV2Info.bCopyRightMarked = true;
2601 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2602 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2603 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2604 pInfo->tagV2Info.bOriginArtistMarked = true;
2605 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2606 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2607 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2608 pInfo->tagV2Info.bComposerMarked = true;
2609 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2610 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2611 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2612 pInfo->tagV2Info.bRecDateMarked = true;
2613 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2614 if (pExtContent[0] != 0) {
2615 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
2616 pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
2618 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
2619 pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
2623 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
2626 imgstartOffset += checkImgExtMax;
2628 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2629 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2631 imgstartOffset++;/*PictureType(1byte) */
2633 if (pExtContent[imgstartOffset] != 0x0) {
2636 int new_dis_len = 0;
2637 char *tmp_desc = NULL;
2640 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2641 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2642 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2645 /*check end of image description*/
2646 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2647 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2648 debug_msg(RELEASE, "length of description (%d)", cur_pos);
2655 dis_len = cur_pos + 1;
2657 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2659 if (tmp_desc != NULL) {
2660 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2662 /*convert description*/
2663 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2664 mmfile_free(tmp_desc);
2665 debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2666 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2669 imgstartOffset += cur_pos;
2671 pInfo->imageInfo.imgDesLen = 0;
2674 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2675 imgstartOffset++; /* endofDesceriptionType(1byte) */
2677 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2681 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2683 if (realCpyFrameNum - imgstartOffset > 0) {
2684 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2685 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2687 if (pInfo->imageInfo.pImageBuf != NULL) {
2688 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2689 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2692 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2693 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2695 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2699 /*checkImgMimeTypeMax = 0;*/
2703 pInfo->tagV2Info.bImageMarked = true;
2710 curPos += purelyFramelen;
2711 if (purelyFramelen != 0)
2712 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2715 if (pExtContent) _FREE_EX(pExtContent);
2716 memset(CompTmp, 0, 4);
2717 if (curPos < taglen) {
2718 needToloopv2taglen -= oneFrameLen;
2721 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2724 realCpyFrameNum = 0;
2725 textEncodingType = 0;
2731 release_characterset_array(charset_array);
2741 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2743 unsigned long taglen = 0;
2744 unsigned long needToloopv2taglen;
2745 unsigned long oneFrameLen = 0;
2746 unsigned long v2numOfFrames = 0;
2747 unsigned long curPos = 0;
2749 unsigned char *pExtContent = NULL;
2750 unsigned long purelyFramelen = 0;
2751 unsigned int encodingOffSet = 0;
2752 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2753 unsigned int textEncodingType = 0;
2754 char **charset_array = NULL;
2755 const char *MIME_PRFIX = "image/";
2757 make_characterset_array(&charset_array);
2759 init_content_info(pInfo);
2761 taglen = pInfo->tagV2Info.tagLen;
2762 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2763 curPos = MP3_TAGv2_HEADER_LEN;
2765 debug_msg(RELEASE, "ID3tag v223--------------------------------------------------------------\n");
2767 /* check Extended Header */
2768 if (buffer[5] & 0x40) {
2769 /* if extended header exists, skip it*/
2770 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2772 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2774 if (extendedHeaderLen > (int)(taglen - curPos)) {
2775 debug_error(DEBUG, "extended header too long.\n");
2777 curPos += extendedHeaderLen;
2782 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2784 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2785 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2786 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2789 memcpy(CompTmp, &buffer[curPos], 4);
2792 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2793 oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2794 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2796 debug_msg(RELEASE, "----------------------------------------------------------------------------------------------------\n");
2798 if (oneFrameLen > taglen - curPos)
2801 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2802 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2804 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2805 curPos += purelyFramelen;
2807 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2809 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2810 textEncodingType = AV_ID3V2_UTF16;
2811 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2813 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2814 textEncodingType = AV_ID3V2_UTF16_BE;
2815 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2817 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2818 textEncodingType = AV_ID3V2_UTF16;
2819 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2821 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2822 textEncodingType = AV_ID3V2_UTF16_BE;
2824 if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2825 debug_msg(RELEASE, "encodingOffset will be set to 1\n");
2828 debug_msg(RELEASE, "Finding encodingOffset\n");
2830 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2833 textEncodingType = AV_ID3V2_ISO_8859;
2834 debug_msg(RELEASE, "this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2837 if (pExtContent) _FREE_EX(pExtContent);
2839 if (encodingOffSet < purelyFramelen) {
2840 realCpyFrameNum = purelyFramelen - encodingOffSet;
2841 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2843 if (pExtContent == NULL) {
2844 debug_msg(DEBUG, "pExtContent malloc failed\n");
2848 memset(pExtContent, '\0', realCpyFrameNum + 3);
2850 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2851 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2852 debug_msg(RELEASE, "get the new text ecoding type\n");
2853 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2857 if (textEncodingType > AV_ID3V2_MAX) {
2858 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2862 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2863 if (realCpyFrameNum > 0) {
2864 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2865 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2866 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2867 pInfo->tagV2Info.bTitleMarked = true;
2869 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2870 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2871 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2872 pInfo->tagV2Info.bArtistMarked = true;
2873 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2874 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2875 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2876 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2877 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2878 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2879 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2880 pInfo->tagV2Info.bConductorMarked = true;
2881 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2882 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2883 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2884 pInfo->tagV2Info.bAlbumMarked = true;
2885 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2886 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2887 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2888 pInfo->tagV2Info.bYearMarked = true;
2889 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2890 if (realCpyFrameNum > 3) {
2891 realCpyFrameNum -= 3;
2894 /*pExtContent[tmp+1] value should't have encoding value */
2895 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2896 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2897 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2898 realCpyFrameNum -= 4;
2902 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2903 realCpyFrameNum -= 2;
2905 textEncodingType = AV_ID3V2_UTF16;
2906 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2907 realCpyFrameNum -= 2;
2909 textEncodingType = AV_ID3V2_UTF16_BE;
2910 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2911 realCpyFrameNum -= 3;
2913 textEncodingType = AV_ID3V2_UTF16;
2914 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2915 realCpyFrameNum -= 3;
2917 textEncodingType = AV_ID3V2_UTF16_BE;
2919 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
2922 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2926 textEncodingType = AV_ID3V2_ISO_8859;
2929 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2930 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2932 debug_msg(RELEASE, "failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2933 pInfo->commentLen = 0;
2936 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2937 pInfo->commentLen = 0;
2941 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2942 pInfo->tagV2Info.bDescriptionMarked = true;
2943 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2946 int copy_start_pos = tmp;
2947 AvSynclyricsInfo *synclyrics_info = NULL;
2948 GList *synclyrics_info_list = NULL;
2950 if (realCpyFrameNum > 5) {
2951 realCpyFrameNum -= 5;
2954 /*pExtContent[tmp+1] value should't have encoding value */
2955 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2956 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2957 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2958 realCpyFrameNum -= 4;
2962 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2963 realCpyFrameNum -= 2;
2965 textEncodingType = AV_ID3V2_UTF16;
2966 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2967 realCpyFrameNum -= 2;
2969 textEncodingType = AV_ID3V2_UTF16_BE;
2970 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2971 realCpyFrameNum -= 3;
2973 textEncodingType = AV_ID3V2_UTF16;
2974 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2975 realCpyFrameNum -= 3;
2977 textEncodingType = AV_ID3V2_UTF16_BE;
2979 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
2982 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2986 textEncodingType = AV_ID3V2_ISO_8859;
2989 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2991 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2992 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
2993 pInfo->syncLyricsNum = 0;
2995 if (textEncodingType == AV_ID3V2_UTF16) {
2996 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
2997 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
2998 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3000 for (idx = 0; idx < realCpyFrameNum; idx++) {
3001 if (pExtContent[tmp + idx] == 0x00) {
3002 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3004 if (synclyrics_info != NULL) {
3005 if (textEncodingType == AV_ID3V2_UTF8) {
3006 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3007 if (synclyrics_info->lyric_info != NULL) {
3008 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3009 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3010 synclyrics_info->lyric_info[copy_len] = '\0';
3013 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);
3016 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];
3018 copy_start_pos = tmp + idx + 1;
3019 debug_msg(RELEASE, "[%lu][%s] idx[%d], copy_len[%d] copy_start_pos[%d]", synclyrics_info->time_info, synclyrics_info->lyric_info, idx, copy_len, copy_start_pos);
3021 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3026 pInfo->pSyncLyrics = synclyrics_info_list;
3027 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3031 debug_msg(RELEASE, "failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3032 pInfo->syncLyricsNum = 0;
3035 debug_msg(RELEASE, "Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3036 pInfo->syncLyricsNum = 0;
3040 //debug_msg(RELEASE, "pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
3041 debug_msg(RELEASE, "pInfo->syncLyricsNum(%d)\n", pInfo->syncLyricsNum);
3042 pInfo->tagV2Info.bSyncLyricsMarked = true;
3043 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3044 char *lang_info = strndup((char *)pExtContent, 3);
3046 if (realCpyFrameNum > 3) {
3047 realCpyFrameNum -= 3;
3050 /*find start of lyrics */
3052 if (pExtContent[tmp] == 0x00) {
3053 if (pExtContent[tmp + 1] == 0x00) {
3054 realCpyFrameNum -= 2;
3064 /*pExtContent[tmp+1] value should't have encoding value */
3065 debug_msg(RELEASE, "tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
3067 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
3068 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3069 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3070 realCpyFrameNum -= 4;
3074 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3075 realCpyFrameNum -= 2;
3077 textEncodingType = AV_ID3V2_UTF16;
3078 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3079 realCpyFrameNum -= 2;
3081 textEncodingType = AV_ID3V2_UTF16_BE;
3082 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
3083 realCpyFrameNum -= 3;
3085 textEncodingType = AV_ID3V2_UTF16;
3086 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
3087 realCpyFrameNum -= 3;
3089 textEncodingType = AV_ID3V2_UTF16_BE;
3091 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3094 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3098 textEncodingType = AV_ID3V2_ISO_8859;
3101 char *char_set = NULL;
3103 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3105 if (textEncodingType == AV_ID3V2_ISO_8859) {
3106 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
3107 char_set = strdup("EUC-KR");
3109 char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
3111 _FREE_EX(lang_info);
3114 if (char_set == NULL) {
3115 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3117 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3121 debug_msg(RELEASE, "failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3122 pInfo->unsynclyricsLen = 0;
3125 debug_msg(RELEASE, "Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3126 pInfo->unsynclyricsLen = 0;
3130 debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3131 pInfo->tagV2Info.bUnsyncLyricsMarked = true;
3132 mmfile_free(lang_info);
3133 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3134 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3135 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3137 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3141 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3144 ret = safe_atoi(pInfo->pGenre, &int_genre);
3146 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
3148 /*Change int to string */
3149 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3150 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3151 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3152 int tmp_genre_len = 0;
3154 memset(tmp_genre, 0, 6);
3155 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3157 tmp_genre_len = strlen(tmp_genre);
3158 if (tmp_genre_len > 0) {
3159 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3160 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3161 if (pInfo->pGenre) {
3162 SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
3167 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
3172 pInfo->tagV2Info.bGenreMarked = true;
3173 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3174 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3175 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3176 pInfo->tagV2Info.bTrackNumMarked = true;
3177 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3178 pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3179 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3180 pInfo->tagV2Info.bEncByMarked = true;
3181 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3182 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3183 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3184 pInfo->tagV2Info.bURLMarked = true;
3185 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3186 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3187 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3188 pInfo->tagV2Info.bCopyRightMarked = true;
3189 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3190 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3191 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3192 pInfo->tagV2Info.bOriginArtistMarked = true;
3193 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3194 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3195 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3196 pInfo->tagV2Info.bComposerMarked = true;
3197 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
3198 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3199 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3200 pInfo->tagV2Info.bRecDateMarked = true;
3201 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3202 debug_msg(DEBUG, "text encoding %d \n", textEncodingType);
3204 if (pExtContent[0] != '\0') {
3205 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3206 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3208 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3209 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3210 checkImgMimeTypeMax++;
3212 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3214 pInfo->imageInfo.imgMimetypeLen = 0;
3215 debug_msg(RELEASE, "APIC image's not included to MIME type\n");
3218 imgstartOffset += checkImgMimeTypeMax;
3220 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3221 pInfo->imageInfo.imgMimetypeLen = 0;
3222 debug_error(DEBUG, "APIC NOT VALID");
3226 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3227 imgstartOffset++;/*endofMIME(1byte) */
3228 debug_msg(RELEASE, "after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
3230 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3231 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3233 debug_msg(RELEASE, "APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
3235 imgstartOffset++;/*PictureType(1byte) */
3236 debug_msg(RELEASE, "after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
3238 if (pExtContent[imgstartOffset] != 0x0) {
3241 int new_dis_len = 0;
3242 char *tmp_desc = NULL;
3245 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3246 if (realCpyFrameNum < imgstartOffset + cur_pos) {
3247 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3250 /*check end of image description*/
3251 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
3252 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
3253 debug_msg(RELEASE, "length of description (%d)", cur_pos);
3260 dis_len = cur_pos + 1;
3262 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3263 if (tmp_desc != NULL) {
3264 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3266 /*convert description*/
3267 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3268 debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3269 mmfile_free(tmp_desc);
3271 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3274 imgstartOffset += cur_pos;
3276 pInfo->imageInfo.imgDesLen = 0;
3277 debug_msg(RELEASE, "APIC image's not included to Description!!!\n");
3280 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3281 imgstartOffset++; /* endofDesceriptionType(1byte) */
3283 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
3287 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3289 if (realCpyFrameNum - imgstartOffset > 0) {
3290 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3291 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3293 if (pInfo->imageInfo.pImageBuf != NULL) {
3294 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3295 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3298 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3299 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3301 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3303 debug_msg(RELEASE, "pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
3305 debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
3306 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
3309 debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
3310 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
3313 checkImgMimeTypeMax = 0;
3316 pInfo->tagV2Info.bImageMarked = true;
3319 debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3324 debug_msg(RELEASE, "All of the pExtContent Values are NULL\n");
3327 curPos += purelyFramelen;
3328 if (purelyFramelen != 0)
3329 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3331 debug_msg(RELEASE, "This Frame's size is Zero! purelyFramelen(%lu)\n", purelyFramelen);
3334 if (pExtContent) _FREE_EX(pExtContent);
3335 memset(CompTmp, 0, 4);
3337 if (curPos < taglen) {
3338 needToloopv2taglen -= oneFrameLen;
3341 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3344 realCpyFrameNum = 0;
3345 textEncodingType = 0;
3351 release_characterset_array(charset_array);
3361 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
3363 unsigned long taglen = 0;
3364 unsigned long needToloopv2taglen;
3365 unsigned long oneFrameLen = 0;
3366 unsigned long v2numOfFrames = 0;
3367 unsigned long curPos = 0;
3369 unsigned char *pExtContent = NULL;
3370 unsigned long purelyFramelen = 0;
3371 unsigned int encodingOffSet = 0;
3372 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
3373 unsigned int textEncodingType = 0;
3374 char **charset_array = NULL;
3375 const char *MIME_PRFIX = "image/";
3377 make_characterset_array(&charset_array);
3379 init_content_info(pInfo);
3381 taglen = pInfo->tagV2Info.tagLen;
3382 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
3383 curPos = MP3_TAGv2_HEADER_LEN;
3385 debug_msg(RELEASE, "ID3tag v224--------------------------------------------------------------\n");
3387 /* check Extended Header */
3388 if (buffer[5] & 0x40) {
3389 /* if extended header exists, skip it*/
3390 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
3392 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
3394 if (extendedHeaderLen > (int)(taglen - curPos)) {
3395 debug_error(DEBUG, "extended header too long.\n");
3397 curPos += extendedHeaderLen;
3401 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
3403 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
3404 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
3405 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
3408 memcpy(CompTmp, &buffer[curPos], 4);
3411 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
3412 oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
3413 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
3414 if (oneFrameLen > taglen - curPos)
3417 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
3418 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
3420 debug_msg(RELEASE, "-----------------------------------------------------------------------------------\n");
3422 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
3423 curPos += purelyFramelen;
3425 /*in case of UTF 16 encoding */
3426 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
3427 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
3429 textEncodingType = AV_ID3V2_UTF16;
3430 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
3432 textEncodingType = AV_ID3V2_UTF16_BE;
3433 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
3435 textEncodingType = AV_ID3V2_UTF16;
3436 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
3438 textEncodingType = AV_ID3V2_UTF16_BE;
3440 /*in case of UTF-16 BE encoding */
3441 if (buffer[curPos - purelyFramelen] == 0x02) {
3443 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
3444 encodingOffSet++;/*null skip! */
3445 textEncodingType = AV_ID3V2_UTF16_BE;
3447 /*in case of UTF8 encoding */
3448 else if (buffer[curPos - purelyFramelen] == 0x03) {
3450 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
3451 encodingOffSet++;/*null skip! */
3452 textEncodingType = AV_ID3V2_UTF8;
3454 /*in case of ISO-8859-1 encoding */
3456 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
3458 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
3459 encodingOffSet++;/*less than 0x20 value skip! */
3460 textEncodingType = AV_ID3V2_ISO_8859;
3464 if (pExtContent) _FREE_EX(pExtContent);
3466 if (encodingOffSet < purelyFramelen) {
3467 realCpyFrameNum = purelyFramelen - encodingOffSet;
3468 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
3470 if (pExtContent == NULL) {
3471 debug_error(DEBUG, "out of memoryu for id3tag parse\n");
3475 memset(pExtContent, '\0', realCpyFrameNum + 3);
3477 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
3478 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
3479 debug_msg(RELEASE, "get the new text ecoding type\n");
3480 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
3484 if (textEncodingType > AV_ID3V2_MAX) {
3485 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
3489 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
3491 if (realCpyFrameNum > 0) {
3492 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
3493 if (textEncodingType == AV_ID3V2_UTF8) {
3494 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3495 if (pInfo->pTitle) {
3496 memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
3497 pInfo->pTitle[realCpyFrameNum] = '\0';
3498 /*string copy with '\0'*/
3499 pInfo->titleLen = realCpyFrameNum;
3500 _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
3503 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
3506 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
3507 pInfo->tagV2Info.bTitleMarked = true;
3509 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
3510 if (textEncodingType == AV_ID3V2_UTF8) {
3511 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3512 if (pInfo->pArtist) {
3513 memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
3514 pInfo->pArtist[realCpyFrameNum] = '\0';
3515 /*string copy with '\0'*/
3516 pInfo->artistLen = realCpyFrameNum;
3517 _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
3520 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
3524 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
3525 pInfo->tagV2Info.bArtistMarked = true;
3526 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
3527 if (textEncodingType == AV_ID3V2_UTF8) {
3528 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3529 if (pInfo->pAlbum_Artist) {
3530 memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
3531 pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
3532 /*string copy with '\0'*/
3533 pInfo->album_artistLen = realCpyFrameNum;
3534 _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
3537 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3540 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3541 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3542 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3543 if (textEncodingType == AV_ID3V2_UTF8) {
3544 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3545 if (pInfo->pConductor) {
3546 memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
3547 pInfo->pConductor[realCpyFrameNum] = '\0';
3548 /*string copy with '\0'*/
3549 pInfo->conductorLen = realCpyFrameNum;
3550 _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
3553 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3556 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3557 pInfo->tagV2Info.bConductorMarked = true;
3558 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3559 if (textEncodingType == AV_ID3V2_UTF8) {
3560 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3561 if (pInfo->pAlbum) {
3562 memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
3563 pInfo->pAlbum[realCpyFrameNum] = '\0';
3564 /*string copy with '\0'*/
3565 pInfo->albumLen = realCpyFrameNum;
3566 _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
3569 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3572 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3573 pInfo->tagV2Info.bAlbumMarked = true;
3574 } 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 */
3575 if (textEncodingType == AV_ID3V2_UTF8) {
3576 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3578 memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
3579 pInfo->pYear[realCpyFrameNum] = '\0';
3580 /*string copy with '\0'*/
3581 pInfo->yearLen = realCpyFrameNum;
3582 _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
3585 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3588 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3589 pInfo->tagV2Info.bYearMarked = true;
3590 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3591 if (realCpyFrameNum > 3) {
3592 realCpyFrameNum -= 3;
3595 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3596 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3597 realCpyFrameNum -= 4;
3601 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3602 realCpyFrameNum -= 2;
3604 textEncodingType = AV_ID3V2_UTF16;
3606 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
3608 } else if (textEncodingType == AV_ID3V2_UTF8) {
3609 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3613 textEncodingType = AV_ID3V2_UTF8;
3615 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3619 textEncodingType = AV_ID3V2_ISO_8859;
3622 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3624 if (textEncodingType == AV_ID3V2_UTF8) {
3625 pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3626 if (pInfo->pComment) {
3627 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
3628 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
3629 pInfo->pComment[realCpyFrameNum] = '\0';
3630 /*string copy with '\0'*/
3631 pInfo->commentLen = realCpyFrameNum;
3632 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
3635 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3638 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3643 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3644 pInfo->tagV2Info.bDescriptionMarked = true;
3645 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3648 int copy_start_pos = tmp;
3649 AvSynclyricsInfo *synclyrics_info = NULL;
3650 GList *synclyrics_info_list = NULL;
3652 if (realCpyFrameNum > 5) {
3653 realCpyFrameNum -= 5;
3656 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3657 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3658 realCpyFrameNum -= 4;
3662 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3663 realCpyFrameNum -= 2;
3665 textEncodingType = AV_ID3V2_UTF16;
3667 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
3669 } else if (textEncodingType == AV_ID3V2_UTF8) {
3670 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3674 textEncodingType = AV_ID3V2_UTF8;
3676 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3680 textEncodingType = AV_ID3V2_ISO_8859;
3683 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3685 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3686 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3687 pInfo->syncLyricsNum = 0;
3689 if (textEncodingType == AV_ID3V2_UTF16) {
3690 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3691 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3692 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3694 for (idx = 0; idx < realCpyFrameNum; idx++) {
3695 if (pExtContent[tmp + idx] == 0x00) {
3696 synclyrics_info = (AvSynclyricsInfo *)mmfile_malloc(sizeof(AvSynclyricsInfo));
3697 if (synclyrics_info) {
3698 if (textEncodingType == AV_ID3V2_UTF8) {
3699 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3700 if (synclyrics_info->lyric_info) {
3701 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3702 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3703 synclyrics_info->lyric_info[copy_len] = '\0';
3706 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3709 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];
3711 copy_start_pos = tmp + idx + 1;
3712 debug_msg(RELEASE, "[%lu][%s] idx[%d], copy_len[%d] copy_start_pos[%d]", synclyrics_info->time_info, synclyrics_info->lyric_info, idx, copy_len, copy_start_pos);
3714 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3719 pInfo->pSyncLyrics = synclyrics_info_list;
3720 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3724 debug_msg(RELEASE, "SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3728 pInfo->tagV2Info.bSyncLyricsMarked = true;
3729 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3730 if (realCpyFrameNum > 3) {
3731 realCpyFrameNum -= 3;
3734 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3735 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3736 realCpyFrameNum -= 4;
3740 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3741 realCpyFrameNum -= 2;
3743 textEncodingType = AV_ID3V2_UTF16;
3745 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3747 } else if (textEncodingType == AV_ID3V2_UTF8) {
3748 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3752 textEncodingType = AV_ID3V2_UTF8;
3754 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3758 textEncodingType = AV_ID3V2_ISO_8859;
3761 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3763 if (textEncodingType == AV_ID3V2_UTF8) {
3764 pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3766 if (pInfo->pUnsyncLyrics != NULL) {
3767 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3768 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3769 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3770 /*string copy with '\0'*/
3771 pInfo->unsynclyricsLen = realCpyFrameNum;
3772 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3774 debug_error(DEBUG, "out of memoryu for SyncLyrics\n");
3777 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3780 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3785 debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3786 pInfo->tagV2Info.bDescriptionMarked = true;
3787 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3788 if (textEncodingType == AV_ID3V2_UTF8) {
3789 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3790 if (pInfo->pGenre) {
3791 memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3792 pInfo->pGenre[realCpyFrameNum] = '\0';
3793 /*string copy with '\0'*/
3794 pInfo->genreLen = realCpyFrameNum;
3795 _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3798 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3801 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3803 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3807 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3810 ret = safe_atoi(pInfo->pGenre, &int_genre);
3812 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
3814 /*Change int to string */
3815 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3816 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3817 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3818 int tmp_genre_len = 0;
3820 memset(tmp_genre, 0, 6);
3821 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3823 tmp_genre_len = strlen(tmp_genre);
3824 if (tmp_genre_len > 0) {
3825 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3826 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3827 if (pInfo->pGenre) {
3828 SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
3833 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
3838 pInfo->tagV2Info.bGenreMarked = true;
3839 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3840 if (textEncodingType == AV_ID3V2_UTF8) {
3841 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3842 if (pInfo->pTrackNum != NULL) {
3843 memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3844 pInfo->pTrackNum[realCpyFrameNum] = '\0';
3845 /*string copy with '\0'*/
3846 pInfo->tracknumLen = realCpyFrameNum;
3847 _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3850 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3853 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3854 pInfo->tagV2Info.bTrackNumMarked = true;
3855 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3856 if (textEncodingType == AV_ID3V2_UTF8) {
3857 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3858 if (pInfo->pEncBy != NULL) {
3859 memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3860 pInfo->pEncBy[realCpyFrameNum] = '\0';
3861 /*string copy with '\0'*/
3862 pInfo->encbyLen = realCpyFrameNum;
3863 _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3866 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3869 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3870 pInfo->tagV2Info.bEncByMarked = true;
3871 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3872 if (textEncodingType == AV_ID3V2_UTF8) {
3873 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3874 if (pInfo->pURL != NULL) {
3875 memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3876 pInfo->pURL[realCpyFrameNum] = '\0';
3877 /*string copy with '\0'*/
3878 pInfo->urlLen = realCpyFrameNum;
3879 _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3882 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3885 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3886 pInfo->tagV2Info.bURLMarked = true;
3887 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3888 if (textEncodingType == AV_ID3V2_UTF8) {
3889 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3890 if (pInfo->pCopyright != NULL) {
3891 memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3892 pInfo->pCopyright[realCpyFrameNum] = '\0';
3893 /*string copy with '\0'*/
3894 pInfo->copyrightLen = realCpyFrameNum;
3895 _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3898 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3901 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3902 pInfo->tagV2Info.bCopyRightMarked = true;
3903 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3904 if (textEncodingType == AV_ID3V2_UTF8) {
3905 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3906 if (pInfo->pOriginArtist != NULL) {
3907 memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3908 pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3909 /*string copy with '\0'*/
3910 pInfo->originartistLen = realCpyFrameNum;
3911 _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3914 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3917 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3918 pInfo->tagV2Info.bOriginArtistMarked = true;
3919 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3920 if (textEncodingType == AV_ID3V2_UTF8) {
3921 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3922 if (pInfo->pComposer != NULL) {
3923 memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3924 pInfo->pComposer[realCpyFrameNum] = '\0';
3925 /*string copy with '\0'*/
3926 pInfo->composerLen = realCpyFrameNum;
3927 _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3930 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3933 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3934 pInfo->tagV2Info.bComposerMarked = true;
3935 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) { /*TYER(year) and TRDA are replaced by the TDRC */
3936 if (textEncodingType == AV_ID3V2_UTF8) {
3937 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3938 if (pInfo->pRecDate != NULL) {
3939 memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3940 pInfo->pRecDate[realCpyFrameNum] = '\0';
3941 /*string copy with '\0'*/
3942 pInfo->recdateLen = realCpyFrameNum;
3943 _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3946 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3949 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3950 pInfo->tagV2Info.bRecDateMarked = true;
3951 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3952 if (textEncodingType == AV_ID3V2_UTF8) {
3953 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3954 if (pInfo->pContentGroup != NULL) {
3955 memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3956 pInfo->pContentGroup[realCpyFrameNum] = '\0';
3957 /*string copy with '\0'*/
3958 pInfo->contentGroupLen = realCpyFrameNum;
3959 _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3962 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3965 debug_msg(RELEASE, "pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3966 pInfo->tagV2Info.bContentGroupMarked = true;
3967 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3968 if (pExtContent[0] != '\0') {
3969 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3970 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3972 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3973 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3974 checkImgMimeTypeMax++;
3976 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3978 pInfo->imageInfo.imgMimetypeLen = 0;
3981 imgstartOffset += checkImgMimeTypeMax;
3983 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3984 pInfo->imageInfo.imgMimetypeLen = 0;
3985 debug_error(DEBUG, "APIC NOT VALID");
3989 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3990 imgstartOffset++;/*endofMIME(1byte) */
3992 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3993 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3995 imgstartOffset++;/*PictureType(1byte) */
3997 if (pExtContent[imgstartOffset] != 0x0) {
4000 int new_dis_len = 0;
4001 char *tmp_desc = NULL;
4004 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
4005 if (realCpyFrameNum < imgstartOffset + cur_pos) {
4006 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
4009 /*check end of image description*/
4010 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
4011 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
4012 debug_msg(RELEASE, "length of description (%d)", cur_pos);
4019 dis_len = cur_pos + 1;
4021 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
4023 if (tmp_desc != NULL) {
4024 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
4025 debug_msg(DEBUG, "tmp_desc %s\n", tmp_desc);
4027 /*convert description*/
4028 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
4029 debug_msg(DEBUG, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
4030 mmfile_free(tmp_desc);
4032 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
4035 imgstartOffset += cur_pos;
4037 pInfo->imageInfo.imgDesLen = 0;
4040 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
4041 imgstartOffset++; /* endofDesceriptionType(1byte) */
4043 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
4047 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
4049 if (realCpyFrameNum - imgstartOffset > 0) {
4050 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
4051 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
4053 if (pInfo->imageInfo.pImageBuf != NULL) {
4054 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
4055 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
4058 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
4059 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
4061 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
4066 checkImgMimeTypeMax = 0;
4069 pInfo->tagV2Info.bImageMarked = true;
4071 debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
4076 debug_msg(RELEASE, "mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
4080 curPos += purelyFramelen;
4081 if (purelyFramelen != 0)
4082 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
4085 if (pExtContent) _FREE_EX(pExtContent);
4086 memset(CompTmp, 0, 4);
4087 if (curPos < taglen) {
4088 needToloopv2taglen -= oneFrameLen;
4091 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
4095 realCpyFrameNum = 0;
4096 textEncodingType = 0;
4102 release_characterset_array(charset_array);
4112 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
4114 char *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
4115 bool bAdditionGenre = false /*, bMpegAudioFrame = false*/;
4116 int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
4117 unsigned char genre = pInfo->genre;
4119 /* for Genre Info */
4120 if (pInfo->tagV2Info.bGenreMarked == false) {
4121 if (pInfo->bV1tagFound == true) {
4122 debug_msg(RELEASE, "Genre: %d\n", genre);
4127 if (MpegAudio_Genre[genre] != NULL) {
4128 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
4129 if (pInfo->genreLen > 0) {
4130 /* Give space for NULL character. Hence added "+1" */
4131 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4132 if (pInfo->pGenre) {
4133 SAFE_STRLCPY(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen + 1);
4138 debug_msg(RELEASE, "Genre was not Found.\n");
4140 } else if (pInfo->tagV2Info.bGenreMarked == true) {
4141 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
4142 pInfo->pGenre[pInfo->genreLen + 1] = '\0';
4143 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
4145 debug_msg(RELEASE, "pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
4147 if (pInfo->pGenre) {
4148 pInfo->genreLen = strlen(pInfo->pGenre);
4149 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4150 if (mpegAudioGenre != NULL) {
4151 SAFE_STRLCPY(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen + 1);
4154 pInfo->genreLen = 0;
4158 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
4161 if (mpegAudioGenre != NULL) {
4164 * (XXX) XXX is 0 - 148
4166 pInfo->genreLen = strlen(mpegAudioGenre);
4167 if (pInfo->genreLen >= 3 &&
4168 mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
4169 bAdditionGenre = true;
4170 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
4171 if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
4172 bAdditionGenre = false;
4178 if (bAdditionGenre == true) {
4179 idv2IntGenre = atoi(mpegAudioGenre + 1);
4181 if (idv2IntGenre > 147 || idv2IntGenre < 0)
4184 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
4185 pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
4186 if (pInfo->genreLen > 0) {
4187 /* Give space for NULL character. Hence added "+1" */
4188 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4189 if (pInfo->pGenre) {
4190 SAFE_STRLCPY(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen + 1);
4194 debug_msg(RELEASE, "pInfo->pGenre = %s\n", pInfo->pGenre);
4195 } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
4200 /* Give space for NULL character. Hence added "+1" */
4201 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4202 if (pInfo->pGenre) {
4203 SAFE_STRLCPY(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen + 1);
4205 debug_msg(RELEASE, "pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
4207 debug_msg(RELEASE, "Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
4210 debug_msg(RELEASE, "mpegAudioGenre = %s\n", mpegAudioGenre);
4213 _FREE_EX(mpegAudioGenre);
4216 debug_msg(RELEASE, "Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
4221 void mm_file_free_synclyrics_list(GList *synclyrics_list)
4225 AvSynclyricsInfo *synclyrics_info = NULL;
4227 if (synclyrics_list == NULL) {
4231 list_len = g_list_length(synclyrics_list);
4232 for (idx = 0; idx < list_len; idx++) {
4233 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
4235 if (synclyrics_info != NULL) {
4236 mmfile_free(synclyrics_info->lyric_info);
4237 mmfile_free(synclyrics_info);
4241 if (synclyrics_list != NULL) {
4242 g_list_free(synclyrics_list);
4243 synclyrics_list = NULL;