//following routine courtesy of John George size_t ID3_GetPictureDataOfPicType(ID3_Tag* tag, const char* TempPicPath, ID3_PictureType pictype) { if (NULL == tag) return 0; else { ID3_Frame* frame = NULL; ID3_Tag::Iterator* iter = tag->CreateIterator(); while (NULL != (frame = iter->GetNext() )) { if(frame->GetID() == ID3FID_PICTURE) { if(frame->GetField(ID3FN_PICTURETYPE)->Get() == (uint32)pictype) break; } } delete iter; if (frame != NULL) { ID3_Field* myField = frame->GetField(ID3FN_DATA); if (myField != NULL) { myField->ToFile(TempPicPath); return (size_t)myField->Size(); } else return 0; } else return 0; } }
//following routine courtesy of John George char* ID3_GetDescriptionOfPicType(ID3_Tag* tag, ID3_PictureType pictype) { char* sPicDescription = NULL; if (NULL == tag) return sPicDescription; ID3_Frame* frame = NULL; ID3_Tag::Iterator* iter = tag->CreateIterator(); while (NULL != (frame = iter->GetNext())) { if(frame->GetID() == ID3FID_PICTURE) { if(frame->GetField(ID3FN_PICTURETYPE)->Get() == (uint32)pictype) break; } } delete iter; if (frame != NULL) { sPicDescription = ID3_GetString(frame, ID3FN_DESCRIPTION); } return sPicDescription; }
//following routine courtesy of John George size_t ID3_RemovePictureType(ID3_Tag* tag, ID3_PictureType pictype) { size_t bremoved = 0; ID3_Frame* frame = NULL; if (NULL == tag) return bremoved; ID3_Tag::Iterator* iter = tag->CreateIterator(); while (NULL != (frame = iter->GetNext())) { if (frame->GetID() == ID3FID_PICTURE) { if (frame->GetField(ID3FN_PICTURETYPE)->Get() == (uint32)pictype) break; } } delete iter; if (NULL != frame) { frame = tag->RemoveFrame(frame); delete frame; bremoved = 1; } return bremoved; }
ID3_Frame* ID3_AddComment(ID3_Tag *tag, const char *text, const char *desc, const char* lang, bool replace) { ID3_Frame* frame = NULL; if (NULL != tag && NULL != text && NULL != desc && strlen(text) > 0) { bool bAdd = true; if (replace) { ID3_RemoveComments(tag, desc); } else { // See if there is already a comment with this description ID3_Tag::Iterator* iter = tag->CreateIterator(); ID3_Frame* frame = NULL; while ((frame = iter->GetNext()) != NULL) { if (frame->GetID() == ID3FID_COMMENT) { char *tmp_desc = ID3_GetString(frame, ID3FN_DESCRIPTION); if (strcmp(tmp_desc, desc) == 0) { bAdd = false; } delete [] tmp_desc; if (!bAdd) { break; } } } delete iter; } if (bAdd) { frame = new ID3_Frame(ID3FID_COMMENT); if (NULL != frame) { frame->GetField(ID3FN_LANGUAGE)->Set(lang); frame->GetField(ID3FN_DESCRIPTION)->Set(desc); frame->GetField(ID3FN_TEXT)->Set(text); tag->AttachFrame(frame); } } } return frame; }
// Remove all comments with the given description (remove all comments if // desc is NULL) size_t ID3_RemoveComments(ID3_Tag *tag, const char *desc) { size_t num_removed = 0; if (NULL == tag) { return num_removed; } ID3_Tag::Iterator* iter = tag->CreateIterator(); ID3_Frame* frame = NULL; while ((frame = iter->GetNext()) != NULL) { if (frame->GetID() == ID3FID_COMMENT) { bool remove = false; // A null description means remove all comments if (NULL == desc) { remove = true; } else { // See if the description we have matches the description of the // current comment. If so, set the "remove the comment" flag to true. char *tmp_desc = ID3_GetString(frame, ID3FN_DESCRIPTION); remove = (strcmp(tmp_desc, desc) == 0); delete [] tmp_desc; } if (remove) { frame = tag->RemoveFrame(frame); delete frame; num_removed++; } } } delete iter; return num_removed; }
//*************************************************************************** bool Kwave::MP3Decoder::parseID3Tags(ID3_Tag &tag) { if (tag.NumFrames() < 1) return true; // no tags, nothing to do QDate creation_date; QTime creation_time; int year = -1; int month = -1; int day = -1; ID3_Tag::Iterator *it = tag.CreateIterator(); ID3_Frame *frame = 0; Kwave::FileInfo info(metaData()); while (it && (frame = it->GetNext())) { const ID3_FrameID id = frame->GetID(); const Kwave::FileProperty property = m_property_map.property(id); const ID3_PropertyMap::Encoding encoding = m_property_map.encoding(id); switch (encoding) { case ID3_PropertyMap::ENC_TEXT_PARTINSET: { QString s = parseId3Frame2String(frame); int cd = 0; int cds = 0; if (s.contains(QLatin1Char('/'))) { int i = s.indexOf(QLatin1Char('/')); cd = s.left(i).toInt(); cds = s.mid(i + 1).toInt(); } else { cd = s.toInt(); } if (cd > 0) info.set(Kwave::INF_CD , QVariant(cd)); if (cds > 0) info.set(Kwave::INF_CDS, QVariant(cds)); break; } case ID3_PropertyMap::ENC_TRACK_NUM: { QString s = parseId3Frame2String(frame); int track = 0; int tracks = 0; if (s.contains(QLatin1Char('/'))) { int i = s.indexOf(QLatin1Char('/')); track = s.left(i).toInt(); tracks = s.mid(i + 1).toInt(); } else { track = s.toInt(); } if (track > 0) info.set(Kwave::INF_TRACK , QVariant(track)); if (tracks > 0) info.set(Kwave::INF_TRACKS, QVariant(tracks)); break; } case ID3_PropertyMap::ENC_TERMS_OF_USE: // the same as ENC_COMMENT, but without "Description" /* FALLTHROUGH */ case ID3_PropertyMap::ENC_COMMENT: { QString s = parseId3Frame2String(frame); // optionally prepend language char *lang = ID3_GetString(frame, ID3FN_LANGUAGE); if (lang) { s = _("[") + _(lang) + _("] ") + s; ID3_FreeString(lang); } // append to already existing tag, separated by a slash if (info.contains(property)) s = info.get(property).toString() + _(" / ") + s; info.set(property, QVariant(s)); break; } case ID3_PropertyMap::ENC_GENRE_TYPE: { QString s = parseId3Frame2String(frame); int genre = Kwave::GenreType::fromID3(s); if (genre >= 0) s = Kwave::GenreType::name(genre, false); info.set(property, QVariant(s)); break; } case ID3_PropertyMap::ENC_LENGTH: { // length in ms -> convert this to samples QString s = parseId3Frame2String(frame); const double rate = info.rate(); bool ok = false; const double ms = s.toDouble(&ok) + 0.5; if (ok && (rate > 0)) { // NOTE: this overwrites the length found in the header! sample_index_t length = static_cast<sample_index_t>( (rate * ms) / 1000.0); info.setLength(length); } break; } case ID3_PropertyMap::ENC_TEXT_TIMESTAMP: { if (!creation_date.isValid()) { QString s = parseId3Frame2String(frame); switch (id) { case ID3FID_RECORDINGDATES: // should be a ISO 8601 timestamp or similar s = Kwave::string2date(s); if (s.length()) creation_date = QDate::fromString(s, Qt::ISODate); break; case ID3FID_DATE: { // DDMM unsigned int ddmm = s.toUInt(); day = ddmm / 100; month = ddmm % 100; break; } case ID3FID_YEAR: /* FALLTHROUGH */ case ID3FID_ORIGYEAR: // YYYY year = s.toUInt(); break; default: break; } } if (creation_time.isValid()) { switch (id) { case ID3FID_TIME: creation_time = QTime::fromString(_("hhmm")); break; default: break; } } break; } case ID3_PropertyMap::ENC_TEXT_SLASH: { // append to already existing tag, separated by a slash QString s = parseId3Frame2String(frame); if (info.contains(property)) s = info.get(property).toString() + _(" / ") + s; info.set(property, QVariant(s)); break; } case ID3_PropertyMap::ENC_TEXT_URL: /* FALLTHROUGH */ case ID3_PropertyMap::ENC_TEXT: info.set(property, QVariant(parseId3Frame2String(frame))); break; case ID3_PropertyMap::ENC_NONE: /* FALLTHROUGH */ default: { QString s = parseId3Frame2String(frame); qWarning("unsupported ID3 tag: %d, descr: '%s', text: '%s'", id, frame->GetDescription(), DBG(s)); break; } } } /* * try to build a valid creation date/time */ if (!creation_date.isValid()) { // no complete creation date - try to reassemble from found y/m/d creation_date = QDate(year, month, day); } if (creation_date.isValid() && creation_time.isValid()) { // full date + time QDateTime dt(creation_date, creation_time); info.set(Kwave::INF_CREATION_DATE, dt.toString( _("yyyy-MM-ddTHH:mm:ss"))); } else if (creation_date.isValid()) { // date without time info.set(Kwave::INF_CREATION_DATE, creation_date.toString( _("yyyy-MM-dd"))); } else if (year > 0) { // only year creation_date = QDate(year, 1, 1); info.set(Kwave::INF_CREATION_DATE, creation_date.toString(_("yyyy"))); } metaData().replace(Kwave::MetaDataList(info)); return true; }
MP3Data * MP3DataGenerator::readMetadata( const char * p_filePath) { // Set up file connection. myID3_Tag = new ID3_Tag(); myID3_Tag->Link( p_filePath); // Storage with default initialization. MP3Data * myMP3Data = new MP3Data(); myMP3Data->setAll( "<undefinded>"); // Retrieve metadata. ID3_Tag::Iterator * tagIter = myID3_Tag->CreateIterator(); ID3_Frame * myFrame = NULL; while( NULL != ( myFrame = tagIter->GetNext())) { if( NULL != myFrame) { ID3_Field * myField = myFrame->GetField( ID3FN_TEXT); // Check if current frame is part of the set aka a field of interest. std::set<ID3_FrameID>::iterator current = interestingID3_FrameIDs->find( myFrame->GetID()); if ( NULL != myField && current != interestingID3_FrameIDs->end()) { ID3_FrameID_LUT * myLUT = new ID3_FrameID_LUT(); std::string frameRealname = std::string( myLUT->getRealname( myFrame->GetID())); // @TODO Show encoding in gui (optional) if( myField->GetEncoding() == ID3TE_ASCII || ID3TE_ISO8859_1) { encoding += frameRealname + ": ISO8859_1 , "; // Genre needs to be converted. if( myFrame->GetID() == ID3FID_CONTENTTYPE) // ID3_FrameID = 32 { const char * genre = myField->GetRawText(); // ID3V1 genre has is an int surrounded by round brackets; ID3V2 genre is text. unsigned int genreIntegerAlias = removeBrackets( genre); if( genreIntegerAlias < ID3_NR_OF_V1_GENRES && genre[0] == '(') myMP3Data->setGenre( ID3_v1_genre_description[ genreIntegerAlias]); else myMP3Data->setGenre( genre); } // All other tags. else if( myFrame->GetID() == ID3FID_TITLE) myMP3Data->setTitle( myField->GetRawText()); else if( myFrame->GetID() == ID3FID_ALBUM) myMP3Data->setAlbum( myField->GetRawText()); else if( myFrame->GetID() == ID3FID_YEAR) myMP3Data->setYear( myField->GetRawText()); else if( myFrame->GetID() == ID3FID_TRACKNUM) myMP3Data->setTracknumber( myField->GetRawText()); else if( myFrame->GetID() == ID3FID_LEADARTIST) myMP3Data->setArtist( myField->GetRawText()); } else if( myField->GetEncoding() == ID3TE_UTF8) { encoding += frameRealname + ": utf8 , "; myMP3Data->setAll( "<unicode utf8 encoding>"); } else if( myField->GetEncoding() == ID3TE_UNICODE || ID3TE_UTF16) { encoding += frameRealname + ": utf16 ,"; // @TODO Conversion to std::string ... myField->GetRawUnicodeText(); myMP3Data->setAll( "<unicode utf16 encoding>"); } else if( myField->GetEncoding() == ID3TE_UTF16BE) { encoding += frameRealname + ": utf16be , "; myMP3Data->setAll( "<unicode utf16be encoding>"); } else if( myField->GetEncoding() == ID3TE_NUMENCODINGS) { encoding += frameRealname + ": numencodings , "; myMP3Data->setAll( "<numencoding>"); } else { encoding += frameRealname + ": unknown , "; myMP3Data->setAll( "<<unknown encoding>"); } } } } // Retrieve file path and file name. myMP3Data->setFilepath( p_filePath); myMP3Data->setFilename( getFilename( p_filePath).c_str()); return myMP3Data; }
void MP3TagReader::ImportTags(MatroskaTagInfo *target) { #ifdef USING_ID3LIB // use an std::auto_ptr here to handle object cleanup automatically ID3_Tag::Iterator *iter = m_Tag.CreateIterator(); ID3_Frame *myFrame = NULL; while (NULL != (myFrame = iter->GetNext())) { // do something with myFrame //myFrame; ID3_Field *textField = myFrame->GetField(ID3FN_TEXTENC); ID3_Field *intField = myFrame->GetField(ID3FN_COUNTER); if (myFrame->GetID() == ID3FID_PLAYCOUNTER) { target->Tag_PlayCounter = intField->Get(); } else if (myFrame->GetID() == ID3FID_POPULARIMETER) { target->Tag_Popularimeter = intField->Get(); } else if (myFrame->GetID() == ID3FID_ALBUM) { MatroskaTagMultiTitleItem *newTagItem = new MatroskaTagMultiTitleItem(); newTagItem->Type = KaxTagMultiTitleType_AlbumMovieShowTitle; newTagItem->Name = textField->GetRawUnicodeText(); target->AddMultiTitleItem(newTagItem); } else if (myFrame->GetID() == ID3FID_BPM) { target->Tag_BPM = intField->Get(); } else if (myFrame->GetID() == ID3FID_COMPOSER) { MatroskaTagMultiEntityItem *newTagItem = new MatroskaTagMultiEntityItem(); newTagItem->Type = KaxTagMultiEntitiesType_Composer; newTagItem->Name = textField->GetRawUnicodeText(); target->AddMultiEntityItem(newTagItem); } else if (myFrame->GetID() == ID3FID_PLAYLISTDELAY) { target->Tag_PlaylistDelay = intField->Get(); } else if (myFrame->GetID() == ID3FID_ENCODEDBY) { MatroskaTagMultiEntityItem *newTagItem = new MatroskaTagMultiEntityItem(); newTagItem->Type = KaxTagMultiEntitiesType_EncodedBy; newTagItem->Name = textField->GetRawUnicodeText(); target->AddMultiEntityItem(newTagItem); } else if (myFrame->GetID() == ID3FID_LYRICIST) { MatroskaTagMultiEntityItem *newTagItem = new MatroskaTagMultiEntityItem(); newTagItem->Type = KaxTagMultiEntitiesType_LyricistTextWriter; newTagItem->Name = textField->GetRawUnicodeText(); target->AddMultiEntityItem(newTagItem); } else if (myFrame->GetID() == ID3FID_TITLE) { MatroskaTagMultiTitleItem *newTagItem = new MatroskaTagMultiTitleItem(); newTagItem->Type = KaxTagMultiTitleType_TrackTitle; newTagItem->Name = textField->GetRawUnicodeText(); target->AddMultiTitleItem(newTagItem); } else if (myFrame->GetID() == ID3FID_SUBTITLE) { MatroskaTagMultiTitleItem *newTagItem = new MatroskaTagMultiTitleItem(); newTagItem->Type = KaxTagMultiTitleType_TrackTitle; newTagItem->SubTitle = textField->GetRawUnicodeText(); target->AddMultiTitleItem(newTagItem); } } delete iter; #endif };
void play_debug_meta(char* filename){ ID3_Tag tag(filename); ID3_Tag::Iterator* iter = tag.CreateIterator(); ID3_Frame* frame = NULL; char buf[1000]; // Iconv conversion descriptor: UTF-16 -> UTF-8 iconv_t cd = iconv_open("UTF8","UTF16BE"); while (NULL != (frame = iter->GetNext())) { char* val = NULL; field_text(&val, frame); printf("Frame: type %d %s %s:\n", frame->GetID(), frame->GetTextID(), frame->GetDescription()); ID3_Frame::Iterator* fieldIter = frame->CreateIterator(); ID3_Field* field = NULL; while (NULL != (field = fieldIter->GetNext())) { printf(" Field: type "); ID3_FieldType type = field->GetType(); switch(type) { case ID3FTY_NONE: printf("none"); break; case ID3FTY_INTEGER: printf("int"); break; case ID3FTY_BINARY: printf("binary"); break; case ID3FTY_TEXTSTRING: field->Get(buf, 1000); printf("text with %d items, encoding ", field->GetNumTextItems()); switch(field->GetEncoding()){ case ID3TE_UTF16: printf("UTF-16"); if ( cd != (iconv_t) -1 ) { char* in = (char*) field->GetRawUnicodeText(); size_t insize = field->Size(); char* bufptr = buf; size_t bufsize = 1000; size_t rc = 0; // Initialize iconv state if( iconv(cd, NULL, NULL, &bufptr, &bufsize) == (size_t) -1 ){ printf("iconv init Failed\n"); } if ( (rc = iconv(cd, &in, &insize, &bufptr, &bufsize)) != (size_t) -1 ) { *bufptr = '\0'; printf(": '%s' (%d chars)\n", buf, rc); } else { printf("<conversion using iconv failed>"); perror("iconv"); } } break; case ID3TE_UTF16BE: printf("UTF-16BE"); printf(": '%s'", buf); break; case ID3TE_UTF8: printf("UTF-8"); printf(": '%s'", buf); break; case ID3TE_NONE: printf("none"); printf(": '%s'", buf); break; case ID3TE_ISO8859_1: printf("ISO-8859-1/ASCII"); printf(": '%s'", buf); break; } break; } printf("\n"); } delete fieldIter; delete [] val; } delete iter; iconv_close(cd); }