Dauer einer MP3 Datei ermitteln

MP3 Dateien begleiten uns ja nun mittlerweile doch schon einige Zeit. Gerade bei der Erforschung des Internets kam man – trotz 56k Modem – auch mal schnell mit MP3s im Berührung. Durch die rasante Verbreitung hat sich MP3 ziemlich schnell als Standard etabliert.

Trotz der weiten Verbreitung gibt es aber trotzdem wenige Schnittstellen um z.B. die ID-Tags von MP3s auszulesen und zu verarbeiten. Einige Projekte wurden nach ID3V1 nicht mehr weiterentwickelt oder bieten nur einen rudimentären Funktionsumfang. Des Öfteren habe ich mich schon nach einer vernünftigen Bibliothek umgesehen. Diese Woche wurde ich allerdings überrascht. Bei meiner Suche bin ich auf die C# ID3 Library gestoßen, die vor kurzem auch in einer neuen Version erschienen ist. Die Benutzung ist denkbar einfach, so dass ich auch gleich mit meinem eigentlichen Projekt loslegen konnte: Der ultimative CD-Daten Validator

Als mein CD-Manager noch keine FreeDB Anbindung hatte, wurden die Daten alle per Hand eingegeben. Da ich vor einigen Jahren angefangen habe, die CDs zu digitalisieren und die ID-Tags entsprechend zu pflegen, wäre es jetzt natürlich toll, wenn die Daten auch an allen drei Stellen gleich wären (Dateisystem, ID-Tag, CD-Manager). Ich habe bereits vor einiger Zeit eine ‚Light-Version‘ davon als PlugIn für den CD-Manager entwickelt. Dabei bin ich auf einen ‚gravierenden‘ Bug im CD-Manager gestoßen (Siehe: Blog Eintrag vom 29.05.2011). Bei Enhanced CDs ist zwischen dem letzten Audiotrack und dem Datentrack eine ‘Lücke’ von 152 Sekunden. Die Klasse, die ich zum ermitteln der Spieldauer verwendet habe, hat dies leider nicht mit berücksichtigt. Wenn man es also genau nimmt, kein Fehler von mir aber ärgerlich, dass das erst Jahre später aufgefallen ist. Nun ja. Mein kleines Programm hat mir diese Unstimmigkeit dann korrigiert. Jetzt fünf Monate später wird das ganze auf die Spitze getrieben und auch die ID-Tags der MP3s sollen in die Validierung mit einfließen.

Nach kurzer Zeit kann ich die ersten Ergebnisse der Validierung auf meinem Bildschirm sehen. Doch was ist das? Eine Zeitabweichung von 152 Sekunden? Die Zahl kommt mir doch bekannt vor … Was ist hier denn passiert? Die C# ID3 Library liefert mir auch eine fehlerhafte Dauer zurück. Wenn man mit einem Hexeditor einen Blick in die MP3-Datei wirft, wird einem auch schnell klar warum: Im Header gibt es ein Kennzeichen: TLEN ein paar Byte weiter steht die – fehlerhafte – Spieldauer. Was für mich so viel heißt wie: Leider schreibt der EAC eine ‚falsche Speildauer‘ in den Header (obwohl sie im Programm korrekt angezeigt wird). Das diese dann natürlich beim auslesen nicht korrekt sein kann ist klar. Die nächste Frage die sich mir aber dann stellt ist: Warum zeigt z.B. Winamp die Spieldauer aber wieder korrekt an? Und natürlich: Wenn man sich auf den Tag nicht verlassen kann, wie ermittelt man dann am besten die Spieldauer?

Ohne das ich mich jetzt auf die Suche nach ‚der richtigen‘ Antwort gemacht habe, kann ich auf jeden Fall schon mal eine Lösung anbieten. Denn ich habe ja auch bisher die Länge von MP3s bestimmt ohne den ID-Tag auszulesen. Ich habe das mal exemplarisch in dieser Sample Klasse dargestellt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
 
namespace Sample.MP3Tools
{
    public class MP3Duration
    {
        [DllImport("winmm.dll")]
        private static extern int mciSendString(string strCommand, StringBuilder strReturn, int iReturnLength, IntPtr hwndCallback);
 
        public static int DurationForFile(string file)
        {
            // Return value
            int rValue = 0;
 
            if (File.Exists(file) && ((mciSendString("open \"" + file + "\" type mpegvideo alias MediaFile", null, 0, IntPtr.Zero)) == 0))
            {
                mciSendString("set MediaFile time format milliseconds", null, 0, IntPtr.Zero);
                mciSendString("set MediaFile seek exactly on", null, 0, IntPtr.Zero);
                StringBuilder str = new StringBuilder(128);
                mciSendString("status MediaFile length", str, 128, IntPtr.Zero);
                ulong length = Convert.ToUInt64(str.ToString());
                rValue = ((int)(length / 1000));
                mciSendString("close MediaFile", null, 0, IntPtr.Zero);
            }
            return rValue;
        }
    }
}

Wenn Zeit ist mache ich mich auf die Suche nach der ‚richtigen‘ Lösung 😉

Ein Kommentar

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.