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 long long new_pos = mmfile_tell(fp);
2153 if ((moov_end == 0) && (new_pos <= basic_header.start_offset)) {
2154 ret = MMFILE_UTIL_FAIL;
2157 basic_header.start_offset = new_pos;
2166 static char *get_string(const char *buf, int buf_size, int *bytes_written)
2170 char str[512] = {0, };
2173 for (i = 0; i < buf_size; i++) {
2177 if ((q - str) >= (int)sizeof(str) - 1)
2183 if (strlen(str) > 0) {
2184 *bytes_written = strlen(str);
2192 static bool is_numeric(const char *buf, int buf_size)
2197 for (idx = 0; idx < buf_size; idx++) {
2198 if (isdigit((int)buf[idx])) {
2209 char *rtrimN(char *pStr)
2212 pos = strlen(pStr) - 1;
2213 for (; pos >= 0; pos--) {
2214 if (pStr[pos] == 0x20) {
2221 return strdup(pStr);
2224 bool safe_atoi(char *buffer, int *si)
2230 const long sl = strtol(buffer, &end, 10);
2232 if (end == buffer) {
2233 debug_error(RELEASE, "not a decimal number");
2235 } else if ('\0' != *end) {
2236 debug_error(RELEASE, "extra characters at end of input: %s", end);
2238 } else if ((LONG_MIN == sl || LONG_MAX == sl) && (ERANGE == errno)) {
2239 debug_error(RELEASE, "out of range of type long");
2241 } else if (sl > INT_MAX) {
2242 debug_error(RELEASE, "greater than INT_MAX");
2244 } else if (sl < INT_MIN) {
2245 debug_error(RELEASE, "less than INT_MIN");
2253 static bool make_characterset_array(char ***charset_array)
2255 char *locale = MMFileUtilGetLocale(NULL);
2257 *charset_array = calloc(AV_ID3V2_MAX, sizeof(char *));
2259 if (*charset_array == NULL) {
2260 debug_error(DEBUG, "calloc failed ");
2266 if (locale != NULL) {
2267 (*charset_array)[AV_ID3V2_ISO_8859] = strdup(locale);
2269 debug_error(DEBUG, "get locale failed");
2270 (*charset_array)[AV_ID3V2_ISO_8859] = NULL;
2273 (*charset_array)[AV_ID3V2_UTF16] = strdup("UCS2");
2274 (*charset_array)[AV_ID3V2_UTF16_BE] = strdup("UTF16-BE");
2275 (*charset_array)[AV_ID3V2_UTF8] = strdup("UTF-8");
2280 static bool release_characterset_array(char **charset_array)
2284 for (i = 0; i < AV_ID3V2_MAX; i++) {
2285 if (charset_array[i] != NULL) {
2286 free(charset_array[i]);
2287 charset_array[i] = NULL;
2291 if (charset_array != NULL) {
2292 free(charset_array);
2293 charset_array = NULL;
2299 static void init_content_info(AvFileContentInfo *pInfo)
2301 pInfo->tagV2Info.bTitleMarked = false;
2302 pInfo->tagV2Info.bArtistMarked = false;
2303 pInfo->tagV2Info.bAlbumMarked = false;
2304 pInfo->tagV2Info.bAlbum_ArtistMarked = false;
2305 pInfo->tagV2Info.bYearMarked = false;
2306 pInfo->tagV2Info.bDescriptionMarked = false;
2307 pInfo->tagV2Info.bGenreMarked = false;
2308 pInfo->tagV2Info.bTrackNumMarked = false;
2309 pInfo->tagV2Info.bEncByMarked = false;
2310 pInfo->tagV2Info.bURLMarked = false;
2311 pInfo->tagV2Info.bCopyRightMarked = false;
2312 pInfo->tagV2Info.bOriginArtistMarked = false;
2313 pInfo->tagV2Info.bComposerMarked = false;
2314 pInfo->tagV2Info.bImageMarked = false;
2316 pInfo->tagV2Info.bRecDateMarked = false;
2317 pInfo->tagV2Info.bContentGroupMarked = false;
2319 pInfo->tagV2Info.bUnsyncLyricsMarked = false;
2320 pInfo->tagV2Info.bSyncLyricsMarked = false;
2321 pInfo->tagV2Info.bConductorMarked = false;
2322 pInfo->tagV2Info.bGenreUTF16 = false;
2324 pInfo->imageInfo.bURLInfo = false;
2325 pInfo->imageInfo.pImageBuf = NULL;
2326 pInfo->imageInfo.imageLen = 0;
2330 bool mm_file_id3tag_parse_v110(AvFileContentInfo *pInfo, unsigned char *buffer)
2332 const char *locale = MMFileUtilGetLocale(NULL);
2333 char *pFullStr = NULL;
2335 debug_msg(RELEASE, "ID3tag v110--------------------------------------------------------------\n");
2337 if (pInfo->tagV2Info.bTitleMarked == false) {
2338 pFullStr = mmfile_string_convert((const char *)&buffer[3], MP3_ID3_TITLE_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->titleLen);
2339 if (pFullStr != NULL) {
2340 pInfo->pTitle = rtrimN(pFullStr);
2344 debug_msg(RELEASE, "pInfo->pTitle returned =(%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2347 if (pInfo->tagV2Info.bArtistMarked == false) {
2348 pFullStr = mmfile_string_convert((const char *)&buffer[33], MP3_ID3_ARTIST_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->artistLen);
2349 if (pFullStr != NULL) {
2350 pInfo->pArtist = rtrimN(pFullStr);
2354 debug_msg(RELEASE, "pInfo->pArtist returned =(%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2357 if (pInfo->tagV2Info.bAlbumMarked == false) {
2358 pFullStr = mmfile_string_convert((const char *)&buffer[63], MP3_ID3_ALBUM_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->albumLen);
2359 if (pFullStr != NULL) {
2360 pInfo->pAlbum = rtrimN(pFullStr);
2364 debug_msg(RELEASE, "pInfo->pAlbum returned =(%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2367 if (pInfo->tagV2Info.bYearMarked == false) {
2369 pInfo->pYear = mmfile_string_convert((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->yearLen);
2371 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2373 if (pInfo->pYear == NULL) { /*Use same logic with ffmpeg*/
2374 pInfo->pYear = get_string((const char *)&buffer[93], MP3_ID3_YEAR_LENGTH, (int *)&pInfo->yearLen);
2375 debug_msg(RELEASE, "pInfo->pYear returned =(%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2379 if (pInfo->tagV2Info.bDescriptionMarked == false) {
2380 pInfo->pComment = mmfile_string_convert((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, "UTF-8", locale, NULL, (unsigned int *)&pInfo->commentLen);
2381 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2383 if (pInfo->pComment == NULL) { /*Use same logic with ffmpeg*/
2384 pInfo->pComment = get_string((const char *)&buffer[97], MP3_ID3_DESCRIPTION_LENGTH, (int *)&pInfo->commentLen);
2385 debug_msg(RELEASE, "pInfo->pComment returned =(%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2389 if (pInfo->tagV2Info.bTrackNumMarked == false) {
2390 pInfo->pTrackNum = mmfile_malloc(5);
2391 if (pInfo->pTrackNum != NULL) {
2392 pInfo->pTrackNum[4] = 0;
2393 snprintf(pInfo->pTrackNum, 4, "%04d", (int)buffer[126]);
2394 pInfo->tracknumLen = strlen(pInfo->pTrackNum);
2396 debug_msg(RELEASE, "pInfo->pTrackNum returned =(%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2400 if (pInfo->tagV2Info.bGenreMarked == false) {
2401 pInfo->genre = buffer[127];
2402 debug_msg(RELEASE, "pInfo->genre returned genre number (%d)\n", pInfo->genre);
2409 bool mm_file_id3tag_parse_v222(AvFileContentInfo *pInfo, unsigned char *buffer)
2411 unsigned long taglen = 0;
2412 unsigned long needToloopv2taglen;
2413 unsigned long oneFrameLen = 0;
2414 unsigned long v2numOfFrames = 0;
2415 unsigned long curPos = 0;
2417 unsigned char *pExtContent = NULL;
2418 unsigned long purelyFramelen = 0;
2419 unsigned int encodingOffSet = 0;
2420 int inx = 0, realCpyFrameNum = 0,
2421 /*checkImgMimeTypeMax = 0, */checkImgExtMax = 0,
2422 imgstartOffset = 0, tmp = 0;
2424 int textEncodingType = 0;
2426 char **charset_array = NULL;
2428 make_characterset_array(&charset_array);
2430 init_content_info(pInfo);
2432 taglen = pInfo->tagV2Info.tagLen;
2433 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2434 curPos = MP3_TAGv2_HEADER_LEN;
2436 debug_msg(RELEASE, "ID3tag v222--------------------------------------------------------------\n");
2438 if (needToloopv2taglen - MP3_TAGv2_22_TXT_HEADER_LEN > MP3_TAGv2_22_TXT_HEADER_LEN) {
2440 while (needToloopv2taglen > MP3_TAGv2_22_TXT_HEADER_LEN) {
2441 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2442 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z'))
2445 memcpy(CompTmp, &buffer[curPos], 3);
2448 oneFrameLen = MP3_TAGv2_22_TXT_HEADER_LEN;
2449 oneFrameLen += (unsigned long)buffer[3 + curPos] << 16 | (unsigned long)buffer[4 + curPos] << 8
2450 | (unsigned long)buffer[5 + curPos];
2451 if (oneFrameLen > taglen - curPos)
2453 purelyFramelen = oneFrameLen - MP3_TAGv2_22_TXT_HEADER_LEN;
2454 curPos += MP3_TAGv2_22_TXT_HEADER_LEN;
2456 if (oneFrameLen > MP3_TAGv2_22_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2457 curPos += purelyFramelen;
2459 if (buffer[curPos - purelyFramelen] == 0x00) {
2461 textEncodingType = AV_ID3V2_ISO_8859;
2462 } else if (buffer[curPos - purelyFramelen] == 0x01) {
2464 textEncodingType = AV_ID3V2_UTF16;
2467 /*in order to deliver valid string to MP */
2468 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
2471 if (encodingOffSet < purelyFramelen) {
2472 realCpyFrameNum = purelyFramelen - encodingOffSet;
2473 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2475 if (pExtContent == NULL) {
2476 debug_error(DEBUG, "out of memory for pExtContent\n");
2480 memset(pExtContent, '\0', realCpyFrameNum + 3);
2482 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2484 if (realCpyFrameNum > 0) {
2485 if (strncmp((char *)CompTmp, "TT2", 3) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2486 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2487 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2488 pInfo->tagV2Info.bTitleMarked = true;
2489 } else if (strncmp((char *)CompTmp, "TP1", 3) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2490 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2491 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2492 pInfo->tagV2Info.bArtistMarked = true;
2493 } else if (strncmp((char *)CompTmp, "TP2", 3) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2494 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2495 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2496 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2497 } else if (strncmp((char *)CompTmp, "TP3", 3) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2498 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2499 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2500 pInfo->tagV2Info.bConductorMarked = true;
2501 } else if (strncmp((char *)CompTmp, "TAL", 3) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2502 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2503 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2504 pInfo->tagV2Info.bAlbumMarked = true;
2505 } else if (strncmp((char *)CompTmp, "TYE", 3) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2506 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2507 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2508 pInfo->tagV2Info.bYearMarked = true;
2509 } else if (strncmp((char *)CompTmp, "COM", 3) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2510 /*skip language data! */
2511 if (realCpyFrameNum > 4) {
2512 realCpyFrameNum -= 4;
2515 /*pExtContent[tmp+1] value should't have encoding value */
2516 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
2517 if (pExtContent[tmp - 1] == 0x00)
2518 textEncodingType = AV_ID3V2_ISO_8859;
2520 textEncodingType = AV_ID3V2_UTF16;
2522 pInfo->pComment = mmfile_string_convert((char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2523 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2524 pInfo->tagV2Info.bDescriptionMarked = true;
2526 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2529 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2533 } else if (strncmp((char *)CompTmp, "TCO", 3) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
2534 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
2535 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
2537 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
2541 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
2544 ret = safe_atoi(pInfo->pGenre, &int_genre);
2546 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
2548 /*Change int to string */
2549 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
2550 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
2551 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
2552 int tmp_genre_len = 0;
2554 memset(tmp_genre, 0, 6);
2555 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
2557 tmp_genre_len = strlen(tmp_genre);
2558 if (tmp_genre_len > 0) {
2559 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
2560 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
2561 if (pInfo->pGenre) {
2562 SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
2567 debug_error(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
2572 pInfo->tagV2Info.bGenreMarked = true;
2573 } else if (strncmp((char *)CompTmp, "TRK", 3) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
2574 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
2575 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
2576 pInfo->tagV2Info.bTrackNumMarked = true;
2577 } else if (strncmp((char *)CompTmp, "TEN", 3) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
2578 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
2579 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
2580 pInfo->tagV2Info.bEncByMarked = true;
2581 } else if (strncmp((char *)CompTmp, "WXX", 3) == 0 && pInfo->tagV2Info.bURLMarked == false) {
2582 if (realCpyFrameNum > 4) {
2583 /*skip language data! */
2584 realCpyFrameNum -= 4;
2587 /*pExtContent[tmp+1] value should't have null value */
2588 if (pExtContent[tmp] > 0x20 && (pExtContent[tmp - 1] == 0x00 || pExtContent[tmp - 1] == 0x01)) {
2589 if (pExtContent[tmp - 1] == 0x00)
2590 textEncodingType = AV_ID3V2_ISO_8859;
2592 textEncodingType = AV_ID3V2_UTF16;
2594 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
2595 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
2596 pInfo->tagV2Info.bURLMarked = true;
2598 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: failed to get URL Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2601 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: URL info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2604 } else if (strncmp((char *)CompTmp, "TCR", 3) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
2605 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
2606 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
2607 pInfo->tagV2Info.bCopyRightMarked = true;
2608 } else if (strncmp((char *)CompTmp, "TOA", 3) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
2609 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
2610 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
2611 pInfo->tagV2Info.bOriginArtistMarked = true;
2612 } else if (strncmp((char *)CompTmp, "TCM", 3) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
2613 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
2614 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
2615 pInfo->tagV2Info.bComposerMarked = true;
2616 } else if (strncmp((char *)CompTmp, "TRD", 3) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
2617 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
2618 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
2619 pInfo->tagV2Info.bRecDateMarked = true;
2620 } else if (strncmp((char *)CompTmp, "PIC", 3) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
2621 if (pExtContent[0] != 0) {
2622 for (inx = 0; inx < MP3_ID3_IMAGE_EXT_MAX_LENGTH; inx++)
2623 pInfo->imageInfo.imageExt[inx] = '\0';/*ini mimetype variable */
2625 while ((checkImgExtMax < MP3_ID3_IMAGE_EXT_MAX_LENGTH - 1) && pExtContent[checkImgExtMax] != '\0') {
2626 pInfo->imageInfo.imageExt[checkImgExtMax] = pExtContent[checkImgExtMax];
2630 debug_msg(RELEASE, "mmf_file_id3tag_parse_v222: PIC image's not included to image Extention\n");
2633 imgstartOffset += checkImgExtMax;
2635 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
2636 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
2638 imgstartOffset++;/*PictureType(1byte) */
2640 if (pExtContent[imgstartOffset] != 0x0) {
2643 int new_dis_len = 0;
2644 char *tmp_desc = NULL;
2647 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
2648 if (realCpyFrameNum < imgstartOffset + cur_pos) {
2649 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
2652 /*check end of image description*/
2653 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
2654 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
2655 debug_msg(RELEASE, "length of description (%d)", cur_pos);
2662 dis_len = cur_pos + 1;
2664 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
2666 if (tmp_desc != NULL) {
2667 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
2669 /*convert description*/
2670 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
2671 mmfile_free(tmp_desc);
2672 debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
2673 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
2676 imgstartOffset += cur_pos;
2678 pInfo->imageInfo.imgDesLen = 0;
2681 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
2682 imgstartOffset++; /* endofDesceriptionType(1byte) */
2684 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
2688 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
2690 if (realCpyFrameNum - imgstartOffset > 0) {
2691 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
2692 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
2694 if (pInfo->imageInfo.pImageBuf != NULL) {
2695 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
2696 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
2699 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
2700 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
2702 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
2706 /*checkImgMimeTypeMax = 0;*/
2710 pInfo->tagV2Info.bImageMarked = true;
2717 curPos += purelyFramelen;
2718 if (purelyFramelen != 0)
2719 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2722 if (pExtContent) _FREE_EX(pExtContent);
2723 memset(CompTmp, 0, 4);
2724 if (curPos < taglen) {
2725 needToloopv2taglen -= oneFrameLen;
2728 needToloopv2taglen = MP3_TAGv2_22_TXT_HEADER_LEN;
2731 realCpyFrameNum = 0;
2732 textEncodingType = 0;
2738 release_characterset_array(charset_array);
2748 bool mm_file_id3tag_parse_v223(AvFileContentInfo *pInfo, unsigned char *buffer)
2750 unsigned long taglen = 0;
2751 unsigned long needToloopv2taglen;
2752 unsigned long oneFrameLen = 0;
2753 unsigned long v2numOfFrames = 0;
2754 unsigned long curPos = 0;
2756 unsigned char *pExtContent = NULL;
2757 unsigned long purelyFramelen = 0;
2758 unsigned int encodingOffSet = 0;
2759 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
2760 unsigned int textEncodingType = 0;
2761 char **charset_array = NULL;
2762 const char *MIME_PRFIX = "image/";
2764 make_characterset_array(&charset_array);
2766 init_content_info(pInfo);
2768 taglen = pInfo->tagV2Info.tagLen;
2769 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
2770 curPos = MP3_TAGv2_HEADER_LEN;
2772 debug_msg(RELEASE, "ID3tag v223--------------------------------------------------------------\n");
2774 /* check Extended Header */
2775 if (buffer[5] & 0x40) {
2776 /* if extended header exists, skip it*/
2777 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
2779 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
2781 if (extendedHeaderLen > (int)(taglen - curPos)) {
2782 debug_error(DEBUG, "extended header too long.\n");
2784 curPos += extendedHeaderLen;
2789 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
2791 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
2792 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
2793 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
2796 memcpy(CompTmp, &buffer[curPos], 4);
2799 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
2800 oneFrameLen += (unsigned long)buffer[4 + curPos] << 24 | (unsigned long)buffer[5 + curPos] << 16
2801 | (unsigned long)buffer[6 + curPos] << 8 | (unsigned long)buffer[7 + curPos];
2803 debug_msg(RELEASE, "----------------------------------------------------------------------------------------------------\n");
2805 if (oneFrameLen > taglen - curPos)
2808 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
2809 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
2811 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
2812 curPos += purelyFramelen;
2814 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
2816 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2817 textEncodingType = AV_ID3V2_UTF16;
2818 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
2820 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2821 textEncodingType = AV_ID3V2_UTF16_BE;
2822 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
2824 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2825 textEncodingType = AV_ID3V2_UTF16;
2826 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
2828 debug_msg(RELEASE, "this text string(%s) encoded by UTF16 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2829 textEncodingType = AV_ID3V2_UTF16_BE;
2831 if (buffer[curPos - purelyFramelen + encodingOffSet] == 0x00) {
2832 debug_msg(RELEASE, "encodingOffset will be set to 1\n");
2835 debug_msg(RELEASE, "Finding encodingOffset\n");
2837 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen)) /* text string encoded by ISO-8859-1 */
2840 textEncodingType = AV_ID3V2_ISO_8859;
2841 debug_msg(RELEASE, "this text string(%s) encoded by ISO-8859-1 encodingOffSet(%d)\n", CompTmp, encodingOffSet);
2844 if (pExtContent) _FREE_EX(pExtContent);
2846 if (encodingOffSet < purelyFramelen) {
2847 realCpyFrameNum = purelyFramelen - encodingOffSet;
2848 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
2850 if (pExtContent == NULL) {
2851 debug_msg(DEBUG, "pExtContent malloc failed\n");
2855 memset(pExtContent, '\0', realCpyFrameNum + 3);
2857 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
2858 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
2859 debug_msg(RELEASE, "get the new text ecoding type\n");
2860 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
2864 if (textEncodingType > AV_ID3V2_MAX) {
2865 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
2869 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
2870 if (realCpyFrameNum > 0) {
2871 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
2872 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
2873 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
2874 pInfo->tagV2Info.bTitleMarked = true;
2876 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
2877 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
2878 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
2879 pInfo->tagV2Info.bArtistMarked = true;
2880 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
2881 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
2882 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
2883 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
2884 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
2885 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
2886 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
2887 pInfo->tagV2Info.bConductorMarked = true;
2888 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
2889 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
2890 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
2891 pInfo->tagV2Info.bAlbumMarked = true;
2892 } else if (strncmp((char *)CompTmp, "TYER", 4) == 0 && pInfo->tagV2Info.bYearMarked == false) {
2893 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
2894 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
2895 pInfo->tagV2Info.bYearMarked = true;
2896 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
2897 if (realCpyFrameNum > 3) {
2898 realCpyFrameNum -= 3;
2901 /*pExtContent[tmp+1] value should't have encoding value */
2902 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2903 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2904 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2905 realCpyFrameNum -= 4;
2909 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2910 realCpyFrameNum -= 2;
2912 textEncodingType = AV_ID3V2_UTF16;
2913 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2914 realCpyFrameNum -= 2;
2916 textEncodingType = AV_ID3V2_UTF16_BE;
2917 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2918 realCpyFrameNum -= 3;
2920 textEncodingType = AV_ID3V2_UTF16;
2921 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2922 realCpyFrameNum -= 3;
2924 textEncodingType = AV_ID3V2_UTF16_BE;
2926 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
2929 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2933 textEncodingType = AV_ID3V2_ISO_8859;
2936 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2937 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
2939 debug_msg(RELEASE, "failed to get Comment Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
2940 pInfo->commentLen = 0;
2943 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
2944 pInfo->commentLen = 0;
2948 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
2949 pInfo->tagV2Info.bDescriptionMarked = true;
2950 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
2953 int copy_start_pos = tmp;
2954 AvSynclyricsInfo *synclyrics_info = NULL;
2955 GList *synclyrics_info_list = NULL;
2957 if (realCpyFrameNum > 5) {
2958 realCpyFrameNum -= 5;
2961 /*pExtContent[tmp+1] value should't have encoding value */
2962 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
2963 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
2964 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
2965 realCpyFrameNum -= 4;
2969 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2970 realCpyFrameNum -= 2;
2972 textEncodingType = AV_ID3V2_UTF16;
2973 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
2974 realCpyFrameNum -= 2;
2976 textEncodingType = AV_ID3V2_UTF16_BE;
2977 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2978 realCpyFrameNum -= 3;
2980 textEncodingType = AV_ID3V2_UTF16;
2981 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
2982 realCpyFrameNum -= 3;
2984 textEncodingType = AV_ID3V2_UTF16_BE;
2986 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
2989 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
2993 textEncodingType = AV_ID3V2_ISO_8859;
2996 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
2998 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
2999 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3000 pInfo->syncLyricsNum = 0;
3002 if (textEncodingType == AV_ID3V2_UTF16) {
3003 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3004 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3005 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3007 for (idx = 0; idx < realCpyFrameNum; idx++) {
3008 if (pExtContent[tmp + idx] == 0x00) {
3009 synclyrics_info = (AvSynclyricsInfo *)malloc(sizeof(AvSynclyricsInfo));
3011 if (synclyrics_info != NULL) {
3012 if (textEncodingType == AV_ID3V2_UTF8) {
3013 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3014 if (synclyrics_info->lyric_info != NULL) {
3015 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3016 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3017 synclyrics_info->lyric_info[copy_len] = '\0';
3020 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);
3023 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];
3025 copy_start_pos = tmp + idx + 1;
3026 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);
3028 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3033 pInfo->pSyncLyrics = synclyrics_info_list;
3034 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3038 debug_msg(RELEASE, "failed to get Synchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3039 pInfo->syncLyricsNum = 0;
3042 debug_msg(RELEASE, "Synchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3043 pInfo->syncLyricsNum = 0;
3047 //debug_msg(RELEASE, "pInfo->pSyncLyrics returned = (%s), pInfo->syncLyricsNum(%d)\n", pInfo->pSyncLyrics, pInfo->syncLyricsNum);
3048 debug_msg(RELEASE, "pInfo->syncLyricsNum(%d)\n", pInfo->syncLyricsNum);
3049 pInfo->tagV2Info.bSyncLyricsMarked = true;
3050 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3051 char *lang_info = strndup((char *)pExtContent, 3);
3053 if (realCpyFrameNum > 3) {
3054 realCpyFrameNum -= 3;
3057 /*find start of lyrics */
3059 if (pExtContent[tmp] == 0x00) {
3060 if (pExtContent[tmp + 1] == 0x00) {
3061 realCpyFrameNum -= 2;
3071 /*pExtContent[tmp+1] value should't have encoding value */
3072 debug_msg(RELEASE, "tpExtContent[%d] %x\n", tmp, pExtContent[tmp]);
3074 if (pExtContent[tmp] == 0x00 || pExtContent[tmp] == 0xFF || pExtContent[tmp] == 0xFE) {
3075 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3076 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3077 realCpyFrameNum -= 4;
3081 if (IS_ENCODEDBY_UTF16(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3082 realCpyFrameNum -= 2;
3084 textEncodingType = AV_ID3V2_UTF16;
3085 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp) && (realCpyFrameNum > 2)) {
3086 realCpyFrameNum -= 2;
3088 textEncodingType = AV_ID3V2_UTF16_BE;
3089 } else if (IS_ENCODEDBY_UTF16(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
3090 realCpyFrameNum -= 3;
3092 textEncodingType = AV_ID3V2_UTF16;
3093 } else if (IS_ENCODEDBY_UTF16_R(pExtContent + tmp + 1) && (realCpyFrameNum > 3)) {
3094 realCpyFrameNum -= 3;
3096 textEncodingType = AV_ID3V2_UTF16_BE;
3098 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3101 while ((pExtContent[tmp] < 0x20) && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3105 textEncodingType = AV_ID3V2_ISO_8859;
3108 char *char_set = NULL;
3110 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3112 if (textEncodingType == AV_ID3V2_ISO_8859) {
3113 if (lang_info != NULL && !strcasecmp(lang_info, "KOR")) {
3114 char_set = strdup("EUC-KR");
3116 char_set = mmfile_get_charset((const char *)&pExtContent[tmp]);
3118 _FREE_EX(lang_info);
3121 if (char_set == NULL) {
3122 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3124 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", char_set, NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3128 debug_msg(RELEASE, "failed to get Unsynchronised lyrics Info tmp(%d), purelyFramelen - encodingOffSet(%lu)\n", tmp, purelyFramelen - encodingOffSet);
3129 pInfo->unsynclyricsLen = 0;
3132 debug_msg(RELEASE, "Unsynchronised lyrics too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3133 pInfo->unsynclyricsLen = 0;
3137 debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3138 pInfo->tagV2Info.bUnsyncLyricsMarked = true;
3139 mmfile_free(lang_info);
3140 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3141 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3142 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3144 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3148 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3151 ret = safe_atoi(pInfo->pGenre, &int_genre);
3153 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
3155 /*Change int to string */
3156 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3157 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3158 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3159 int tmp_genre_len = 0;
3161 memset(tmp_genre, 0, 6);
3162 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3164 tmp_genre_len = strlen(tmp_genre);
3165 if (tmp_genre_len > 0) {
3166 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3167 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3168 if (pInfo->pGenre) {
3169 SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
3174 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
3179 pInfo->tagV2Info.bGenreMarked = true;
3180 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3181 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3182 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3183 pInfo->tagV2Info.bTrackNumMarked = true;
3184 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3185 pInfo->pEncBy = mmfile_string_convert((char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3186 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3187 pInfo->tagV2Info.bEncByMarked = true;
3188 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3189 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3190 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3191 pInfo->tagV2Info.bURLMarked = true;
3192 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3193 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3194 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3195 pInfo->tagV2Info.bCopyRightMarked = true;
3196 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3197 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3198 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3199 pInfo->tagV2Info.bOriginArtistMarked = true;
3200 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3201 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3202 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->composerLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3203 pInfo->tagV2Info.bComposerMarked = true;
3204 } else if (strncmp((char *)CompTmp, "TRDA", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) {
3205 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3206 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3207 pInfo->tagV2Info.bRecDateMarked = true;
3208 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3209 debug_msg(DEBUG, "text encoding %d \n", textEncodingType);
3211 if (pExtContent[0] != '\0') {
3212 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3213 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3215 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3216 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3217 checkImgMimeTypeMax++;
3219 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3221 pInfo->imageInfo.imgMimetypeLen = 0;
3222 debug_msg(RELEASE, "APIC image's not included to MIME type\n");
3225 imgstartOffset += checkImgMimeTypeMax;
3227 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3228 pInfo->imageInfo.imgMimetypeLen = 0;
3229 debug_error(DEBUG, "APIC NOT VALID");
3233 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3234 imgstartOffset++;/*endofMIME(1byte) */
3235 debug_msg(RELEASE, "after scaning Mime type imgstartOffset(%d) value!\n", imgstartOffset);
3237 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
3238 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
3240 debug_msg(RELEASE, "APIC image has invalid picture type(0x%x)\n", pExtContent[imgstartOffset]);
3242 imgstartOffset++;/*PictureType(1byte) */
3243 debug_msg(RELEASE, "after scaning PictureType imgstartOffset(%d) value!\n", imgstartOffset);
3245 if (pExtContent[imgstartOffset] != 0x0) {
3248 int new_dis_len = 0;
3249 char *tmp_desc = NULL;
3252 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
3253 if (realCpyFrameNum < imgstartOffset + cur_pos) {
3254 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
3257 /*check end of image description*/
3258 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
3259 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
3260 debug_msg(RELEASE, "length of description (%d)", cur_pos);
3267 dis_len = cur_pos + 1;
3269 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
3270 if (tmp_desc != NULL) {
3271 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
3273 /*convert description*/
3274 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
3275 debug_msg(RELEASE, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
3276 mmfile_free(tmp_desc);
3278 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
3281 imgstartOffset += cur_pos;
3283 pInfo->imageInfo.imgDesLen = 0;
3284 debug_msg(RELEASE, "APIC image's not included to Description!!!\n");
3287 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3288 imgstartOffset++; /* endofDesceriptionType(1byte) */
3290 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
3294 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
3296 if (realCpyFrameNum - imgstartOffset > 0) {
3297 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
3298 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
3300 if (pInfo->imageInfo.pImageBuf != NULL) {
3301 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
3302 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
3305 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
3306 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
3308 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
3310 debug_msg(RELEASE, "pInfo->imageInfo.imageLen(%d), imgstartOffset(%d)!\n", pInfo->imageInfo.imageLen, imgstartOffset);
3312 debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of description! realCpyFrameNum - imgstartOffset(%d)\n",
3313 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
3316 debug_msg(RELEASE, "pExtContent[imgstartOffset](%d) value should setted NULL value for end of mimetype! realCpyFrameNum - imgstartOffset(%d)\n",
3317 pExtContent[imgstartOffset], realCpyFrameNum - imgstartOffset);
3320 checkImgMimeTypeMax = 0;
3323 pInfo->tagV2Info.bImageMarked = true;
3326 debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
3331 debug_msg(RELEASE, "All of the pExtContent Values are NULL\n");
3334 curPos += purelyFramelen;
3335 if (purelyFramelen != 0)
3336 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3338 debug_msg(RELEASE, "This Frame's size is Zero! purelyFramelen(%lu)\n", purelyFramelen);
3341 if (pExtContent) _FREE_EX(pExtContent);
3342 memset(CompTmp, 0, 4);
3344 if (curPos < taglen) {
3345 needToloopv2taglen -= oneFrameLen;
3348 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
3351 realCpyFrameNum = 0;
3352 textEncodingType = 0;
3358 release_characterset_array(charset_array);
3368 bool mm_file_id3tag_parse_v224(AvFileContentInfo *pInfo, unsigned char *buffer)
3370 unsigned long taglen = 0;
3371 unsigned long needToloopv2taglen;
3372 unsigned long oneFrameLen = 0;
3373 unsigned long v2numOfFrames = 0;
3374 unsigned long curPos = 0;
3376 unsigned char *pExtContent = NULL;
3377 unsigned long purelyFramelen = 0;
3378 unsigned int encodingOffSet = 0;
3379 int inx = 0, realCpyFrameNum = 0, checkImgMimeTypeMax = 0, imgstartOffset = 0, tmp = 0;
3380 unsigned int textEncodingType = 0;
3381 char **charset_array = NULL;
3382 const char *MIME_PRFIX = "image/";
3384 make_characterset_array(&charset_array);
3386 init_content_info(pInfo);
3388 taglen = pInfo->tagV2Info.tagLen;
3389 needToloopv2taglen = taglen - MP3_TAGv2_HEADER_LEN;
3390 curPos = MP3_TAGv2_HEADER_LEN;
3392 debug_msg(RELEASE, "ID3tag v224--------------------------------------------------------------\n");
3394 /* check Extended Header */
3395 if (buffer[5] & 0x40) {
3396 /* if extended header exists, skip it*/
3397 int extendedHeaderLen = (unsigned long)buffer[10] << 21 | (unsigned long)buffer[11] << 14 | (unsigned long)buffer[12] << 7 | (unsigned long)buffer[13];
3399 debug_msg(RELEASE, "--------------- extendedHeaderLen = %d\n", extendedHeaderLen);
3401 if (extendedHeaderLen > (int)(taglen - curPos)) {
3402 debug_error(DEBUG, "extended header too long.\n");
3404 curPos += extendedHeaderLen;
3408 if (needToloopv2taglen - MP3_TAGv2_23_TXT_HEADER_LEN > MP3_TAGv2_23_TXT_HEADER_LEN) {
3410 while (needToloopv2taglen > MP3_TAGv2_23_TXT_HEADER_LEN) {
3411 if ((buffer[curPos] < '0' || buffer[curPos] > 'Z') || (buffer[curPos + 1] < '0' || buffer[curPos + 1] > 'Z')
3412 || (buffer[curPos + 2] < '0' || buffer[curPos + 2] > 'Z') || (buffer[curPos + 3] < '0' || buffer[curPos + 3] > 'Z'))
3415 memcpy(CompTmp, &buffer[curPos], 4);
3418 oneFrameLen = MP3_TAGv2_23_TXT_HEADER_LEN;
3419 oneFrameLen += (unsigned long)buffer[4 + curPos] << 21 | (unsigned long)buffer[5 + curPos] << 14
3420 | (unsigned long)buffer[6 + curPos] << 7 | (unsigned long)buffer[7 + curPos];
3421 if (oneFrameLen > taglen - curPos)
3424 purelyFramelen = oneFrameLen - MP3_TAGv2_23_TXT_HEADER_LEN;
3425 curPos += MP3_TAGv2_23_TXT_HEADER_LEN;
3427 debug_msg(RELEASE, "-----------------------------------------------------------------------------------\n");
3429 if (oneFrameLen > MP3_TAGv2_23_TXT_HEADER_LEN && purelyFramelen <= taglen - curPos) {
3430 curPos += purelyFramelen;
3432 /*in case of UTF 16 encoding */
3433 /*buffer+(curPos-purelyFramelen) data should '0x01' but in order to expansion, we don't accurately check the value. */
3434 if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen))) {
3436 textEncodingType = AV_ID3V2_UTF16;
3437 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen))) {
3439 textEncodingType = AV_ID3V2_UTF16_BE;
3440 } else if (IS_ENCODEDBY_UTF16(buffer + (curPos - purelyFramelen + 1))) {
3442 textEncodingType = AV_ID3V2_UTF16;
3443 } else if (IS_ENCODEDBY_UTF16_R(buffer + (curPos - purelyFramelen + 1))) {
3445 textEncodingType = AV_ID3V2_UTF16_BE;
3447 /*in case of UTF-16 BE encoding */
3448 if (buffer[curPos - purelyFramelen] == 0x02) {
3450 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
3451 encodingOffSet++;/*null skip! */
3452 textEncodingType = AV_ID3V2_UTF16_BE;
3454 /*in case of UTF8 encoding */
3455 else if (buffer[curPos - purelyFramelen] == 0x03) {
3457 while ((buffer[curPos - purelyFramelen + encodingOffSet] == '\0') && (encodingOffSet < purelyFramelen))
3458 encodingOffSet++;/*null skip! */
3459 textEncodingType = AV_ID3V2_UTF8;
3461 /*in case of ISO-8859-1 encoding */
3463 /*buffer+(curPos-purelyFramelen) data should 0x00 but in order to expansion, we don't accurately check the value. */
3465 while ((buffer[curPos - purelyFramelen + encodingOffSet] < 0x20) && (encodingOffSet < purelyFramelen))
3466 encodingOffSet++;/*less than 0x20 value skip! */
3467 textEncodingType = AV_ID3V2_ISO_8859;
3471 if (pExtContent) _FREE_EX(pExtContent);
3473 if (encodingOffSet < purelyFramelen) {
3474 realCpyFrameNum = purelyFramelen - encodingOffSet;
3475 pExtContent = mmfile_malloc(realCpyFrameNum + 3);
3477 if (pExtContent == NULL) {
3478 debug_error(DEBUG, "out of memoryu for id3tag parse\n");
3482 memset(pExtContent, '\0', realCpyFrameNum + 3);
3484 if (textEncodingType != AV_ID3V2_UTF16 && textEncodingType != AV_ID3V2_UTF16_BE) {
3485 if (CompTmp[0] == 'T' || (strcmp(CompTmp, "APIC") == 0)) {
3486 debug_msg(RELEASE, "get the new text ecoding type\n");
3487 textEncodingType = buffer[curPos - purelyFramelen + encodingOffSet - 1];
3491 if (textEncodingType > AV_ID3V2_MAX) {
3492 debug_msg(DEBUG, "WRONG ENCOIDNG TYPE [%d], FRAME[%s]\n", textEncodingType, (char *)CompTmp);
3496 memcpy(pExtContent, &buffer[curPos - purelyFramelen + encodingOffSet], purelyFramelen - encodingOffSet);
3498 if (realCpyFrameNum > 0) {
3499 if (strncmp((char *)CompTmp, "TIT2", 4) == 0 && pInfo->tagV2Info.bTitleMarked == false) {
3500 if (textEncodingType == AV_ID3V2_UTF8) {
3501 pInfo->pTitle = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3502 if (pInfo->pTitle) {
3503 memcpy(pInfo->pTitle, pExtContent, realCpyFrameNum);
3504 pInfo->pTitle[realCpyFrameNum] = '\0';
3505 /*string copy with '\0'*/
3506 pInfo->titleLen = realCpyFrameNum;
3507 _STRNCPY_EX(pInfo->pTitle, pExtContent, pInfo->titleLen);
3510 pInfo->pTitle = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->titleLen);
3513 debug_msg(RELEASE, "pInfo->pTitle returned = (%s), pInfo->titleLen(%d)\n", pInfo->pTitle, pInfo->titleLen);
3514 pInfo->tagV2Info.bTitleMarked = true;
3516 } else if (strncmp((char *)CompTmp, "TPE1", 4) == 0 && pInfo->tagV2Info.bArtistMarked == false) {
3517 if (textEncodingType == AV_ID3V2_UTF8) {
3518 pInfo->pArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3519 if (pInfo->pArtist) {
3520 memcpy(pInfo->pArtist, pExtContent, realCpyFrameNum);
3521 pInfo->pArtist[realCpyFrameNum] = '\0';
3522 /*string copy with '\0'*/
3523 pInfo->artistLen = realCpyFrameNum;
3524 _STRNCPY_EX(pInfo->pArtist, pExtContent, pInfo->artistLen);
3527 pInfo->pArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->artistLen);
3531 debug_msg(RELEASE, "pInfo->pArtist returned = (%s), pInfo->artistLen(%d)\n", pInfo->pArtist, pInfo->artistLen);
3532 pInfo->tagV2Info.bArtistMarked = true;
3533 } else if (strncmp((char *)CompTmp, "TPE2", 4) == 0 && pInfo->tagV2Info.bAlbum_ArtistMarked == false) {
3534 if (textEncodingType == AV_ID3V2_UTF8) {
3535 pInfo->pAlbum_Artist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3536 if (pInfo->pAlbum_Artist) {
3537 memcpy(pInfo->pAlbum_Artist, pExtContent, realCpyFrameNum);
3538 pInfo->pAlbum_Artist[realCpyFrameNum] = '\0';
3539 /*string copy with '\0'*/
3540 pInfo->album_artistLen = realCpyFrameNum;
3541 _STRNCPY_EX(pInfo->pAlbum_Artist, pExtContent, pInfo->album_artistLen);
3544 pInfo->pAlbum_Artist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->album_artistLen);
3547 debug_msg(RELEASE, "pInfo->pAlbum_Artist returned = (%s), pInfo->album_artistLen(%d)\n", pInfo->pAlbum_Artist, pInfo->album_artistLen);
3548 pInfo->tagV2Info.bAlbum_ArtistMarked = true;
3549 } else if (strncmp((char *)CompTmp, "TPE3", 4) == 0 && pInfo->tagV2Info.bConductorMarked == false) {
3550 if (textEncodingType == AV_ID3V2_UTF8) {
3551 pInfo->pConductor = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3552 if (pInfo->pConductor) {
3553 memcpy(pInfo->pConductor, pExtContent, realCpyFrameNum);
3554 pInfo->pConductor[realCpyFrameNum] = '\0';
3555 /*string copy with '\0'*/
3556 pInfo->conductorLen = realCpyFrameNum;
3557 _STRNCPY_EX(pInfo->pConductor, pExtContent, pInfo->conductorLen);
3560 pInfo->pConductor = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->conductorLen);
3563 debug_msg(RELEASE, "pInfo->pConductor returned = (%s), pInfo->conductorLen(%d)\n", pInfo->pConductor, pInfo->conductorLen);
3564 pInfo->tagV2Info.bConductorMarked = true;
3565 } else if (strncmp((char *)CompTmp, "TALB", 4) == 0 && pInfo->tagV2Info.bAlbumMarked == false) {
3566 if (textEncodingType == AV_ID3V2_UTF8) {
3567 pInfo->pAlbum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3568 if (pInfo->pAlbum) {
3569 memcpy(pInfo->pAlbum, pExtContent, realCpyFrameNum);
3570 pInfo->pAlbum[realCpyFrameNum] = '\0';
3571 /*string copy with '\0'*/
3572 pInfo->albumLen = realCpyFrameNum;
3573 _STRNCPY_EX(pInfo->pAlbum, pExtContent, pInfo->albumLen);
3576 pInfo->pAlbum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->albumLen);
3579 debug_msg(RELEASE, "pInfo->pAlbum returned = (%s), pInfo->albumLen(%d)\n", pInfo->pAlbum, pInfo->albumLen);
3580 pInfo->tagV2Info.bAlbumMarked = true;
3581 } 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 */
3582 if (textEncodingType == AV_ID3V2_UTF8) {
3583 pInfo->pYear = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3585 memcpy(pInfo->pYear, pExtContent, realCpyFrameNum);
3586 pInfo->pYear[realCpyFrameNum] = '\0';
3587 /*string copy with '\0'*/
3588 pInfo->yearLen = realCpyFrameNum;
3589 _STRNCPY_EX(pInfo->pYear, pExtContent, pInfo->yearLen);
3592 pInfo->pYear = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->yearLen);
3595 debug_msg(RELEASE, "pInfo->pYear returned = (%s), pInfo->yearLen(%d)\n", pInfo->pYear, pInfo->yearLen);
3596 pInfo->tagV2Info.bYearMarked = true;
3597 } else if (strncmp((char *)CompTmp, "COMM", 4) == 0 && pInfo->tagV2Info.bDescriptionMarked == false) {
3598 if (realCpyFrameNum > 3) {
3599 realCpyFrameNum -= 3;
3602 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3603 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3604 realCpyFrameNum -= 4;
3608 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3609 realCpyFrameNum -= 2;
3611 textEncodingType = AV_ID3V2_UTF16;
3613 debug_msg(RELEASE, "pInfo->pComment Never Get Here!!\n");
3615 } else if (textEncodingType == AV_ID3V2_UTF8) {
3616 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3620 textEncodingType = AV_ID3V2_UTF8;
3622 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3626 textEncodingType = AV_ID3V2_ISO_8859;
3629 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3631 if (textEncodingType == AV_ID3V2_UTF8) {
3632 pInfo->pComment = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3633 if (pInfo->pComment) {
3634 memset(pInfo->pComment, 0, (realCpyFrameNum + 2));
3635 memcpy(pInfo->pComment, pExtContent + tmp, realCpyFrameNum);
3636 pInfo->pComment[realCpyFrameNum] = '\0';
3637 /*string copy with '\0'*/
3638 pInfo->commentLen = realCpyFrameNum;
3639 _STRNCPY_EX(pInfo->pComment, pExtContent, pInfo->commentLen);
3642 pInfo->pComment = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->commentLen);
3645 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3650 debug_msg(RELEASE, "pInfo->pComment returned = (%s), pInfo->commentLen(%d)\n", pInfo->pComment, pInfo->commentLen);
3651 pInfo->tagV2Info.bDescriptionMarked = true;
3652 } else if (strncmp((char *)CompTmp, "SYLT", 4) == 0 && pInfo->tagV2Info.bSyncLyricsMarked == false) {
3655 int copy_start_pos = tmp;
3656 AvSynclyricsInfo *synclyrics_info = NULL;
3657 GList *synclyrics_info_list = NULL;
3659 if (realCpyFrameNum > 5) {
3660 realCpyFrameNum -= 5;
3663 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3664 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3665 realCpyFrameNum -= 4;
3669 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3670 realCpyFrameNum -= 2;
3672 textEncodingType = AV_ID3V2_UTF16;
3674 debug_msg(RELEASE, "pInfo->pSyncLyrics Never Get Here!!\n");
3676 } else if (textEncodingType == AV_ID3V2_UTF8) {
3677 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3681 textEncodingType = AV_ID3V2_UTF8;
3683 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3687 textEncodingType = AV_ID3V2_ISO_8859;
3690 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3692 if (realCpyFrameNum < MMFILE_SYNC_LYRIC_INFO_MIN_LEN) {
3693 debug_msg(RELEASE, "failed to get Synchronised lyrics Info realCpyFramNum(%d)\n", realCpyFrameNum);
3694 pInfo->syncLyricsNum = 0;
3696 if (textEncodingType == AV_ID3V2_UTF16) {
3697 debug_warning(DEBUG, "[AV_ID3V2_UTF16] not implemented\n");
3698 } else if (textEncodingType == AV_ID3V2_UTF16_BE) {
3699 debug_warning(DEBUG, "[AV_ID3V2_UTF16_BE] not implemented\n");
3701 for (idx = 0; idx < realCpyFrameNum; idx++) {
3702 if (pExtContent[tmp + idx] == 0x00) {
3703 synclyrics_info = (AvSynclyricsInfo *)mmfile_malloc(sizeof(AvSynclyricsInfo));
3704 if (synclyrics_info) {
3705 if (textEncodingType == AV_ID3V2_UTF8) {
3706 synclyrics_info->lyric_info = mmfile_malloc(copy_len + 1);
3707 if (synclyrics_info->lyric_info) {
3708 memset(synclyrics_info->lyric_info, 0, copy_len + 1);
3709 memcpy(synclyrics_info->lyric_info, pExtContent + copy_start_pos, copy_len);
3710 synclyrics_info->lyric_info[copy_len] = '\0';
3713 synclyrics_info->lyric_info = mmfile_string_convert((const char *)&pExtContent[copy_start_pos], copy_len, "UTF-8", charset_array[textEncodingType], NULL, NULL);
3716 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];
3718 copy_start_pos = tmp + idx + 1;
3719 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);
3721 synclyrics_info_list = g_list_append(synclyrics_info_list, synclyrics_info);
3726 pInfo->pSyncLyrics = synclyrics_info_list;
3727 pInfo->syncLyricsNum = g_list_length(pInfo->pSyncLyrics);
3731 debug_msg(RELEASE, "SyncLyrics info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3735 pInfo->tagV2Info.bSyncLyricsMarked = true;
3736 } else if (strncmp((char *)CompTmp, "USLT", 4) == 0 && pInfo->tagV2Info.bUnsyncLyricsMarked == false) {
3737 if (realCpyFrameNum > 3) {
3738 realCpyFrameNum -= 3;
3741 if (textEncodingType == AV_ID3V2_UTF16 || textEncodingType == AV_ID3V2_UTF16_BE) {
3742 while ((NEWLINE_OF_UTF16(pExtContent + tmp) || NEWLINE_OF_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 4) {
3743 realCpyFrameNum -= 4;
3747 if ((IS_ENCODEDBY_UTF16(pExtContent + tmp) || IS_ENCODEDBY_UTF16_R(pExtContent + tmp)) && realCpyFrameNum > 2) {
3748 realCpyFrameNum -= 2;
3750 textEncodingType = AV_ID3V2_UTF16;
3752 debug_msg(RELEASE, "pInfo->pUnsyncLyrics Never Get Here!!\n");
3754 } else if (textEncodingType == AV_ID3V2_UTF8) {
3755 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3759 textEncodingType = AV_ID3V2_UTF8;
3761 while (pExtContent[tmp] < 0x20 && (tmp < realCpyFrameNum)) { /* text string encoded by ISO-8859-1 */
3765 textEncodingType = AV_ID3V2_ISO_8859;
3768 debug_msg(RELEASE, "tmp(%d) textEncodingType(%d), realCpyFrameNum(%d)\n", tmp, textEncodingType, realCpyFrameNum);
3770 if (textEncodingType == AV_ID3V2_UTF8) {
3771 pInfo->pUnsyncLyrics = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3773 if (pInfo->pUnsyncLyrics != NULL) {
3774 memset(pInfo->pUnsyncLyrics, 0, (realCpyFrameNum + 2));
3775 memcpy(pInfo->pUnsyncLyrics, pExtContent + tmp, realCpyFrameNum);
3776 pInfo->pUnsyncLyrics[realCpyFrameNum] = '\0';
3777 /*string copy with '\0'*/
3778 pInfo->unsynclyricsLen = realCpyFrameNum;
3779 _STRNCPY_EX(pInfo->pUnsyncLyrics, pExtContent, pInfo->unsynclyricsLen);
3781 debug_error(DEBUG, "out of memoryu for SyncLyrics\n");
3784 pInfo->pUnsyncLyrics = mmfile_string_convert((const char *)&pExtContent[tmp], realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->unsynclyricsLen);
3787 debug_msg(RELEASE, "Description info too small to parse realCpyFrameNum(%d)\n", realCpyFrameNum);
3792 debug_msg(RELEASE, "pInfo->pUnsyncLyrics returned = (%s), pInfo->unsynclyricsLen(%d)\n", pInfo->pUnsyncLyrics, pInfo->unsynclyricsLen);
3793 pInfo->tagV2Info.bDescriptionMarked = true;
3794 } else if (strncmp((char *)CompTmp, "TCON", 4) == 0 && pInfo->tagV2Info.bGenreMarked == false) {
3795 if (textEncodingType == AV_ID3V2_UTF8) {
3796 pInfo->pGenre = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3797 if (pInfo->pGenre) {
3798 memcpy(pInfo->pGenre, pExtContent, realCpyFrameNum);
3799 pInfo->pGenre[realCpyFrameNum] = '\0';
3800 /*string copy with '\0'*/
3801 pInfo->genreLen = realCpyFrameNum;
3802 _STRNCPY_EX(pInfo->pGenre, pExtContent, pInfo->genreLen);
3805 pInfo->pGenre = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->genreLen);
3808 debug_msg(RELEASE, "pInfo->pGenre returned = (%s), pInfo->genreLen(%d)\n", pInfo->pGenre, pInfo->genreLen);
3810 if ((pInfo->pGenre != NULL) && (pInfo->genreLen > 0)) {
3814 ret = is_numeric(pInfo->pGenre, pInfo->genreLen);
3817 ret = safe_atoi(pInfo->pGenre, &int_genre);
3819 debug_msg(RELEASE, "genre information is inteager [%d]\n", int_genre);
3821 /*Change int to string */
3822 if ((0 <= int_genre) && (int_genre < GENRE_COUNT - 1)) {
3823 /*save genreinfo like "(123)". mm_file_id3tag_restore_content_info convert it to string*/
3824 char tmp_genre[6] = {0, }; /*ex. "(123)+NULL"*/
3825 int tmp_genre_len = 0;
3827 memset(tmp_genre, 0, 6);
3828 snprintf(tmp_genre, sizeof(tmp_genre), "(%d)", int_genre);
3830 tmp_genre_len = strlen(tmp_genre);
3831 if (tmp_genre_len > 0) {
3832 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
3833 pInfo->pGenre = mmfile_malloc(sizeof(char) * (tmp_genre_len + 1));
3834 if (pInfo->pGenre) {
3835 SAFE_STRLCPY(pInfo->pGenre, tmp_genre, tmp_genre_len + 1);
3840 debug_msg(RELEASE, "genre information is wrong inteager [%s]\n", pInfo->pGenre);
3845 pInfo->tagV2Info.bGenreMarked = true;
3846 } else if (strncmp((char *)CompTmp, "TRCK", 4) == 0 && pInfo->tagV2Info.bTrackNumMarked == false) {
3847 if (textEncodingType == AV_ID3V2_UTF8) {
3848 pInfo->pTrackNum = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3849 if (pInfo->pTrackNum != NULL) {
3850 memcpy(pInfo->pTrackNum, pExtContent, realCpyFrameNum);
3851 pInfo->pTrackNum[realCpyFrameNum] = '\0';
3852 /*string copy with '\0'*/
3853 pInfo->tracknumLen = realCpyFrameNum;
3854 _STRNCPY_EX(pInfo->pTrackNum, pExtContent, pInfo->tracknumLen);
3857 pInfo->pTrackNum = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->tracknumLen);
3860 debug_msg(RELEASE, "pInfo->pTrackNum returned = (%s), pInfo->tracknumLen(%d)\n", pInfo->pTrackNum, pInfo->tracknumLen);
3861 pInfo->tagV2Info.bTrackNumMarked = true;
3862 } else if (strncmp((char *)CompTmp, "TENC", 4) == 0 && pInfo->tagV2Info.bEncByMarked == false) {
3863 if (textEncodingType == AV_ID3V2_UTF8) {
3864 pInfo->pEncBy = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3865 if (pInfo->pEncBy != NULL) {
3866 memcpy(pInfo->pEncBy, pExtContent, realCpyFrameNum);
3867 pInfo->pEncBy[realCpyFrameNum] = '\0';
3868 /*string copy with '\0'*/
3869 pInfo->encbyLen = realCpyFrameNum;
3870 _STRNCPY_EX(pInfo->pEncBy, pExtContent, pInfo->encbyLen);
3873 pInfo->pEncBy = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->encbyLen);
3876 debug_msg(RELEASE, "pInfo->pEncBy returned = (%s), pInfo->encbyLen(%d)\n", pInfo->pEncBy, pInfo->encbyLen);
3877 pInfo->tagV2Info.bEncByMarked = true;
3878 } else if (strncmp((char *)CompTmp, "WXXX", 4) == 0 && pInfo->tagV2Info.bURLMarked == false) {
3879 if (textEncodingType == AV_ID3V2_UTF8) {
3880 pInfo->pURL = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3881 if (pInfo->pURL != NULL) {
3882 memcpy(pInfo->pURL, pExtContent, realCpyFrameNum);
3883 pInfo->pURL[realCpyFrameNum] = '\0';
3884 /*string copy with '\0'*/
3885 pInfo->urlLen = realCpyFrameNum;
3886 _STRNCPY_EX(pInfo->pURL, pExtContent, pInfo->urlLen);
3889 pInfo->pURL = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->urlLen);
3892 debug_msg(RELEASE, "pInfo->pURL returned = (%s), pInfo->urlLen(%d)\n", pInfo->pURL, pInfo->urlLen);
3893 pInfo->tagV2Info.bURLMarked = true;
3894 } else if (strncmp((char *)CompTmp, "TCOP", 4) == 0 && pInfo->tagV2Info.bCopyRightMarked == false) {
3895 if (textEncodingType == AV_ID3V2_UTF8) {
3896 pInfo->pCopyright = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3897 if (pInfo->pCopyright != NULL) {
3898 memcpy(pInfo->pCopyright, pExtContent, realCpyFrameNum);
3899 pInfo->pCopyright[realCpyFrameNum] = '\0';
3900 /*string copy with '\0'*/
3901 pInfo->copyrightLen = realCpyFrameNum;
3902 _STRNCPY_EX(pInfo->pCopyright, pExtContent, pInfo->copyrightLen);
3905 pInfo->pCopyright = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->copyrightLen);
3908 debug_msg(RELEASE, "pInfo->pCopyright returned = (%s), pInfo->copyrightLen(%d)\n", pInfo->pCopyright, pInfo->copyrightLen);
3909 pInfo->tagV2Info.bCopyRightMarked = true;
3910 } else if (strncmp((char *)CompTmp, "TOPE", 4) == 0 && pInfo->tagV2Info.bOriginArtistMarked == false) {
3911 if (textEncodingType == AV_ID3V2_UTF8) {
3912 pInfo->pOriginArtist = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3913 if (pInfo->pOriginArtist != NULL) {
3914 memcpy(pInfo->pOriginArtist, pExtContent, realCpyFrameNum);
3915 pInfo->pOriginArtist[realCpyFrameNum] = '\0';
3916 /*string copy with '\0'*/
3917 pInfo->originartistLen = realCpyFrameNum;
3918 _STRNCPY_EX(pInfo->pOriginArtist, pExtContent, pInfo->originartistLen);
3921 pInfo->pOriginArtist = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->originartistLen);
3924 debug_msg(RELEASE, "pInfo->pOriginArtist returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pOriginArtist, pInfo->originartistLen);
3925 pInfo->tagV2Info.bOriginArtistMarked = true;
3926 } else if (strncmp((char *)CompTmp, "TCOM", 4) == 0 && pInfo->tagV2Info.bComposerMarked == false) {
3927 if (textEncodingType == AV_ID3V2_UTF8) {
3928 pInfo->pComposer = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3929 if (pInfo->pComposer != NULL) {
3930 memcpy(pInfo->pComposer, pExtContent, realCpyFrameNum);
3931 pInfo->pComposer[realCpyFrameNum] = '\0';
3932 /*string copy with '\0'*/
3933 pInfo->composerLen = realCpyFrameNum;
3934 _STRNCPY_EX(pInfo->pComposer, pExtContent, pInfo->composerLen);
3937 pInfo->pComposer = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->composerLen);
3940 debug_msg(RELEASE, "pInfo->pComposer returned = (%s), pInfo->originartistLen(%d)\n", pInfo->pComposer, pInfo->composerLen);
3941 pInfo->tagV2Info.bComposerMarked = true;
3942 } else if (strncmp((char *)CompTmp, "TDRC", 4) == 0 && pInfo->tagV2Info.bRecDateMarked == false) { /*TYER(year) and TRDA are replaced by the TDRC */
3943 if (textEncodingType == AV_ID3V2_UTF8) {
3944 pInfo->pRecDate = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3945 if (pInfo->pRecDate != NULL) {
3946 memcpy(pInfo->pRecDate, pExtContent, realCpyFrameNum);
3947 pInfo->pRecDate[realCpyFrameNum] = '\0';
3948 /*string copy with '\0'*/
3949 pInfo->recdateLen = realCpyFrameNum;
3950 _STRNCPY_EX(pInfo->pRecDate, pExtContent, pInfo->recdateLen);
3953 pInfo->pRecDate = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->recdateLen);
3956 debug_msg(RELEASE, "pInfo->pRecDate returned = (%s), pInfo->recdateLen(%d)\n", pInfo->pRecDate, pInfo->recdateLen);
3957 pInfo->tagV2Info.bRecDateMarked = true;
3958 } else if (strncmp((char *)CompTmp, "TIT1", 4) == 0 && pInfo->tagV2Info.bContentGroupMarked == false) {
3959 if (textEncodingType == AV_ID3V2_UTF8) {
3960 pInfo->pContentGroup = mmfile_malloc(realCpyFrameNum + 2); /*Ignore NULL char for UTF16 */
3961 if (pInfo->pContentGroup != NULL) {
3962 memcpy(pInfo->pContentGroup, pExtContent, realCpyFrameNum);
3963 pInfo->pContentGroup[realCpyFrameNum] = '\0';
3964 /*string copy with '\0'*/
3965 pInfo->contentGroupLen = realCpyFrameNum;
3966 _STRNCPY_EX(pInfo->pContentGroup, pExtContent, pInfo->contentGroupLen);
3969 pInfo->pContentGroup = mmfile_string_convert((const char *)pExtContent, realCpyFrameNum, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&pInfo->contentGroupLen);
3972 debug_msg(RELEASE, "pInfo->pContentGroup returned = (%s), pInfo->contentGroupLen(%d)\n", pInfo->pContentGroup, pInfo->contentGroupLen);
3973 pInfo->tagV2Info.bContentGroupMarked = true;
3974 } else if (strncmp((char *)CompTmp, "APIC", 4) == 0 && pInfo->tagV2Info.bImageMarked == false && realCpyFrameNum <= 2000000) {
3975 if (pExtContent[0] != '\0') {
3976 for (inx = 0; inx < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1; inx++)
3977 pInfo->imageInfo.imageMIMEType[inx] = '\0';/*ini mimetype variable */
3979 while ((checkImgMimeTypeMax < MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH - 1) && pExtContent[checkImgMimeTypeMax] != '\0') {
3980 pInfo->imageInfo.imageMIMEType[checkImgMimeTypeMax] = pExtContent[checkImgMimeTypeMax];
3981 checkImgMimeTypeMax++;
3983 pInfo->imageInfo.imgMimetypeLen = checkImgMimeTypeMax;
3985 pInfo->imageInfo.imgMimetypeLen = 0;
3988 imgstartOffset += checkImgMimeTypeMax;
3990 if (strncmp(pInfo->imageInfo.imageMIMEType, MIME_PRFIX, strlen(MIME_PRFIX)) != 0) {
3991 pInfo->imageInfo.imgMimetypeLen = 0;
3992 debug_error(DEBUG, "APIC NOT VALID");
3996 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
3997 imgstartOffset++;/*endofMIME(1byte) */
3999 if (pExtContent[imgstartOffset] < AV_ID3V2_PICTURE_TYPE_MAX) {
4000 pInfo->imageInfo.pictureType = pExtContent[imgstartOffset];
4002 imgstartOffset++;/*PictureType(1byte) */
4004 if (pExtContent[imgstartOffset] != 0x0) {
4007 int new_dis_len = 0;
4008 char *tmp_desc = NULL;
4011 if (pExtContent[imgstartOffset + cur_pos] == '\0') {
4012 if (realCpyFrameNum < imgstartOffset + cur_pos) {
4013 debug_error(DEBUG, "End of APIC Tag %d %d %d\n", realCpyFrameNum, imgstartOffset, cur_pos);
4016 /*check end of image description*/
4017 if ((pExtContent[imgstartOffset + cur_pos + 1] == gTagJPEGHeader[0]) ||
4018 (pExtContent[imgstartOffset + cur_pos + 1] == gTagPNGHeader[0])) {
4019 debug_msg(RELEASE, "length of description (%d)", cur_pos);
4026 dis_len = cur_pos + 1;
4028 tmp_desc = mmfile_malloc(sizeof(char) * dis_len);
4030 if (tmp_desc != NULL) {
4031 memcpy(tmp_desc, pExtContent + imgstartOffset, dis_len);
4032 debug_msg(DEBUG, "tmp_desc %s\n", tmp_desc);
4034 /*convert description*/
4035 pInfo->imageInfo.imageDescription = mmfile_string_convert(tmp_desc, dis_len, "UTF-8", charset_array[textEncodingType], NULL, (unsigned int *)&new_dis_len);
4036 debug_msg(DEBUG, "new_desc %s(%d)\n", pInfo->imageInfo.imageDescription, new_dis_len);
4037 mmfile_free(tmp_desc);
4039 pInfo->imageInfo.imgDesLen = new_dis_len; /**/
4042 imgstartOffset += cur_pos;
4044 pInfo->imageInfo.imgDesLen = 0;
4047 if ((pExtContent[imgstartOffset] == '\0') && (realCpyFrameNum - imgstartOffset > 0)) {
4048 imgstartOffset++; /* endofDesceriptionType(1byte) */
4050 while (pExtContent[imgstartOffset] == '\0') { /*some content has useless '\0' in front of picture data */
4054 debug_msg(RELEASE, "after scaning imgDescription imgstartOffset(%d) value!\n", imgstartOffset);
4056 if (realCpyFrameNum - imgstartOffset > 0) {
4057 pInfo->imageInfo.imageLen = realCpyFrameNum - imgstartOffset;
4058 pInfo->imageInfo.pImageBuf = mmfile_malloc(pInfo->imageInfo.imageLen + 1);
4060 if (pInfo->imageInfo.pImageBuf != NULL) {
4061 memcpy(pInfo->imageInfo.pImageBuf, pExtContent + imgstartOffset, pInfo->imageInfo.imageLen);
4062 pInfo->imageInfo.pImageBuf[pInfo->imageInfo.imageLen] = 0;
4065 if (IS_INCLUDE_URL(pInfo->imageInfo.imageMIMEType))
4066 pInfo->imageInfo.bURLInfo = true; /*if mimetype is "-->", image date has an URL */
4068 debug_msg(RELEASE, "No APIC image!! realCpyFrameNum(%d) - imgstartOffset(%d)\n", realCpyFrameNum, imgstartOffset);
4073 checkImgMimeTypeMax = 0;
4076 pInfo->tagV2Info.bImageMarked = true;
4078 debug_msg(RELEASE, "CompTmp(%s) This Frame ID currently not Supports!!\n", CompTmp);
4083 debug_msg(RELEASE, "mmf_file_id3tag_parse_v224: All of the pExtContent Values are NULL\n");
4087 curPos += purelyFramelen;
4088 if (purelyFramelen != 0)
4089 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
4092 if (pExtContent) _FREE_EX(pExtContent);
4093 memset(CompTmp, 0, 4);
4094 if (curPos < taglen) {
4095 needToloopv2taglen -= oneFrameLen;
4098 needToloopv2taglen = MP3_TAGv2_23_TXT_HEADER_LEN;
4102 realCpyFrameNum = 0;
4103 textEncodingType = 0;
4109 release_characterset_array(charset_array);
4119 void mm_file_id3tag_restore_content_info(AvFileContentInfo *pInfo)
4121 char *mpegAudioGenre = NULL/*, *tmpGenreForV1Tag = NULL*/;
4122 bool bAdditionGenre = false /*, bMpegAudioFrame = false*/;
4123 int mpegAudioFileLen = 0, idv2IntGenre = 148/*, tmpinx = 0, tmpinx2=0*/;
4124 unsigned char genre = pInfo->genre;
4126 /* for Genre Info */
4127 if (pInfo->tagV2Info.bGenreMarked == false) {
4128 if (pInfo->bV1tagFound == true) {
4129 debug_msg(RELEASE, "Genre: %d\n", genre);
4134 if (MpegAudio_Genre[genre] != NULL) {
4135 pInfo->genreLen = strlen(MpegAudio_Genre[genre]);
4136 if (pInfo->genreLen > 0) {
4137 /* Give space for NULL character. Hence added "+1" */
4138 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4139 if (pInfo->pGenre) {
4140 SAFE_STRLCPY(pInfo->pGenre, MpegAudio_Genre[genre], pInfo->genreLen + 1);
4145 debug_msg(RELEASE, "Genre was not Found.\n");
4147 } else if (pInfo->tagV2Info.bGenreMarked == true) {
4148 if (pInfo->genreLen && pInfo->tagV2Info.bGenreUTF16) {
4149 pInfo->pGenre[pInfo->genreLen + 1] = '\0';
4150 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen * AV_WM_LOCALCODE_SIZE_MAX + 1));
4152 debug_msg(RELEASE, "pInfo->genreLen size is Zero Or not UTF16 code! genreLen[%d] genre[%s]\n", pInfo->genreLen, pInfo->pGenre);
4154 if (pInfo->pGenre) {
4155 pInfo->genreLen = strlen(pInfo->pGenre);
4156 mpegAudioGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4157 if (mpegAudioGenre != NULL) {
4158 SAFE_STRLCPY(mpegAudioGenre, pInfo->pGenre, pInfo->genreLen + 1);
4161 pInfo->genreLen = 0;
4165 if (pInfo->pGenre) _FREE_EX(pInfo->pGenre);
4168 if (mpegAudioGenre != NULL) {
4171 * (XXX) XXX is 0 - 148
4173 pInfo->genreLen = strlen(mpegAudioGenre);
4174 if (pInfo->genreLen >= 3 &&
4175 mpegAudioGenre[0] == '(' && mpegAudioGenre[pInfo->genreLen - 1] == ')') {
4176 bAdditionGenre = true;
4177 for (mpegAudioFileLen = 1; mpegAudioFileLen <= pInfo->genreLen - 2; mpegAudioFileLen++) {
4178 if (mpegAudioGenre[mpegAudioFileLen] < '0' || mpegAudioGenre[mpegAudioFileLen] > '9') {
4179 bAdditionGenre = false;
4185 if (bAdditionGenre == true) {
4186 idv2IntGenre = atoi(mpegAudioGenre + 1);
4188 if (idv2IntGenre > 147 || idv2IntGenre < 0)
4191 if (MpegAudio_Genre[idv2IntGenre] != NULL) {
4192 pInfo->genreLen = strlen(MpegAudio_Genre[idv2IntGenre]);
4193 if (pInfo->genreLen > 0) {
4194 /* Give space for NULL character. Hence added "+1" */
4195 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4196 if (pInfo->pGenre) {
4197 SAFE_STRLCPY(pInfo->pGenre, MpegAudio_Genre[idv2IntGenre], pInfo->genreLen + 1);
4201 debug_msg(RELEASE, "pInfo->pGenre = %s\n", pInfo->pGenre);
4202 } else if (bAdditionGenre == false && pInfo->genreLen > 0) {
4207 /* Give space for NULL character. Hence added "+1" */
4208 pInfo->pGenre = mmfile_malloc(sizeof(char) * (pInfo->genreLen + 1));
4209 if (pInfo->pGenre) {
4210 SAFE_STRLCPY(pInfo->pGenre, mpegAudioGenre, pInfo->genreLen + 1);
4212 debug_msg(RELEASE, "pInfo->pGenre = %s, pInfo->genreLen = %d\n", pInfo->pGenre, pInfo->genreLen);
4214 debug_msg(RELEASE, "Failed to \"(...)\" value to genre = %s\n", pInfo->pGenre);
4217 debug_msg(RELEASE, "mpegAudioGenre = %s\n", mpegAudioGenre);
4220 _FREE_EX(mpegAudioGenre);
4223 debug_msg(RELEASE, "Neither ID3 v1 nor v2 info doesn't have Genre Info.\n");
4228 void mm_file_free_synclyrics_list(GList *synclyrics_list)
4232 AvSynclyricsInfo *synclyrics_info = NULL;
4234 if (synclyrics_list == NULL) {
4238 list_len = g_list_length(synclyrics_list);
4239 for (idx = 0; idx < list_len; idx++) {
4240 synclyrics_info = g_list_nth_data(synclyrics_list, idx);
4242 if (synclyrics_info != NULL) {
4243 mmfile_free(synclyrics_info->lyric_info);
4244 mmfile_free(synclyrics_info);
4248 if (synclyrics_list != NULL) {
4249 g_list_free(synclyrics_list);
4250 synclyrics_list = NULL;