📄 id3tag.c
字号:
/************************************************** * * id3tag.c * * CVS ID: $Id: id3tag.c,v 1.46 2007/11/08 14:18:26 trubac Exp $ * Author: Jiri Sedmik [JS] - STM * Date: $Date: 2007/11/08 14:18:26 $ * Revision: $Revision: 1.46 $ * * Description: * * *************************************************** * * COPYRIGHT (C) ST Microelectronics 2005 * All Rights Reserved * **************************************************** * * STM CVS Log: * * $Log: id3tag.c,v $ * Revision 1.46 2007/11/08 14:18:26 trubac * Fix for bitrate parser lock inside random data stream * * Revision 1.45 2007/11/06 10:34:41 belardi * Removed code to treat TrackNo for ID3v1.1 as special case and not convert it to UTF-8 * * Revision 1.44 2007/09/11 16:00:07 belardi * Bug fix to avoid overflowing song_info.info array when long tags are present * * Revision 1.43 2007/09/11 14:14:47 sedmik * fix for multiple comments (only one occurrence of comment is stored for id3v2) * * Revision 1.42 2007/09/11 13:34:56 trubac * ID3v2 decoding function skips another comment frames if they are more * * Revision 1.41 2007/09/10 20:02:52 trubac * added test of language code to single byte endoded fields * * Revision 1.40 2007/09/10 18:39:33 trubac * workaround for ISO 639-2 language codes possibly present in ID3 comments * * Revision 1.39 2007/09/10 15:49:36 trubac * Update related to possible string array overflow * * Revision 1.38 2007/07/24 14:17:45 belardi * Fix bug of UTF8 conversion in Track number filed for v1.1 ID3 tags. * * Revision 1.37 2007/07/09 13:59:23 trubac * Fix for ID3v2 decoding, wrong cache filling * * Revision 1.36 2007/06/29 13:18:13 belardi * Added support for Track Number in ID3 v1.1 and v2.x * * Revision 1.35 2007/03/27 10:01:46 trubac * fixed Genre = 0 situation * * Revision 1.34 2007/03/19 14:28:04 trubac * directory names shrinking fixed * * Revision 1.33 2007/03/15 12:53:11 sedmik * fix for id3v2 empty frames * * Revision 1.32 2006/12/11 14:41:31 trubac * bitrate parsing slightly improved * * Revision 1.31 2006/12/08 14:42:09 trubac * Bitrate parser improvement * * Revision 1.30 2006/11/20 09:18:12 chlapik * fixed bugs in GetBitrate(), added workaround for mp1 in DecodeInfo2() * * Revision 1.29 2006/10/31 14:14:19 chlapik * support for Layer I & II: * - Layer type, sample rate and channel number are determined by BitrateParser before playback * - mp3 decoder checks if these parameters found in valid header matches, if not scan bitstream per bytes * * Revision 1.28 2006/10/25 15:22:09 trubac * fixed problem of last frame in ID3.22 tag * * Revision 1.27 2006/10/17 09:54:06 trubac * new id3 tag strings handling + new tag infos in song_info * * Revision 1.26 2006/10/09 12:51:05 trubac * Bitrate parser extensions, more info in song info * * Revision 1.25 2006/10/05 13:49:22 trubac * Improvement, code reduction of ID3v1 decoding * * Revision 1.24 2006/09/27 19:50:04 belardi * Removed (global) unused variables * * Revision 1.23 2006/09/25 16:06:33 belardi * better comment * * Revision 1.22 2006/09/25 15:52:35 belardi * Added #pragma to force ARM compilation in a function that fails otherwise * * Revision 1.21 2006/09/22 14:00:35 belardi * Added configuration.h to list of includes * * Revision 1.20 2006/09/15 19:42:06 belardi * Merged the m8_cav2_cm80506_cs3563. * - renamed CASE labels * * ***************************************************/#include <string.h>#include "configuration.h"#include "mp3_common.h"#include "id3tag.h"#include "tag.h" //[LL] added#include "utf8.h"#include "ioread.h"#include "filesys.h"#include "debug.h"//extern uint8 tag_length; // [RB] unusedextern uint8 tag_buf[]; //[LL] moved to tag.c; changed name id3_tag[]extern uint8 filesys_sectbuf[];//int32 m,n; // [RB] unusedstatic const unsigned int bitstreamTypes[] = { 0x00000000, // undefined 0x4D504733, // MPG3 0x4D504732, // MPG2 0x4D504731 // MPG1}; /* local functions *//* void ID3_ExtractID3v1(unsigned int pos); *//* void ID3_ExtractID3v2(unsigned int pos, unsigned int lstart); */GRESULT GetBitRate(t_SongInfos *songi);/*** Extract the ID3 TAG from the Selected File ***/int ID3_TagDecode(t_SongInfos *song_info, uint32 count_down){// t_SongInfos temp_song_info; uint32 identifier = 0; uint8 * buffer; int error; /* initialise internall buffer for ID3 tag recognition */ buffer = tag_buf; //temp_song_info = &song_info; //work with local copy of file informations //memcpy(&temp_song_info, song_info, sizeof(t_SongInfos)); /* Test ID3 tag ver 1 */ if (XAR_SeekFile (song_info, song_info->size - 128, 0) == S_OK) { if (XAR_ReadFile (song_info, buffer, 128,IO_READ_CACHE)<128 ) return E_READ_FAILURE; else { identifier = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]); if ( ID3_TAG_V1 == identifier ) { error = ID3_ExtractID3v1(song_info,buffer); if (S_OK != error) //pass error code to upper func return error; } } } XAR_SeekFile(song_info, 0, 0); ID3_ExtractID3v2(song_info ,buffer,count_down); //temp_song_info = &song_info; //reinit local copy of file informations //memcpy(&temp_song_info, song_info, sizeof(t_SongInfos)); //JS commented, not needed now XAR_SeekFile (song_info, 0, 0); return S_OK;}uint8 const ID3v1_FIELDS[] = { ALBUM_TITLE,ID3_TAG_V1_ALBUM_POSITION,ID3_TAG_V1_ITEM_LENGTH, SONG_TITLE,ID3_TAG_V1_TITLE_POSITION,ID3_TAG_V1_ITEM_LENGTH, ARTIST,ID3_TAG_V1_ARTIST_POSITION,ID3_TAG_V1_ITEM_LENGTH, YEAR,ID3_TAG_V1_YEAR_POSITION,4, COMMENT,ID3_TAG_V1_COMMENT_POSITION,ID3_TAG_V1_ITEM_LENGTH, TRACK_NO,ID3_TAG_V1_COMMENT_POSITION,1, /* not an error, Track number is contained in the Comment field */ GENRE,ID3_TAG_V1_GENRE_POSITION,1, 0 }; /*** Extract the ID3 TAG - version 1***/int ID3_ExtractID3v1(t_SongInfos *song_info,uint8 * buffer){ /* found ID3 Tag version 1 - exctract info (compatible v1.0 and v1.1)*/ uint8 length; uint8 *len_ptr; GRESULT wlen; t_conv_param p; int id = 0,ID,IDpos,IDlen; uint8 temp_buf[ID3V1_MAX_TEXT_SIZE*2]; //for charset conversions /* allocate and assign memory for tag v1 infos */ len_ptr = song_info->strings + song_info->strtop; while(ID3v1_FIELDS[id] !=0 ) { ID = ID3v1_FIELDS[id++]; IDpos = ID3v1_FIELDS[id++]; IDlen = ID3v1_FIELDS[id++]; if ((song_info->n_infos < XSONG_INFO_TAGS) && (song_info->strtop < MAX_STRINGS_SIZE - 2)) { if(ID == GENRE) length = 1; else if (ID == TRACK_NO) { /* ID3v1.1 track number stored in last byte of comment field */ /* but only if below condition is met */ if ((buffer[IDpos + 28] == 0) && (buffer[IDpos + 29] != 0)) { length = 1; IDpos = IDpos + 29; } else { length = 0; } } else length = id3_v1_len(&(buffer[IDpos]),IDlen); if(length>0) {#if 0 /* [RB] this code created a special case for TrackNo */ /* to return it as single byte instead of UTF-8 as all others */ /* It seemed more efficient but it creates confusion in the Host */ /* and is not compliant with CIS, so it's removed */ if (ID == TRACK_NO) { *(len_ptr + 1) = buffer[IDpos]; wlen = 1; } else#endif { estrcpy(temp_buf, &(buffer[IDpos]), length); str_convert_byte2int(temp_buf, length); p.be = 1; p.limit = wmin(255, MAX_STRINGS_SIZE - song_info->strtop - 1); p.trunc = 0; wlen = WideStringToUTF8((uint8*)temp_buf,len_ptr+1, length, &p ); } if((wlen>0)&&(wlen<256)) { *len_ptr = wlen; song_info->infos[song_info->n_infos].tag_version = 1; song_info->infos[song_info->n_infos].enc_of_src = TEXT_ENCODING_ISO_8859_1; song_info->infos[song_info->n_infos].info_type = (t_SongTagType) ID; song_info->infos[song_info->n_infos].string_offset = song_info->strtop; song_info->strtop += (wlen + 1); len_ptr += (1 + wlen); song_info->n_infos++; } } } } song_info->end_offset = song_info->size - 128; //default length of v1 tag return S_OK; }/*** Extract the ID3 TAG - version 2 ***/int write_byte(t_SongInfos *si, uint8 b){ if(si->strtop >= MAX_STRINGS_SIZE) // [OT] to avoid strings array overflow return 0; if (si->strings[si->infos[si->n_infos].string_offset] >= ID3V2_MAX_TEXT_SIZE) // check current length return 0; if (si->strings[si->infos[si->n_infos].string_offset] == 0) // pointer shift at beginning si->strtop++; *(si->strings + si->strtop) = b; si->strtop++; (si->strings[si->infos[si->n_infos].string_offset])++; return 1;}int write_utf8(t_SongInfos *si, uint16 w){ if(w<=0x7f) return write_byte(si,w); if(w<=0x7ff) { if(write_byte(si, 0xC0 | (w >> 6))) { return write_byte(si, 0x80 | (w & 0x3F)); } return 0; } if(write_byte(si, 0xE0 | (w >> 12))) { if(write_byte(si, 0x80 | (0x3f & (w >> 6)))) { return write_byte(si, 0x80 | (w & 0x3F)); } } return 0;}int ID3_ExtractID3v2(t_SongInfos *song_info, uint8 * buffer, uint32 count_down ){ /* found ID3 Tag version 2 - exctract info */ int32 p,n,cnt,chcnt,i,cnt0; int comment = 0; uint16 word; // pointer inside ID3 tag ID32_PROCESSING_ENUM processing_switch = ID32_FIND_FRAME; //general functionality switch (find frame, parse info from frame) uint32 frID,frflags,id_be; uint32 pos,id32rev,id32flags,id_data,id_frtop; uint32 load_pos,cmp_enc,gr_iden;static uint32 v2_length; uint32 identifier = 0,utf8_conv; t_TextEncoding id32_encoding; GRESULT res; /* get length of id3 tag version 2: 7 lsb bits valid on each byte */ /* fill info struct, to inform upper layer funcs where mp3 decoder can start inside file */ /* Test ID3 tag ver 2 */ if ( XAR_ReadFile(song_info, buffer, 10, IO_READ_CACHE) < 10 ) { XAR_SeekFile (song_info, 0, 0); return E_READ_FAILURE; } else {/* identifier = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]); if ( 0x524946 != identifier ) while(1);*/ identifier = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]); XAR_SeekFile (song_info, 0, 0); if ( ID3_TAG_V2 != identifier ) { //while(1); // debug !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! return S_FALSE; } } v2_length = ((buffer[ID3_TAG_V2_LENGTH_POSITION] & 0x7f) <<21) | ((buffer[ID3_TAG_V2_LENGTH_POSITION+1] & 0x7f) <<14) | ((buffer[ID3_TAG_V2_LENGTH_POSITION+2] & 0x7f) <<7) | (buffer[ID3_TAG_V2_LENGTH_POSITION+3] & 0x7f) ; if((v2_length+ID3_TAG_V2_HEADER_LENGTH)<ID3_BUFFER_LENGTH) res = XAR_ReadFile(song_info, buffer, v2_length+ID3_TAG_V2_HEADER_LENGTH, IO_READ_CACHE); else res = XAR_ReadFile(song_info, buffer, ID3_BUFFER_LENGTH, IO_READ_CACHE); load_pos = 0; // what is currently in buffer beginning if(!res) return E_READ_FAILURE; if (count_down==0) //if ID3 tag is too long, it's possible to use timeout checking (input nonzero value) count_down = v2_length + ID3_TAG_V2_HEADER_LENGTH; // OT v2_length += ID3_TAG_V2_HEADER_LENGTH; song_info->start_offset = v2_length; id32rev = buffer[ID3_TAG_V2_VERSION_POSITION]; if((id32rev>4)||(id32rev<2)) return E_FAIL; id32flags = buffer[ID3_TAG_V2_FLAGS_POSITION]; //unsync = (0 != (id32flags&128)); pos = ID3_TAG_V2_HEADER_LENGTH; p = id32flags&0x4f; if(p) { if(p&0xf) return E_FAIL; // extended header present switch(id32rev) { case 3: pos = buffer[13] + 14; break; case 4: pos = 10+(buffer[11]<<14)+(buffer[12]<<7)+buffer[13]; break; default: return E_FAIL; } } while(1) { switch(processing_switch) { case ID32_FIND_FRAME: // evaluate frame header size if(id32rev==2) p = 6; else p = 10; if(((pos+p)>=v2_length) || (song_info->strtop >= MAX_STRINGS_SIZE)) { processing_switch = ID32_TERMINATE; break; } if((pos+p)>(load_pos+ID3_BUFFER_LENGTH)) { n = pos&(~3); // new load_pos p = wmin(n+ID3_BUFFER_LENGTH,v2_length); cnt = p - n; if(cnt <= 0) { processing_switch = ID32_TERMINATE; break; } // how many bytes should be prepared in buffer if((n - load_pos)<ID3_BUFFER_LENGTH) // check if data follow continuously { p = ID3_BUFFER_LENGTH - (n - load_pos); // count of present bytes to keep memcpy(buffer, buffer + (n - load_pos), p ); cnt -= p ; } else // not continuous jump ( frame is big ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -