MP3 Tags auslesen/schreiben - wie?



  • Hallo!

    Seit Neustem spiel ich jetzt auch mit C++ rum, hab eigentlich nur ein wenig Programmiererfahrung mit Java. Was ich mir zuerst vorgenommen habe ist, ein kleines Command-Line-Tool zu schreiben, über welches sich leicht ID3 Tags von MP3-Dateien auslesen bzw. ändern lassen.

    Hier ist mal was ich soweit habe, allerdings verstehe ich die Referenzen zum ID3 Protokoll nicht (zumindest die, die ich gegoogled habe).

    Hier mal ein Test-Code den ich soweit gemacht hab:

    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    struct ID3fields
    {
    	char tag[3];
    	char title[30];
     	char artist[30];
    	char album[30];
    	char year[4];
    	char comment[30];
    	int genre;
    };
    
    ID3fields _getID3Tags(char* file) {
    
    	ID3fields id3f;
    	ifstream mp3File;
    
    	mp3File.open(file);
    	if(!mp3File.is_open())
    		return id3f;
    
    	string line;
    	while(!mp3File.eof()) {
    		getline(mp3File, line);
    	}
    
    	string value = line.substr(line.find("TIT2")+11, line.find("TPE1")-line.find("TIT2")-11);
    
    	for(int i = 0; i < (signed)value.length(); i++) {
    		id3f.artist[i] = value[i];
    		if(i == value.length()-1) {
    			cout << "length: " << i << endl;
    			id3f.artist[i+1] = '\0';
    		}
    	}
    
    	//cout << value << endl;
    
    	mp3File.close();
    
    	return id3f;
    }
    
    void main() {
    
    	ID3fields id3f;
    
    	id3f = _getID3Tags("a.mp3");
    	cout << id3f.artist << endl;
    	id3f = _getID3Tags("d.mp3");
    	cout << id3f.artist << endl;
    	id3f = _getID3Tags("e.mp3");
    	cout << id3f.artist << endl;
    	//_getID3Tags("c.mp3");
    
    }
    

    Komischerweise gibt mir das erstmal die Titel von manchen *.mp3 Dateien aus, für 'a.mp3' sowie 'd.mp3' funktioniert das soweit auch prima, nur bei manchen anderen MP3-Dateien kommt nur irgend ein Kauderwelsch heraus.

    Ich vermute ich geh die Sache komplett falsch an, auch versteh ich nicht so richtig wie man die version des ID3 Tags (v1/v2/v3/v4) feststellt - eventuell funktioniert das auslesen der Titel bei meinen MP3-Dateien nur wenn sie einer bestimmten ID3 Version unterliegen?

    Tipps/Tricks und eventuell kleine Beispielcodes, vll. auch eine gut beschriebene RFC wären super, irgendwie komm ich grad nicht so klar 😉

    Eigentlich hab ich erstmal nur die MP3 eingelesen und ausgegeben, dann geschaut wie die Titel getrennt sind, da kam ca. sowas wie: [...]TIT2[...]Titel Name[...]TPE1[...] heraus, danach hab ich einfach berechnet (funktioniert allerdings nicht bei allen MP3's, wie bereits gesagt), wo der Titel im String liegt und danach halt den Substring rausgezogen (den Titel).

    Grüße,
    ghett0



  • Nimm einfach id3lib.
    Beispielcodeschnippsel:

    #include <id3/tag.h>
    #include <string>
    using namespace std;
    
    static string getGenre(const string& fileName)
    {
        ID3_Tag myTag(fileName.c_str());
        ID3_Frame* myFrame = myTag.Find(ID3FID_CONTENTTYPE);
        if (myFrame)
        {
            ID3_Field* myField = myFrame->GetField(ID3FN_TEXT);
            return myField->GetRawText();
        }
        return "";
    }
    


  • Ja, hab ich schon gegoogled. Allerdings wollt ich das ganze ja zum Lernen selber machen 🙂
    Es gibt ja eigentlich genug gute DLL's und Tools (id3.exe mp3 mass tagger, cddbccontrol.dll, id3lib.dll etc.) um MP3 Dateien zu taggen/tags auszulesen.

    Mfg



  • I did some more research and found out, almost all the data I am looking for is within the last 128 bytes of the file. Each field of that table has 30bytes width, though one just need to grab those.

    What I still need, I have no idea how to grab the track's length 'min:s' from that file. Any suggestions?

    // load a file into memory
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    void _getID3Tag_all(char* file) {
    
    	cout << file << endl;
    
    	char ch;
        ifstream fin(file);
    
    	fin.seekg(-128, ios::end);
    	int now = fin.tellg();
    	cout << now << endl;
    
    	int x = 0;
    	while(fin.get(ch)) {
    		cout << "CHAR: " << ch << " X: " << x << endl;
    		x++;
    	}
        fin.close();
    
    	cout << endl << endl << endl;
    
    }
    
    int main () {
    
    	//12345
    	_getID3Tag_all("a.mp3");
    	_getID3Tag_all("b.mp3");
    	_getID3Tag_all("c.mp3");
    }
    


  • Die Länge steht nicht im Tag, zumindest nicht in V1 Tags. Und V2 Tags sind ungleich schwieriger zu lesen.
    Ich weiss auch nicht ob man aus der MP3-Frame-Header des letzten Frames die Länge raus bekommt. MP3-Frame-Headers sind noch relativ einfach zu finden, Google hilft dir.



  • Einen Einstieg hast du ja schon 😉

    Wenn du es bisher noch nicht gemacht hast, schau mal mit einem Hexeditor auf Dateianfang und -ende. Vergleiche dann die Ergebnisse deines Programms mit dem was dir der Hexeditor zeigt und optimiere dein Programm.

    MfG f.-th.



  • Die Spezifikation der ID3 Tags findest du unter http://www.id3.org

    Ein paar Worte zu deinen Fragen:

    Der ID3 Version 1 Tag steht am Ende der MP3-Datei. Ein ID3 Version 2 Tag hingegen steht unmittelbar am Beginn einer MP3-Datei. Eine MP3-Datei kann entweder keinen, einen, oder beide Versionen eines ID3-Tags beinhalten.

    Der Version 1 Tag ist sehr viel leichter zu lesen und zu schreiben, hat allerdings nur sehr limitierten Funktionsumfang (fixe maximale Länge der Strings, kein Support für Coverbilder, Songtexte, Unicode-Kodierung etc.). ID3 Version 2 Tags können sehr viel mehr, sind jedoch auch um sehr viel aufwändiger zu implementieren (mehrere tausend Codezeilen für eine vollständige Implementierung).

    Der aktuelle Standard sind ID3 Tags Version 2.4, trotzdem ist die ID3 Version 2.3 aus diversen Gründen bis heute die am meisten verwendete. ID3 Tags in den Versionen 1.0, 1.1, und 2.2 sind veraltet. ID3 Tags in den Versionen 2.0 und 2.1 existieren übrigens nicht.

    Die Länge einer MP3-Datei ist leider ebenfalls nicht ganz einfach zu berechnen. Zuerst muss zwischen einer CBR (konstante Bitrate) oder VBR bzw. ABR (variable Bitrate) kodierten MP3-Datei unterschieden werden. Bei einer CBR MP3 kann die Bitrate einfach über den Header des ersten MP3 Frames ausgelesen werden. Zusammen mit der Größe der Datei (bzw. der Audiodaten) kann dann die Länge der MP3 berechnet werden.

    Bei einer VBR MP3 hat es sich etabliert, einen sogenannten VBR-Header am Anfang der MP3 zu kodieren, der die Anzahl der Frames enthält. Zusammen mit der Samplingrate lässt sich hier wiederum die Länge der MP3 berechnen.

    Problematisch sind VBR MP3's ohne VBR-Header. Bei diesen müssen die Frame-Header der gesamten MP3 durchgeparst werden, um die Anzahl der Frames bzw. die durchschnittliche Bitrate ausfindig zu machen. Dies ist zum einen langsam, und zum anderen etwas aufwändig zu implementieren. Einige Programme können daher bei MP3's mit variabler Bitrate ohne VBR-Header keine korrekte Länge berechnen, obwohl es sich hier um standardkonforme MP3's handelt.

    Links zu den genauen Spezifikationen der MP3 Frame Headers und VBR Headers habe ich im Moment leider gerade nicht zur Hand, sind aber über Google etc. zu finden.

    Gruß,
    -- emkey08 --


Anmelden zum Antworten