/* Fill info structure with data from the id3 tag */ static void mp3_info (const char *file_name, struct file_tags *info, const int tags_sel) { if (tags_sel & TAGS_COMMENTS) { struct id3_tag *tag; struct id3_file *id3file; char *track = NULL; id3file = id3_file_open (file_name, ID3_FILE_MODE_READONLY); if (!id3file) return; tag = id3_file_tag (id3file); if (tag) { info->artist = get_tag (tag, ID3_FRAME_ARTIST); info->title = get_tag (tag, ID3_FRAME_TITLE); info->album = get_tag (tag, ID3_FRAME_ALBUM); track = get_tag (tag, ID3_FRAME_TRACK); if (track) { char *end; info->track = strtol (track, &end, 10); if (end == track) info->track = -1; free (track); } } id3_file_close (id3file); } if (tags_sel & TAGS_TIME) info->time = count_time (file_name); }
void LibMadWrapper::buildMetadata() noexcept { // TODO we have to find ID3 tag in the mpeg file, but this should be done while trying decoding mpeg-frame-headers // whenever libmad returns lost_sync error, there might be a id3 tag struct id3_file *s = id3_file_open(this->Filename.c_str(), ID3_FILE_MODE_READONLY); if (s == nullptr) { return; } struct id3_tag *t = id3_file_tag(s); if (t == nullptr) { id3_file_close(s); return; } this->Metadata.Title = id3_get_tag(t, ID3_FRAME_TITLE); this->Metadata.Artist = id3_get_tag(t, ID3_FRAME_ARTIST); this->Metadata.Album = id3_get_tag(t, ID3_FRAME_ALBUM); this->Metadata.Year = id3_get_tag(t, ID3_FRAME_YEAR); this->Metadata.Genre = id3_get_tag(t, ID3_FRAME_GENRE); this->Metadata.Track = id3_get_tag(t, ID3_FRAME_TRACK); this->Metadata.Comment = id3_get_tag(t, ID3_FRAME_COMMENT); id3_file_close(s); }
void Tags::ImportID3(wxString fileName) { #ifdef USE_LIBID3TAG #ifdef _UNICODE /* id3_file_open doesn't handle fn_Str() in Unicode build. May or may not actually work. */ struct id3_file *fp = id3_file_open(FILENAME(fileName).mb_str(), ID3_FILE_MODE_READONLY); #else // ANSI struct id3_file *fp = id3_file_open(FILENAME(fileName).fn_str(), ID3_FILE_MODE_READONLY); #endif // Unicode/ANSI if (!fp) return; struct id3_tag *tp = id3_file_tag(fp); if (!tp) return; mTitle = GetID3FieldStr(tp, ID3_FRAME_TITLE); mArtist = GetID3FieldStr(tp, ID3_FRAME_ARTIST); mAlbum = GetID3FieldStr(tp, ID3_FRAME_ALBUM); mYear = GetID3FieldStr(tp, ID3_FRAME_YEAR); mComments = GetID3FieldStr(tp, ID3_FRAME_COMMENT); long l; wxString s; if ((s = GetID3FieldStr(tp, ID3_FRAME_TRACK)).ToLong(&l)) mTrackNum = l; mID3V2 = ( tp->options & ID3_TAG_OPTION_ID3V1 ) ? false : true; s = GetID3FieldStr(tp, ID3_FRAME_GENRE); if( mID3V2 ) { int numGenres = GetNumGenres(); for(int i=0; i<numGenres; i++) if (0 == s.CmpNoCase(GetGenreNum(i))) mGenre = i; } else { if( s.ToLong( &l ) ) mGenre = l; } id3_file_close(fp); #endif // ifdef USE_LIBID3TAG }
trackDetails * getMP3Details(char *path) { trackDetails *details; details = calloc(1,sizeof(trackDetails)); struct id3_file *mp3file = NULL; struct id3_tag *tag = NULL; mp3file = id3_file_open(path,ID3_FILE_MODE_READONLY); if(mp3file!=NULL) { tag = id3_file_tag(mp3file); details->title = getTagString(tag,"TIT2"); details->artist = getTagString(tag,"TPE1"); details->album = getTagString(tag,"TALB"); } else { fprintf(stdout,"could not get details for %s\n",path); } id3_file_close(mp3file); return details; }
/* Fill info structure with data from aac comments */ static void aac_info (const char *file_name, struct file_tags *info, const int tags_sel) { if (tags_sel & TAGS_COMMENTS) { struct id3_tag *tag; struct id3_file *id3file; char *track = NULL; id3file = id3_file_open (file_name, ID3_FILE_MODE_READONLY); if (!id3file) return; tag = id3_file_tag (id3file); if (tag) { info->artist = get_tag (tag, ID3_FRAME_ARTIST); info->title = get_tag (tag, ID3_FRAME_TITLE); info->album = get_tag (tag, ID3_FRAME_ALBUM); track = get_tag (tag, ID3_FRAME_TRACK); if (track) { char *end; info->track = strtol (track, &end, 10); if (end == track) info->track = -1; free (track); } } id3_file_close (id3file); } if (tags_sel & TAGS_TIME) { struct aac_data *data; data = aac_open_internal (NULL, file_name); if (data->ok) info->time = aac_count_time (data); else logit ("%s", decoder_error_text (&data->error)); aac_close (data); } }
static int get_id3_info( const char *fname, struct id3_file **id3struct, struct id3_tag **id3tag) { struct id3_file *s; struct id3_tag *t; s = id3_file_open(fname, ID3_FILE_MODE_READONLY); if( s == NULL ) return (0); t = id3_file_tag(s); if(t == NULL) { id3_file_close(s); return (0); } *id3struct = s; *id3tag = t; return (1); }
/* ** bool prepareMP3(string strFile, bool bReadOnly) ** ** Prepare a mp3 file to retreive it's tag information if it has ** ** Parameter: ** strFile: mp3 file with full pathname ** bReadOnly: Indicate how you are going to open the file. */ bool CMP3ID3::prepareMP3(string strFile, bool bReadOnly){ if ( m_pID3File != NULL ) id3_file_close(m_pID3File); int fileID = -1; if ( bReadOnly ) fileID = open(strFile.c_str(),O_RDONLY); else fileID = open(strFile.c_str(),O_RDWR); if ( fileID == -1 ) return false; if ( bReadOnly ) m_pID3File = id3_file_fdopen(fileID,ID3_FILE_MODE_READONLY); else m_pID3File = id3_file_fdopen(fileID,ID3_FILE_MODE_READWRITE); if ( m_pID3File == NULL ) return false; m_pID3Tag = id3_file_tag(m_pID3File); return true; }
int main(int argc, char *argv[]) { int fd = 0; char *currentfile, old_dir[PATH_MAX]; playlist *pl = NULL; struct id3_file *id3struct = NULL; struct id3_tag *id3tag = NULL; buffer playbuf; struct mad_decoder decoder; old_dir[0] = '\0'; playbuf.pl = pl = new_playlist(); if (!pl) { fprintf(stderr, "malloc failed at startup!\n"); exit(1); } options.volume = MAD_F_ONE; status = MPG321_PLAYING; /* Get the command line options */ parse_options(argc, argv, pl); /* If there were no files and no playlist specified just print the usage */ if (!playlist_file && optind == argc) { usage(argv[0]); exit(0); } if (playlist_file) load_playlist(pl, playlist_file); add_cmdline_files(pl, argv); if (shuffle_play) shuffle_files(pl); ao_initialize(); check_default_play_device(); if (!(options.opt & MPG321_REMOTE_PLAY)) { handle_signals(-1); /* initialize signal handler */ remote_input_buf[0] = '\0'; } if (!(options.opt & MPG321_QUIET_PLAY)) mpg123_boilerplate(); if (options.opt & MPG321_REMOTE_PLAY) { printf ("@R MPG123\n"); } /* Play the mpeg files or zip it! */ while((currentfile = get_next_file(pl, &playbuf))) { if (quit_now) break; signal(SIGINT, SIG_DFL); playbuf.buf = NULL; playbuf.fd = -1; playbuf.length = 0; playbuf.done = 0; playbuf.num_frames = 0; playbuf.max_frames = -1; strncpy(playbuf.filename,currentfile, PATH_MAX); playbuf.filename[PATH_MAX-1] = '\0'; if (status == MPG321_PLAYING) file_change = 1; mad_timer_reset(&playbuf.duration); mad_timer_reset(¤t_time); if (!(options.opt & MPG321_QUIET_PLAY) && file_change) { id3struct = id3_file_open (currentfile, ID3_FILE_MODE_READONLY); if (id3struct) { id3tag = id3_file_tag (id3struct); if (id3tag) { show_id3 (id3tag); } id3_file_close (id3struct); } } if (options.opt & MPG321_REMOTE_PLAY && file_change) { id3struct = id3_file_open (currentfile, ID3_FILE_MODE_READONLY); if (id3struct) { id3tag = id3_file_tag (id3struct); if (id3tag) { if (!show_id3(id3tag)) { /* This shouldn't be necessary, but it appears that libid3tag doesn't necessarily know if there are no id3 tags on a given mp3 */ char * basec = strdup(currentfile); char * basen = basename(basec); char * dot = strrchr(basen, '.'); if (dot) *dot = '\0'; printf("@I %s\n", basen); free(basec); } } else { fprintf(stderr, "Allocation error"); exit(1); } id3_file_close (id3struct); } else { char * basec = strdup(currentfile); char * basen = basename(basec); char * dot = strrchr(basen, '.'); if (dot) *dot = '\0'; printf("@I %s\n", basen); free(basec); } } /* Create the MPEG stream */ /* Check if source is on the network */ if((fd = raw_open(currentfile)) != 0 || (fd = http_open(currentfile)) != 0 || (fd = ftp_open(currentfile)) != 0) { playbuf.fd = fd; playbuf.buf = malloc(BUF_SIZE); playbuf.length = BUF_SIZE; mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0, output, /*error*/0, /* message */ 0); } /* Check if we are to use stdin for input */ else if(strcmp(currentfile, "-") == 0) { playbuf.fd = fileno(stdin); playbuf.buf = malloc(BUF_SIZE); playbuf.length = BUF_SIZE; mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0, output, /*error*/0, /* message */ 0); } /* currentfile is a local file (presumably.) mmap() it */ else { struct stat stat; if((fd = open(currentfile, O_RDONLY)) == -1) { mpg321_error(currentfile); /* mpg123 stops immediately if it can't open a file */ break; } if(fstat(fd, &stat) == -1) { close(fd); mpg321_error(currentfile); continue; } if (!S_ISREG(stat.st_mode)) { close(fd); continue; } calc_length(currentfile, &playbuf); if ((options.maxframes != -1) && (options.maxframes <= playbuf.num_frames)) { playbuf.max_frames = options.maxframes; } playbuf.frames = malloc((playbuf.num_frames + 1) * sizeof(void*)); playbuf.times = malloc((playbuf.num_frames + 1) * sizeof(mad_timer_t)); if((playbuf.buf = mmap(0, playbuf.length, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { close(fd); mpg321_error(currentfile); continue; } close(fd); playbuf.frames[0] = playbuf.buf; mad_decoder_init(&decoder, &playbuf, read_from_mmap, read_header, /*filter*/0, output, /*error*/0, /* message */ 0); } if(!(options.opt & MPG321_QUIET_PLAY))/*zip it!!!*/ { /* Because dirname might modify the argument */ char * dirc = strdup(currentfile); char * basec = strdup(currentfile); char * basen = basename(basec); char * dirn = dirname(dirc); /* make sure that the file has a pathname; otherwise don't print out a Directory: listing */ if(strchr(currentfile, '/') && strncmp(old_dir, dirn, PATH_MAX) != 0) { /* Print information about the file */ fprintf(stderr, "\n"); fprintf(stderr,"Directory: %s/\n", dirn); strncpy(old_dir, dirn, PATH_MAX); old_dir[PATH_MAX-1] = '\0'; } /* print a newline between different songs only, not after Directory: listing */ else { fprintf(stderr, "\n"); } fprintf(stderr,"Playing MPEG stream from %s ...\n", basen); free(dirc); free(basec); } signal(SIGINT, handle_signals); /* Every time the user gets us to rewind, we exit decoding, reinitialize it, and re-start it */ while (1) { mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); /* if we're rewinding on an mmap()ed stream */ if(status == MPG321_REWINDING && playbuf.fd == -1) { mad_decoder_init(&decoder, &playbuf, read_from_mmap, read_header, /*filter*/0, output, /*error*/0, /* message */ 0); } else break; } if (!(options.opt & MPG321_QUIET_PLAY)) { char time_formatted[11]; mad_timer_string(current_time, time_formatted, "%.1u:%.2u", MAD_UNITS_MINUTES, MAD_UNITS_SECONDS, 0); fprintf(stderr, "\n[%s] Decoding of %s finished.\n",time_formatted, basename(currentfile)); } if (options.opt & MPG321_REMOTE_PLAY && status == MPG321_STOPPED) { clear_remote_file(pl); } mad_decoder_finish(&decoder); if (quit_now) break; if (playbuf.frames) free(playbuf.frames); if (playbuf.times) free(playbuf.times); if (playbuf.fd == -1) { munmap(playbuf.buf, playbuf.length); } else { free(playbuf.buf); if (playbuf.fd != fileno(stdin)) close(playbuf.fd); } } if(playdevice) ao_close(playdevice); ao_shutdown(); #if defined(RAW_SUPPORT) || defined(HTTP_SUPPORT) || defined(FTP_SUPPORT) if(fd) close(fd); #endif return(0); }
int scan_mp3_get_mp3tags(char *file, MP3FILE *pmp3) { struct id3_file *pid3file; struct id3_tag *pid3tag; struct id3_frame *pid3frame; int err; int index; int used; char *utf8_text; int genre=WINAMP_GENRE_UNKNOWN; int have_utf8; int have_text; id3_ucs4_t const *native_text; char *tmp; int got_numeric_genre; int rating; char *conversion_codepage; pid3file=id3_file_open(file,ID3_FILE_MODE_READONLY); if(!pid3file) { DPRINTF(E_WARN,L_SCAN,"Cannot open %s\n",file); return FALSE; } pid3tag=id3_file_tag(pid3file); if(!pid3tag) { err=errno; id3_file_close(pid3file); errno=err; DPRINTF(E_WARN,L_SCAN,"Cannot get ID3 tag for %s\n",file); return FALSE; } DPRINTF(E_SPAM,L_SCAN,"Starting mp3 tag scan\n"); conversion_codepage = conf_alloc_string("scanning","mp3_tag_codepage", "ISO-8859-1"); index=0; while((pid3frame=id3_tag_findframe(pid3tag,"",index))) { used=0; utf8_text=NULL; native_text=NULL; have_utf8=0; have_text=0; DPRINTF(E_SPAM,L_SCAN,"Found tag %s\n",pid3frame->id); if(!strcmp(pid3frame->id,"YTCP")) { /* for id3v2.2 */ pmp3->compilation = 1; DPRINTF(E_DBG,L_SCAN,"Compilation: %d\n", pmp3->compilation); } if(((pid3frame->id[0] == 'T')||(strcmp(pid3frame->id,"COMM")==0)) && (id3_field_getnstrings(&pid3frame->fields[1]))) have_text=1; if(have_text) { native_text=id3_field_getstrings(&pid3frame->fields[1],0); if(native_text) { have_utf8=1; utf8_text = (char*)id3_ucs4_utf8duplicate(native_text); if(utf8_text) mem_register(utf8_text,0); if(id3_field_gettextencoding(&pid3frame->fields[1]) == ID3_FIELD_TEXTENCODING_ISO_8859_1) { #ifdef HAVE_ICONV /* this is kinda cheesy, but ucs4* == char* for 8859-1 */ free(utf8_text); utf8_text = (char*)util_xtoutf8_alloc((unsigned char*)native_text, strlen((char*)native_text), conversion_codepage); #endif } if(!strcmp(pid3frame->id,"TIT2")) { /* Title */ used=1; pmp3->title = utf8_text; DPRINTF(E_DBG,L_SCAN," Title: %s\n",utf8_text); } else if(!strcmp(pid3frame->id,"TPE1")) { used=1; pmp3->artist = utf8_text; DPRINTF(E_DBG,L_SCAN," Artist: %s\n",utf8_text); } else if(!strcmp(pid3frame->id,"TALB")) { used=1; pmp3->album = utf8_text; DPRINTF(E_DBG,L_SCAN," Album: %s\n",utf8_text); } else if(!strcmp(pid3frame->id,"TCOM")) { used=1; pmp3->composer = utf8_text; DPRINTF(E_DBG,L_SCAN," Composer: %s\n",utf8_text); } else if(!strcmp(pid3frame->id,"TIT1")) { used=1; pmp3->grouping = utf8_text; DPRINTF(E_DBG,L_SCAN," Grouping: %s\n",utf8_text); } else if(!strcmp(pid3frame->id,"TPE2")) { used=1; pmp3->orchestra = utf8_text; DPRINTF(E_DBG,L_SCAN," Orchestra: %s\n",utf8_text); } else if(!strcmp(pid3frame->id,"TPE3")) { used=1; pmp3->conductor = utf8_text; DPRINTF(E_DBG,L_SCAN," Conductor: %s\n",utf8_text); } else if(!strcmp(pid3frame->id,"TCON")) { used=1; pmp3->genre = utf8_text; got_numeric_genre=0; DPRINTF(E_DBG,L_SCAN," Genre: %s\n",utf8_text); if(pmp3->genre) { if(!strlen(pmp3->genre)) { genre=WINAMP_GENRE_UNKNOWN; got_numeric_genre=1; } else if (scan_mp3_is_numeric(pmp3->genre)) { genre=atoi(pmp3->genre); got_numeric_genre=1; } else if ((pmp3->genre[0] == '(') && (isdigit(pmp3->genre[1]))) { genre=atoi((char*)&pmp3->genre[1]); got_numeric_genre=1; } if(got_numeric_genre) { if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN)) genre=WINAMP_GENRE_UNKNOWN; free(pmp3->genre); pmp3->genre=strdup(scan_winamp_genre[genre]); } } } else if(!strcmp(pid3frame->id,"COMM")) { used=1; pmp3->comment = utf8_text; DPRINTF(E_DBG,L_SCAN," Comment: %s\n",pmp3->comment); } else if(!strcmp(pid3frame->id,"TPOS")) { tmp=utf8_text; strsep(&tmp,"/"); if(tmp) { pmp3->total_discs=atoi(tmp); } pmp3->disc=atoi(utf8_text); DPRINTF(E_DBG,L_SCAN," Disc %d of %d\n",pmp3->disc,pmp3->total_discs); } else if(!strcmp(pid3frame->id,"TRCK")) { tmp=utf8_text; strsep(&tmp,"/"); if(tmp) { pmp3->total_tracks=atoi(tmp); } pmp3->track=atoi(utf8_text); DPRINTF(E_DBG,L_SCAN," Track %d of %d\n",pmp3->track,pmp3->total_tracks); } else if(!strcmp(pid3frame->id,"TDRC")) { pmp3->year = atoi(utf8_text); DPRINTF(E_DBG,L_SCAN," Year: %d\n",pmp3->year); } else if(!strcmp(pid3frame->id,"TLEN")) { pmp3->song_length = atoi(utf8_text); /* now in ms */ DPRINTF(E_DBG,L_SCAN," Length: %d\n", pmp3->song_length); } else if(!strcmp(pid3frame->id,"TBPM")) { pmp3->bpm = atoi(utf8_text); DPRINTF(E_DBG,L_SCAN,"BPM: %d\n", pmp3->bpm); } else if(!strcmp(pid3frame->id,"TCMP")) { /* for id3v2.3 */ pmp3->compilation = (char)atoi(utf8_text); DPRINTF(E_DBG,L_SCAN,"Compilation: %d\n", pmp3->compilation); } } } /* can check for non-text tags here */ if((!used) && (have_utf8) && (utf8_text)) free(utf8_text); if((!strcmp(pid3frame->id,"POPM")) && (pid3frame->nfields == 3)) { rating = id3_field_getint(&pid3frame->fields[1]); if(rating >= 0x01) pmp3->rating = 20; if(rating >= 0x40) pmp3->rating = 40; if(rating >= 0x80) pmp3->rating = 60; if(rating >= 0xC4) pmp3->rating = 80; if(rating >= 0xFF) pmp3->rating = 100; } /* v2 COMM tags are a bit different than v1 */ if((!strcmp(pid3frame->id,"COMM")) && (pid3frame->nfields == 4)) { /* Make sure it isn't a application-specific comment... * This currently includes the following: * * iTunes_CDDB_IDs * iTunNORM * * If other apps stuff crap into comment fields, then we'll ignore them * here. */ native_text=id3_field_getstring(&pid3frame->fields[2]); if(native_text) { utf8_text=(char*)id3_ucs4_utf8duplicate(native_text); if(utf8_text) mem_register(utf8_text,0); if((utf8_text) && (strncasecmp(utf8_text,"iTun",4) != 0)) { /* it's a real comment */ if(utf8_text) free(utf8_text); native_text=id3_field_getfullstring(&pid3frame->fields[3]); if(native_text) { if(pmp3->comment) free(pmp3->comment); utf8_text=(char*)id3_ucs4_utf8duplicate(native_text); if(utf8_text) { mem_register(utf8_text,0); pmp3->comment=utf8_text; } } } else { if(utf8_text) free(utf8_text); } } } index++; } free(conversion_codepage); id3_file_close(pid3file); DPRINTF(E_DBG,L_SCAN,"Got id3 tag successfully\n"); return TRUE; }
void MP3ImportFileHandle::ImportID3(Tags *tags) { #ifdef USE_LIBID3TAG struct id3_file *fp = id3_file_open(OSFILENAME(mFilename), ID3_FILE_MODE_READONLY); if (!fp) { return; } struct id3_tag *tp = id3_file_tag(fp); if (!tp) { id3_file_close(fp); return; } tags->Clear(); tags->SetID3V2( tp->options & ID3_TAG_OPTION_ID3V1 ? false : true ); // Loop through all frames for (int i = 0; i < (int) tp->nframes; i++) { struct id3_frame *frame = tp->frames[i]; // printf("ID: %08x '%4s'\n", (int) *(int *)frame->id, frame->id); // printf("Desc: %s\n", frame->description); // printf("Num fields: %d\n", frame->nfields); // for (int j = 0; j < (int) frame->nfields; j++) { // printf("field %d type %d\n", j, frame->fields[j].type ); // if (frame->fields[j].type == ID3_FIELD_TYPE_STRINGLIST) { // printf("num strings %d\n", frame->fields[j].stringlist.nstrings); // } // } wxString n, v; // Determine the tag name if (strcmp(frame->id, ID3_FRAME_TITLE) == 0) { n = TAG_TITLE; } else if (strcmp(frame->id, ID3_FRAME_ARTIST) == 0) { n = TAG_ARTIST; } else if (strcmp(frame->id, ID3_FRAME_ALBUM) == 0) { n = TAG_ALBUM; } else if (strcmp(frame->id, ID3_FRAME_TRACK) == 0) { n = TAG_TRACK; } else if (strcmp(frame->id, "TYER") == 0) { n = TAG_YEAR; } else if (strcmp(frame->id, ID3_FRAME_YEAR) == 0) { n = TAG_YEAR; } else if (strcmp(frame->id, ID3_FRAME_COMMENT) == 0) { n = TAG_COMMENTS; } else if (strcmp(frame->id, ID3_FRAME_GENRE) == 0) { n = TAG_GENRE; } else { // Use frame description as default tag name. The descriptions // may include several "meanings" separated by "/" characters, so // we just use the first meaning n = UTF8CTOWX(frame->description).BeforeFirst(wxT('/')); } const id3_ucs4_t *ustr = NULL; if (n == TAG_COMMENTS) { ustr = id3_field_getfullstring(&frame->fields[3]); } else if (frame->nfields == 3) { ustr = id3_field_getstring(&frame->fields[1]); if (ustr) { char *str = (char *)id3_ucs4_utf8duplicate(ustr); n = UTF8CTOWX(str); free(str); } ustr = id3_field_getstring(&frame->fields[2]); } else if (frame->nfields >= 2) { ustr = id3_field_getstrings(&frame->fields[1], 0); } if (ustr) { char *str = (char *)id3_ucs4_utf8duplicate(ustr); v = UTF8CTOWX(str); free(str); } if (!n.IsEmpty() && !v.IsEmpty()) { tags->SetTag(n, v); } } // Convert v1 genre to name if (tags->HasTag(TAG_GENRE)) { long g = -1; if (tags->GetTag(TAG_GENRE).ToLong(&g)) { tags->SetTag(TAG_GENRE, tags->GetGenre(g)); } } id3_file_close(fp); #endif // ifdef USE_LIBID3TAG }
void MP3ImportFileHandle::ImportID3(Tags *tags) { #ifdef USE_LIBID3TAG wxFile f; // will be closed when it goes out of scope struct id3_file *fp = NULL; if (f.Open(mFilename)) { // Use id3_file_fdopen() instead of id3_file_open since wxWidgets can open a // file with a Unicode name and id3_file_open() can't (under Windows). fp = id3_file_fdopen(f.fd(), ID3_FILE_MODE_READONLY); } if (!fp) { return; } // The file descriptor is now owned by "fp", so we must tell "f" to forget // about it. f.Detach(); struct id3_tag *tp = id3_file_tag(fp); if (!tp) { id3_file_close(fp); return; } tags->Clear(); // Loop through all frames bool have_year = false; for (int i = 0; i < (int) tp->nframes; i++) { struct id3_frame *frame = tp->frames[i]; // printf("ID: %08x '%4s'\n", (int) *(int *)frame->id, frame->id); // printf("Desc: %s\n", frame->description); // printf("Num fields: %d\n", frame->nfields); // for (int j = 0; j < (int) frame->nfields; j++) { // printf("field %d type %d\n", j, frame->fields[j].type ); // if (frame->fields[j].type == ID3_FIELD_TYPE_STRINGLIST) { // printf("num strings %d\n", frame->fields[j].stringlist.nstrings); // } // } wxString n, v; // Determine the tag name if (strcmp(frame->id, ID3_FRAME_TITLE) == 0) { n = TAG_TITLE; } else if (strcmp(frame->id, ID3_FRAME_ARTIST) == 0) { n = TAG_ARTIST; } else if (strcmp(frame->id, ID3_FRAME_ALBUM) == 0) { n = TAG_ALBUM; } else if (strcmp(frame->id, ID3_FRAME_TRACK) == 0) { n = TAG_TRACK; } else if (strcmp(frame->id, ID3_FRAME_YEAR) == 0) { // LLL: When libid3tag encounters the "TYER" tag, it converts it to a // "ZOBS" (obsolete) tag and adds a "TDRC" tag at the end of the // list of tags using the first 4 characters of the "TYER" tag. // Since we write both the "TDRC" and "TYER" tags, the "TDRC" tag // will always be encountered first in the list. We want use it // since the converted "TYER" tag may have been truncated. if (have_year) { continue; } n = TAG_YEAR; have_year = true; } else if (strcmp(frame->id, ID3_FRAME_COMMENT) == 0) { n = TAG_COMMENTS; } else if (strcmp(frame->id, ID3_FRAME_GENRE) == 0) { n = TAG_GENRE; } else { // Use frame description as default tag name. The descriptions // may include several "meanings" separated by "/" characters, so // we just use the first meaning n = UTF8CTOWX(frame->description).BeforeFirst(wxT('/')); } const id3_ucs4_t *ustr = NULL; if (n == TAG_COMMENTS) { ustr = id3_field_getfullstring(&frame->fields[3]); } else if (frame->nfields == 3) { ustr = id3_field_getstring(&frame->fields[1]); if (ustr) { char *str = (char *)id3_ucs4_utf8duplicate(ustr); n = UTF8CTOWX(str); free(str); } ustr = id3_field_getstring(&frame->fields[2]); } else if (frame->nfields >= 2) { ustr = id3_field_getstrings(&frame->fields[1], 0); } if (ustr) { char *str = (char *)id3_ucs4_utf8duplicate(ustr); v = UTF8CTOWX(str); free(str); } if (!n.IsEmpty() && !v.IsEmpty()) { tags->SetTag(n, v); } } // Convert v1 genre to name if (tags->HasTag(TAG_GENRE)) { long g = -1; if (tags->GetTag(TAG_GENRE).ToLong(&g)) { tags->SetTag(TAG_GENRE, tags->GetGenre(g)); } } id3_file_close(fp); #endif // ifdef USE_LIBID3TAG }
static context * context_create(const char *filename) { context *node = (context *) malloc(sizeof(context)); context *ptr, *last; int last_id = INT_MAX; node->refcount = 1; { struct id3_file *file; struct id3_tag *tag; unsigned int i; file = id3_file_open(filename, ID3_FILE_MODE_READONLY); if (!file) { fprintf(stderr, "Unable to open tagged file %s: %s\n", filename, strerror(errno)); goto fail_free; } tag = id3_file_tag(file); if (!tag) { fprintf(stderr, "Unable to find ID3v2 tags in file %s\n", filename); id3_file_close(file); goto fail_free; } node->tag = id3_tag_new(); for (i = 0; i < id3_tag_get_numframes(tag); i++) if (!strcmp(id3_frame_id(id3_tag_get_frame(tag, i)), "APIC")) id3_tag_attachframe(node->tag, id3_tag_get_frame(tag, i)); id3_file_close(file); } node->filename = strdup(filename); if (!id3_ctxs) { node->id = 1; node->next = NULL; id3_ctxs = node; return node; } ptr = id3_ctxs; last = NULL; while (UNLIKELY(ptr && (ptr->id + 1) >= last_id)) { last_id = ptr->id; last = ptr; ptr = ptr->next; } /* Paranoid! this can occur only if there are INT_MAX contexts :) */ if (UNLIKELY(!ptr)) { fprintf(stderr, "Too many open ID3 contexts\n"); goto fail_close; } node->id = ptr->id + 1; if (UNLIKELY(! !last)) { node->next = last->next; last->next = node; } else { node->next = id3_ctxs; id3_ctxs = node; } return node; fail_close: free(node->filename); id3_tag_delete(node->tag); fail_free: free(node); return NULL; }
// This is a shorter and faster version of scanFile(), that only scans the samplerate and number of Channels of the stream. void mpgDecoder::readMetaFromFile( playListItem * pli ) { #ifdef HAVE_MAD // use QFile as input Buffer, which is needed by libMad, cause it cannot detect EOF.... QFile madFile(pli->getFile()); madFile.open( QIODevice::ReadOnly ); unsigned char buffer[65536]; mad_stream scanStream; mad_header scanHeader; mad_stream_init (&scanStream); mad_header_init (&scanHeader); // get some more Byte from File... int readCnt = 0; while( !madFile.atEnd() && readCnt < 65536 ) { buffer[readCnt] = madFile.read(1).at(0); readCnt++; } if (madFile.atEnd()) return; mad_stream_buffer (&scanStream, buffer, readCnt ); while (1) { if (mad_header_decode (&scanHeader, &scanStream) == -1) { if (scanStream.error == MAD_ERROR_BUFLEN) break; if (!MAD_RECOVERABLE (scanStream.error)) break; continue; } } pli->setSamplerate( scanHeader.samplerate ); pli->setChannels( MAD_NCHANNELS(&scanHeader) ); mad_header_finish (&scanHeader); mad_stream_finish (&scanStream); #endif // read ID3 Metadata #ifdef HAVE_ID3TAG id3_file* id3f = id3_file_open( pli->getFile().toAscii(), ID3_FILE_MODE_READONLY ); id3_tag* id3 = id3_file_tag( id3f ); // only overwrite metadata of playlist-item if files contains own ones... QString temp = getID3String(id3, ID3_FRAME_ARTIST); if(!temp.isEmpty()) pli->setArtist( temp ); temp = getID3String(id3, ID3_FRAME_TITLE); if(!temp.isEmpty()) pli->setTitle( temp ); temp = getID3String(id3, ID3_FRAME_GENRE); if(!temp.isEmpty()) pli->setGenre( temp ); id3_file_close( id3f ); #endif }
int mp3_get_tag (Private * h, char *path, struct SongDBEntry *e) { FILE *fd; mp3Private *mp3_priv = (mp3Private *) h; int length = 0; long size = 0; char *empty = strdup (""); char *title = NULL, *artist = NULL, *album = NULL; char *comment = NULL, *year = NULL, *genre = NULL; if( h == NULL || path == NULL || e ==NULL) return ERROR_INVALID_ARG; { struct id3_file *id3file; struct id3_tag *id3tag; id3_ucs4_t *ucs4; id3_latin1_t *latin1; struct id3_frame *frame; id3file = id3_file_open ( path, ID3_FILE_MODE_READONLY); if (id3file == NULL) { ERROR("get_tag: Error opening file: %s", strerror (errno)); return -1; } id3tag = id3_file_tag (id3file); frame = id3_tag_findframe (id3tag, ID3_FRAME_TITLE, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings ((union id3_field const *) &frame->fields[1], 0); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { title = strdup (latin1); } } } frame = id3_tag_findframe (id3tag, ID3_FRAME_ARTIST, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings (&frame->fields[1], 0); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { artist = strdup (latin1); } } } frame = id3_tag_findframe ((struct id3_tag const *) id3tag, ID3_FRAME_ALBUM, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings (&frame->fields[1], 0); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { album = strdup (latin1); } } } frame = id3_tag_findframe ((struct id3_tag const *) id3tag, ID3_FRAME_COMMENT, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings (&frame->fields[1], 0); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { comment = strdup (latin1); } } } frame = id3_tag_findframe ((struct id3_tag const *) id3tag, ID3_FRAME_YEAR, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings (&frame->fields[1], 0); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { year = strdup (latin1); } } } frame = id3_tag_findframe ((struct id3_tag const *) id3tag, ID3_FRAME_GENRE, 0); if (frame != NULL) { ucs4 = (id3_ucs4_t *) id3_field_getstrings (&frame->fields[1], 0); if (ucs4 != NULL) { ucs4 = (id3_ucs4_t *) id3_genre_name (ucs4); if (ucs4 != NULL) { latin1 = id3_ucs4_latin1duplicate (ucs4); if (latin1 != NULL) { genre = strdup (latin1); } } } } id3_file_close (id3file); } e->title = title; e->artist = artist; e->album = album; e->comment = comment; e->year = year; e->genre = genre; /* length calculation stuff */ { struct mad_header header; struct xing xing; if( e->AddInfo == NULL ) { e->AddInfo = malloc( sizeof(struct SongAddInfo) ); if( e->AddInfo == NULL) return ERROR_NO_MEMORY; memset( e->AddInfo, 0, sizeof( struct SongAddInfo )); } fd = fopen ( path, "rb"); if (fd == NULL) { ERROR("get_tag: Error opening file %s:%s", path, strerror (errno)); return ERROR_OPEN_ERROR; } fseek(fd,0,SEEK_END); size=ftell(fd); fseek(fd,0,SEEK_SET); e->filesize = size; if (scan_header (fd, &header, &xing) == -1) { fclose (fd); // printf ("get_tag: Error Reading File\n"); return ERROR_READ_SEEK_ERROR; } switch( header.layer ) { case MAD_LAYER_I: e->AddInfo->type = str_mpeg1_l1; break; case MAD_LAYER_II: e->AddInfo->type = str_mpeg1_l2; break; case MAD_LAYER_III: if( header.flags & MAD_FLAG_MPEG_2_5_EXT ) e->AddInfo->type = str_mpeg25_l3; else e->AddInfo->type = str_mpeg1_l3; break; default: e->AddInfo->type = NULL; break; } e->AddInfo->n_ch = MAD_NCHANNELS(&header); e->AddInfo->SampleRate = header.samplerate; e->AddInfo->bitrate = header.bitrate; e->AddInfo->err_protection = ((header.flags & MAD_FLAG_PROTECTION) >0); e->AddInfo->copyright = ((header.flags & MAD_FLAG_COPYRIGHT) >0); e->AddInfo->original = ((header.flags & MAD_FLAG_ORIGINAL) >0); fseek (fd, 0, SEEK_SET); // bitrate = 0; if (xing.flags & XING_FRAMES) { mad_timer_t timer; timer = header.duration; mad_timer_multiply (&timer, xing.frames); length = mad_timer_count (timer, MAD_UNITS_MILLISECONDS); /* if (xing.flags & XING_BYTES) bitrate = xing.bytes * 8 / length; */ // printf ("XING header w/ XING_FRAMES found. length = %d\n", length); } else { if (!cfg->lengthcalc) length = (size * 8 / (header.bitrate / 1000)); /* est. */ else { fseek (fd, 0, SEEK_SET); scan_file (fd, &length, NULL); } } e->time = length; mp3_priv->length = length; } fclose (fd); mp3_priv->size = size; mp3_priv->position = 0; return 1; }
void Tags::ImportID3(wxString fileName) { #ifdef USE_LIBID3TAG struct id3_file *fp = id3_file_open(OSFILENAME(fileName), ID3_FILE_MODE_READONLY); if (!fp) return; struct id3_tag *tp = id3_file_tag(fp); if (!tp) return; mTitle = GetID3FieldStr(tp, ID3_FRAME_TITLE); mArtist = GetID3FieldStr(tp, ID3_FRAME_ARTIST); mAlbum = GetID3FieldStr(tp, ID3_FRAME_ALBUM); mYear = GetID3FieldStr(tp, ID3_FRAME_YEAR); mComments = GetID3FieldStr(tp, ID3_FRAME_COMMENT); long l; wxString s; if ((s = GetID3FieldStr(tp, ID3_FRAME_TRACK)).ToLong(&l)) mTrackNum = l; mID3V2 = ( tp->options & ID3_TAG_OPTION_ID3V1 ) ? false : true; s = GetID3FieldStr(tp, ID3_FRAME_GENRE); if( mID3V2 ) { int numGenres = GetNumGenres(); for(int i=0; i<numGenres; i++) if (0 == s.CmpNoCase(GetGenreNum(i))) mGenre = i; } else { if( s.ToLong( &l ) ) mGenre = l; } // Loop through all remaining frames int i; for(i=0; i<(int)tp->nframes; i++) { struct id3_frame *frame = tp->frames[i]; //printf("ID: %08x '%4s'\n", (int) *(int *)frame->id, frame->id); //printf("Desc: %s\n", frame->description); //printf("Num fields: %d\n", frame->nfields); if (!strcmp(frame->id, ID3_FRAME_TITLE) || !strcmp(frame->id, ID3_FRAME_ARTIST) || !strcmp(frame->id, ID3_FRAME_ALBUM) || !strcmp(frame->id, ID3_FRAME_YEAR) || !strcmp(frame->id, ID3_FRAME_COMMENT) || !strcmp(frame->id, ID3_FRAME_GENRE) || !strcmp(frame->id, ID3_FRAME_TRACK)) { continue; } const id3_ucs4_t *ustr; if (frame->nfields>=2) { ustr = id3_field_getstrings(&frame->fields[1], 0); if (ustr) { wxString name = UTF8CTOWX(frame->description); char *str = (char *)id3_ucs4_utf8duplicate(ustr); wxString value = UTF8CTOWX(str); free(str); mExtraNames.Add(name); mExtraValues.Add(value); } } if (frame->nfields==3) { wxString name, value; ustr = id3_field_getstring(&frame->fields[2]); if (ustr) { char *str = (char *)id3_ucs4_utf8duplicate(ustr); value = UTF8CTOWX(str); free(str); } ustr = id3_field_getstring(&frame->fields[1]); if (ustr) { char *str = (char *)id3_ucs4_utf8duplicate(ustr); name = UTF8CTOWX(str); free(str); } mExtraNames.Add(name); mExtraValues.Add(value); } } id3_file_close(fp); #endif // ifdef USE_LIBID3TAG }
void DecodeTag(PLAYERINFO* playerinfo) { const PLAYERDECODE* decode = &playerinfo->decode; AVFormatContext* format = decode->format; AVCodecContext* context = decode->context; PLAYERTAG* playertag = &playerinfo->tag; if (playertag->read) return; if (format != NULL && context != NULL) { const AVCodecDescriptor* descriptor = context->codec_descriptor; const char* name = descriptor->name; if (name != NULL) { CharToWideChar(name, 3, playertag->ext, 3); _wcsupr_s(playertag->ext, sizeof(playertag->ext) / sizeof(wchar_t)); } if (StrCmp(playertag->ext, L"MP3") == 0) { const char* filename = playerinfo->filename; id3_file* file = id3_file_open(filename, ID3_FILE_MODE_READONLY); id3_tag* tag = id3_file_tag(file); if (tag != NULL && tag->nframes > 0) { wchar_t* title = GetMP3Tag(tag, ID3_FRAME_TITLE); if (title == NULL) title = GetMP3Tag(tag, ID3_FRAME_ALBUM); wchar_t* artist = GetMP3Tag(tag, ID3_FRAME_ARTIST); playertag->artist = artist; playertag->title = title; } SAFE_DELETE_ARRAY(file->path); id3_file_close(file); } else { AVDictionary* dictionary = format->metadata; if (dictionary != NULL) { AVDictionaryEntry* entry = av_dict_get(dictionary, "title", NULL, 0); if (entry != NULL && entry->value != NULL) { wchar_t* title = UTF8toWideChar(entry->value, strlen(entry->value)); playertag->title = title; } else { entry = av_dict_get(dictionary, "album", NULL, 0); if (entry != NULL && entry->value != NULL) { wchar_t* title = UTF8toWideChar(entry->value, strlen(entry->value)); playertag->title = title; } } entry = av_dict_get(dictionary, "artist", NULL, 0); if (entry != NULL && entry->value != NULL) { wchar_t* artist = UTF8toWideChar(entry->value, strlen(entry->value)); playertag->artist = artist; } } } if (StrCmp(playertag->ext, L"PCM") == 0) StrCpy(playertag->ext, L"WAV"); if (playertag->title == NULL) { SAFE_DELETE_ARRAY(playertag->artist); SplitTag(playerinfo->filename, &playertag->title, &playertag->artist); if (playertag->title == NULL) { wchar_t* title = GetFileName(playerinfo->filename); if (title != NULL) { SplitTitle(title, &playertag->title); if (playertag->title == NULL) playertag->title = title; else SAFE_DELETE_ARRAY(title); } } if (playertag->title != NULL) { wchar_t* title = playertag->title; wchar_t* first = NULL; wchar_t* second = NULL; Split(title, L".", &first, &second); if (first != NULL && second != NULL) { if (IsNumber(first)) { SAFE_DELETE_ARRAY(title); playertag->title = second; } else { SAFE_DELETE_ARRAY(second); } SAFE_DELETE_ARRAY(first); } } } long duration = format->duration / 1000; playerinfo->duration = duration; duration = duration / 1000; long minute = duration / 60; long second = duration % 60; wsprintf(playertag->timer, L"%d:%02d", minute, second); wsprintf(playertag->sample, L"%dHz", context->sample_rate); if (context->bit_rate > 0) wsprintf(playertag->bitrate, L"%dkbps", context->bit_rate / 1000); else wsprintf(playertag->bitrate, L"%dkbps", format->bit_rate / 1000); switch (context->channels) { case 1: StrCpy(playertag->channels, L"单声道"); break; case 4: StrCpy(playertag->channels, L"四声道"); break; case 5: StrCpy(playertag->channels, L"4.1声道"); break; case 6: StrCpy(playertag->channels, L"5.1声道"); break; case 7: StrCpy(playertag->channels, L"6.1声道"); break; case 8: StrCpy(playertag->channels, L"7.1声道"); break; default: StrCpy(playertag->channels, L"立体声"); break; } } playertag->read = TRUE; }
JNIEXPORT jstring JNICALL Java_com_ssb_droidsound_utils_ID3Tag_getStringInfo(JNIEnv *env, jobject obj, jint what) { struct id3_file *id3file = (struct id3_file*)env->GetLongField(obj, refField); struct id3_tag *tag = (struct id3_tag*)env->GetLongField(obj, tagRefField); __android_log_print(ANDROID_LOG_VERBOSE, "ID3Tag", "Get String Info %p %p", id3file, tag); if(!tag && id3file) tag = id3_file_tag(id3file); if(!tag) return 0; const id3_ucs4_t *title = NULL; struct id3_frame *frame = NULL; __android_log_print(ANDROID_LOG_VERBOSE, "ID3Tag", "id3tag %p", tag); switch(what) { case INFO_TITLE: frame = id3_tag_findframe(tag, ID3_FRAME_TITLE, 0); break; case INFO_AUTHOR: frame = id3_tag_findframe(tag, ID3_FRAME_ARTIST, 0); break; case INFO_COPYRIGHT: frame = id3_tag_findframe(tag, ID3_FRAME_YEAR, 0); break; case ID3INFO_GENRE: frame = id3_tag_findframe(tag, ID3_FRAME_GENRE, 0); if(frame) { title = id3_field_getstrings(&frame->fields[1], 0); title = id3_genre_name(title); } break; case ID3INFO_ALBUM: frame = id3_tag_findframe(tag, ID3_FRAME_ALBUM, 0); break; case ID3INFO_TRACK: frame = id3_tag_findframe(tag, ID3_FRAME_TRACK, 0); break; case ID3INFO_COMMENT: frame = id3_tag_findframe(tag, ID3_FRAME_COMMENT, 0); if(frame) { __android_log_print(ANDROID_LOG_VERBOSE, "ID3Tag", "COMMENT %d fields", frame->nfields); if(frame->nfields >= 4) title = id3_field_getfullstring(&frame->fields[3]); } break; } if(frame) { __android_log_print(ANDROID_LOG_VERBOSE, "ID3Tag", "frame %p %d", frame, what); if(title == NULL) title = id3_field_getstrings(&frame->fields[1], 0); if(title) { __android_log_print(ANDROID_LOG_VERBOSE, "ID3Tag", "title %p", title); id3_utf8_t *titleu8 = id3_ucs4_utf8duplicate(title); jstring j = env->NewStringUTF((const char *)titleu8); return j; } } return NULL; }
static int _get_mp3tags(char *file, struct song_metadata *psong) { struct id3_file *pid3file; struct id3_tag *pid3tag; struct id3_frame *pid3frame; int err; int index; int used; unsigned char *utf8_text; int genre = WINAMP_GENRE_UNKNOWN; int have_utf8; int have_text; id3_ucs4_t const *native_text; char *tmp; int got_numeric_genre; id3_byte_t const *image; id3_length_t image_size = 0; pid3file = id3_file_open(file, ID3_FILE_MODE_READONLY); if(!pid3file) { DPRINTF(E_ERROR, L_SCANNER, "Cannot open %s\n", file); return -1; } pid3tag = id3_file_tag(pid3file); if(!pid3tag) { err = errno; id3_file_close(pid3file); errno = err; DPRINTF(E_WARN, L_SCANNER, "Cannot get ID3 tag for %s\n", file); return -1; } index = 0; while((pid3frame = id3_tag_findframe(pid3tag, "", index))) { used = 0; utf8_text = NULL; native_text = NULL; have_utf8 = 0; have_text = 0; if(!strcmp(pid3frame->id, "YTCP")) /* for id3v2.2 */ { psong->compilation = 1; DPRINTF(E_DEBUG, L_SCANNER, "Compilation: %d [%s]\n", psong->compilation, basename(file)); } else if(!strcmp(pid3frame->id, "APIC") && !image_size) { if( (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpeg") == 0) || (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpg") == 0) || (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "jpeg") == 0) #if HAVE_LIBPNG || (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/png") == 0) || (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "png") == 0) #endif ) { image = id3_field_getbinarydata(&pid3frame->fields[4], &image_size); if( image_size ) { psong->image = malloc(image_size); memcpy(psong->image, image, image_size); psong->image_size = image_size; //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Found thumbnail: %d\n", psong->image_size); } } } if(((pid3frame->id[0] == 'T') || (strcmp(pid3frame->id, "COMM") == 0)) && (id3_field_getnstrings(&pid3frame->fields[1]))) have_text = 1; if(have_text) { native_text = id3_field_getstrings(&pid3frame->fields[1], 0); if(native_text) { have_utf8 = 1; if(lang_index >= 0) utf8_text = _get_utf8_text(native_text); // through iconv else utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text); if(!strcmp(pid3frame->id, "TIT2")) { used = 1; psong->title = (char*)utf8_text; } else if(!strcmp(pid3frame->id, "TPE1")) { used = 1; psong->contributor[ROLE_ARTIST] = (char*)utf8_text; } else if(!strcmp(pid3frame->id, "TALB")) { used = 1; psong->album = (char*)utf8_text; } else if(!strcmp(pid3frame->id, "TCOM")) { used = 1; psong->contributor[ROLE_COMPOSER] = (char*)utf8_text; } else if(!strcmp(pid3frame->id, "TIT1")) { used = 1; psong->grouping = (char*)utf8_text; } else if(!strcmp(pid3frame->id, "TPE2")) { used = 1; psong->contributor[ROLE_BAND] = (char*)utf8_text; } else if(!strcmp(pid3frame->id, "TPE3")) { used = 1; psong->contributor[ROLE_CONDUCTOR] = (char*)utf8_text; } else if(!strcmp(pid3frame->id, "TCON")) { used = 1; psong->genre = (char*)utf8_text; got_numeric_genre = 0; if(psong->genre) { if(!strlen(psong->genre)) { genre = WINAMP_GENRE_UNKNOWN; got_numeric_genre = 1; } else if(isdigit(psong->genre[0])) { genre = atoi(psong->genre); got_numeric_genre = 1; } else if((psong->genre[0] == '(') && (isdigit(psong->genre[1]))) { genre = atoi((char*)&psong->genre[1]); got_numeric_genre = 1; } if(got_numeric_genre) { if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN)) genre = WINAMP_GENRE_UNKNOWN; free(psong->genre); psong->genre = strdup(winamp_genre[genre]); } } } else if(!strcmp(pid3frame->id, "COMM")) { used = 1; psong->comment = (char*)utf8_text; } else if(!strcmp(pid3frame->id, "TPOS")) { tmp = (char*)utf8_text; strsep(&tmp, "/"); if(tmp) { psong->total_discs = atoi(tmp); } psong->disc = atoi((char*)utf8_text); } else if(!strcmp(pid3frame->id, "TRCK")) { tmp = (char*)utf8_text; strsep(&tmp, "/"); if(tmp) { psong->total_tracks = atoi(tmp); } psong->track = atoi((char*)utf8_text); } else if(!strcmp(pid3frame->id, "TDRC")) { psong->year = atoi((char*)utf8_text); } else if(!strcmp(pid3frame->id, "TLEN")) { psong->song_length = atoi((char*)utf8_text); } else if(!strcmp(pid3frame->id, "TBPM")) { psong->bpm = atoi((char*)utf8_text); } else if(!strcmp(pid3frame->id, "TCMP")) { psong->compilation = (char)atoi((char*)utf8_text); } } } // check if text tag if((!used) && (have_utf8) && (utf8_text)) free(utf8_text); // v2 COMM if((!strcmp(pid3frame->id, "COMM")) && (pid3frame->nfields == 4)) { native_text = id3_field_getstring(&pid3frame->fields[2]); if(native_text) { utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text); if((utf8_text) && (strncasecmp((char*)utf8_text, "iTun", 4) != 0)) { // read comment free(utf8_text); native_text = id3_field_getfullstring(&pid3frame->fields[3]); if(native_text) { utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text); if(utf8_text) { free(psong->comment); psong->comment = (char*)utf8_text; } } } else { free(utf8_text); } } } index++; } id3_file_close(pid3file); //DEBUG DPRINTF(E_INFO, L_SCANNER, "Got id3 tag successfully for file=%s\n", file); return 0; }