Bitrate und Länge eines MP3s bestimmen

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Bitrate und Länge eines MP3s bestimmen

    Hallo,

    Ich bin dabei eine Klasse zu basteln, die die Bitrate und die Länge und eines MP3s bestimmen kann.

    Allerdings scheint das nicht einwandfrei funktionieren zu wollen.

    Die Vorgehensweise:
    Der komplette Inhalt der Datei wird als String eingelesen.
    Danach per

    explode(chr(255),$string);

    geteilt, weil ein Frame ja mit "11111111111" Bits beginnen muss.
    Danach überprüfe ich mit einer Schleife wirklich jedes Frame, indem ich die MPEG Audio version und die Layer description bestimme und dadurch dann die Bitrate.

    Die Bitrate eines MP3s, welches mit lame konstant mit 128kbit/s enkodiert wurde, hat jedoch folgende "Bitrate-Verteilung":

    Array
    (
    [128] => 621
    [bad] => 30
    [32] => 34
    [256] => 24
    [56] => 24
    [free] => 63
    [160] => 26
    [416] => 5
    [224] => 21
    [320] => 24
    [112] => 30
    [48] => 19
    [80] => 24
    [96] => 29
    [288] => 8
    [384] => 12
    [40] => 15
    [144] => 8
    [64] => 19
    [8] => 7
    [352] => 7
    [192] => 13
    [24] => 7
    [16] => 9
    [448] => 4
    )
    Also die meisten Frames sind wirklich mit 128 kbits/s enkodiert, aber es gibt auch viele andere Bitraten.

    Jetzt meine Frage: ist das normal? Eigentlich nicht, oder? Weil ich ja konstant kodiert habe. Also mit dem Befehl:
    Code:
    # C:\Programme\lame\lame.exe -b 128 Y:\supercops.wav Y:\supercops_128bit.mp3
    // EDIT:

    Das gleiche habe ich auch mit 32 kbit und 256 kbit enkodierten MP3s ausprobiert und das Ergebnis war immer ähnlich. Also mein Code scheint zumindest halbwegs richtig zu sein
    Zuletzt geändert von naitSirch; 30.04.2008, 08:21.
    Nachwuchs-Entwickler der Ameus GmbH
    Internetlösungen, Managed Server, Software- & Webentwicklung

  • #2
    11 bits mit 1 sind nicht chr(255).. chr gibt einen 8-bit wert zurück.
    also da mit strings zu arbeiten ist keine gute idee.

    [edit]
    http://www.fh-jena.de/contrib/fb/et/.../mp3_2_res.htm

    also ich würd ja binary öffnen und ganze header lesen.
    Zuletzt geändert von frodenius; 01.05.2008, 13:13.
    blllubb

    Kommentar


    • #3
      Syncword (12 Bit) ID (1 Bit): Offiziell ist ID-Signatur nur ein Bit groß, um die verwendete MPEG-Version zu kennzeichnen. In der Urfassung steht der Wert 1 für MPEG 1 und der Wert 0 für MPEG 2. Mit dem inoffiziellen Standard MPEG 2.5 reicht ein Bit als Kennung jedoch nicht mehr aus. Anwendungen, die diesen Standard bereits unterstützen, verwenden das zwölfte Bit des Syncwords als zusätzliche MPEG-ID. Ist dieses auf 0 gesetzt, steht dies für MPEG 2.5. Standardmäßig sind alle Bits des Syncwords gesetzt.
      Das ist aus dem Link, den Du mir geschickt hast.
      Das Syncword ist ja 11 Bits lang. Und unter "Standardmäßig sind alle Bits des Syncwords gesetzt" verstehe ich eigentlich, dass die alle den Wert 1 tragen. Wobei bei der Version 2.5 dürften ja dann nur die ersten 10 Bits auf 1 gesetzt sein, oder?

      Aber das komische ist ja immernoc, dass mein Script ja zumindest teilweise korrekt arbeitet. Vielleicht haben die falschen Werte etwas damit zu tun, dass die 2.5er MPEG Version falsch interpretiert wird?!

      Aber warum meinst Du, dass mit Strings zu arbeiten keine gute Idee ist?
      Klar chr(255) gibt einen String zurueck, aber ich lese dann ja auch noch die nächsten drei Bytes ein, und wandle die mit decbin in den Binärwert um. Da dann natürlich auch sowas wie "1001" 'rauskommen kann, habe ich eine Funktion, die dann vorne so viele Nullen drann hängt, bis es 8 Bits sind.
      Somit erhalte ich dann immer 32 Bits (also den Frame-Header) und daraus hole ich mir dann die benötigten Informationen.

      Aber was genau meinst Du mit
      also ich würd ja binary öffnen und ganze header lesen.
      Wie funktioniert das denn? Ich habe bisher noch nie wirklich etwas mit Binären Dateien gemacht...
      Nachwuchs-Entwickler der Ameus GmbH
      Internetlösungen, Managed Server, Software- & Webentwicklung

      Kommentar


      • #4
        Wie funktioniert das denn? Ich habe bisher noch nie wirklich etwas mit Binären Dateien gemacht...
        fread
        Die Regeln | rtfm | register_globals | strings | SQL-Injections | [COLOR=silver][[/COLOR][COLOR=royalblue]–[/COLOR][COLOR=silver]][/COLOR]

        Kommentar


        • #5
          nein also eigentlich ist das syncword 12 bit lang. für mpeg 2.5 braucht man eben nur das 12te bit auf 0. dh 11 bits sind immer gesetzt.
          das mit den strings machst du wahrscheinlich per file_get_contents(), oder?
          das problem ist eben das strings in php aus 8 bit zeichen bestehen. und woher willst du wissen dass es in den ton-daten kein byte gibt, bei dem auch alle bits gesetzt sind?
          das ist sogar sehr wahrscheinlich.

          auf php-classes.org gibts einige klassen um mp3 inkl. id3 tags zu parsen. (als inspriration)
          Zuletzt geändert von frodenius; 03.05.2008, 17:18.
          blllubb

          Kommentar


          • #6
            ich sehe grad, dass ich die Datei doch mit
            PHP-Code:
            $fp fopen($path,"rb");
            $file fread($fp,filesize($path)); 
            einlese. Dann ist das ja "binär".

            Wenn Ihr wollt, könnt Ihr Euch ja mal den Code der Funktion ansehen, die die Bitrate und ähnliches bestimmt.

            PHP-Code:
            $zerlegt explode(chr(255),$this->file);
                    
            for(
            $pos=0$pos<sizeof($zerlegt); $pos++) {
                        
                
            $frame chr(255).$zerlegt[$pos]; // hier wird das chr(255) wieder drann gehängt, was durch explode() "verloren gegangen" ist
                       
                
            $char1 substr($frame,0,1);
                
            $byte[0] = $this->decbinFill(ord($char1),8); // hier steht sowas wie: "11111111"
                       
                
            $char2 substr($frame,1,1);
                
            $byte[1] = $this->decbinFill(ord($char2),8); // hier steht sowas wie: "00100111"
                       
                
            $char3 substr($frame,2,1);
                
            $byte[2] = $this->decbinFill(ord($char3),8); // hier steht sowas wie: "00100111"
                       
                
            $char4 substr($frame,3,1);
                
            $byte[3] = $this->decbinFill(ord($char4),8); // hier steht sowas wie: "00100111"
                        
                
            $header implode("",$byte); // fügt die vier Bytes ohne Trennzeichen zusammen, so dass der Header genau 32 Bits lang ist
                        
                
            if(substr($header,0,11) == "11111111111" ) { // hier wird das Syncword überprüft
                  
            $version =     $this->versionsubstr($header,11,2) ];
                  
            $layer =     $this->layersubstr($header,13,2) ];
                       
                  if(
            $version == $layer == 1)
                     
            $b 0;
                  else if(
            $version == $layer == 2)
                        
            $b 1;
                  else if(
            $version == $layer == 3)
                           
            $b 2;
                  else if(
            $version == $layer == 1)
                          
            $b 3;
                  else if(
            $version == & ( $layer == $layer == ) )
                           
            $b 4;
                               
                  
            $bitrate $this->bitratesubstr($header,16,4) ][$b];
                  
            $ergebnis[$bitrate]++;
                }

            Die Funktion decbinFill(Dezimalzahl, erwünschte Länge)
            PHP-Code:
                function decbinFill($dec,$length=0) {
                    
            $str decbin($dec);
                    
            $nulls $length-strlen($str);
                    if(
            $nulls>0) {
                        for(
            $i=0;$i<$nulls;$i++) {
                            
            $str '0'.$str;
                        }
                    }
                    return 
            $str;
                } 
            Zuletzt geändert von naitSirch; 06.05.2008, 09:48.
            Nachwuchs-Entwickler der Ameus GmbH
            Internetlösungen, Managed Server, Software- & Webentwicklung

            Kommentar


            • #7
              also wie gesagt:
              du kannst dir nicht sicher sein dass 8 gesetzte bits in folge nur in den syncwords der frame-header vorkommen.
              und außerdem halten sich die frames nicht an bytes sondern bits. dh die 11 bits könnten auch zu 5 und 6 in zwei bytes stecken, und der header wird gar nicht erkannt.
              blllubb

              Kommentar


              • #8
                Original geschrieben von frodenius
                also wie gesagt:
                du kannst dir nicht sicher sein dass 8 gesetzte bits in folge nur in den syncwords der frame-header vorkommen.
                Das stimmt. Aber wie testen das andere Programme?

                Original geschrieben von frodenius
                und außerdem halten sich die frames nicht an bytes sondern bits. dh die 11 bits könnten auch zu 5 und 6 in zwei bytes stecken, und der header wird gar nicht erkannt.
                Also eigentlich kann das nicht sein, weil ich ja mit der Funktion debinFill() arbeite. Wenn bei einem Byte nur 5 bits gesetzt wird, wird es in 00011111 umgewandelt.

                Wenn also zwei Bytes, einmal mit 5 und einmal mit 6 gesetzten Bits, hintereinander stehen, würde das so aussehen:
                0001111100111111
                es würde also nicht als syncword interpretiert werden. Zumindest, wenn ich das richtig verstehe...
                Nachwuchs-Entwickler der Ameus GmbH
                Internetlösungen, Managed Server, Software- & Webentwicklung

                Kommentar


                • #9
                  Also eigtl kann das nicht sein, weil..
                  [...]
                  es würde also nicht als syncword iterpretiert werden. ...
                  ...
                  ja eben doch wohl, nein, doch, nein, DOCH!
                  ja klar. wird nicht als syncword erkannt -> kein header erkannt.

                  andere programme lesen die datei als bitstream.

                  ich würde (wie gesagt) die header als ganzes analysieren.
                  erst mal die datei mit file_get_contents einlesen und dann erst mal gucken ob TAG also erstes steht, dann die tags lesen. wenn jetzt die frames anfangen, interpretierst du den ersten header und wenn da eine konstante bitrate drin steht, dann wird das auch im rest der datei so sein. wenn die bitrate variabel ist wirst du bei jedem frame seine größe berechnen müssen, um zum nächsten zu finden.
                  blllubb

                  Kommentar


                  • #10
                    Achso. Ich glaub' jetzt hat es klick gemacht
                    Wenn z.B. 2 Bytes hintereinanderstehen mit:
                    00111111,11111000

                    In dem Fall würde mein Script das gar nicht beachten, weil es ja mit "00" anfängt...
                    Okay, daran werd' ich arbeiten. Vielen Dank für die Hilfe frodenius
                    Nachwuchs-Entwickler der Ameus GmbH
                    Internetlösungen, Managed Server, Software- & Webentwicklung

                    Kommentar

                    Lädt...
                    X