Bitrate einer MP3-Datei auslesen

  • Schönen Tag auch!
    Ich suche eine Möglichkeit die Bitrate einer MP3-Datei auszulesen. Forensuche und Google haben mir nicht weitergeholfen. Ich habe zwar rausgefunden dass man die Bitrate auslesen kann, dennoch hab ich nicht rausgefunden WIE.
    Desweiteren wäre es schön wenn sich realisieren lässt, dass bei VBR-Codierten Dateien die durchschnittliche Bitrate berechnet wird.

    Gruß,
    Trampi

    • Offizieller Beitrag
    Spoiler anzeigen
    [autoit]

    ;===============================================================================
    ;
    ; Description: Retrieve MP3 (MP2, MPA) basic information
    ; Parameter(s): File name
    ; Requirement(s): None
    ; Return Value(s): On Success - array with data:
    ; 0 - MPEG version
    ; 1 - Layer
    ; 2 - Bitrate
    ; 3 - Frequency
    ; 4 - Channel Mode
    ; 5 - Duration
    ; 6 - Frames
    ; 7 - CRC protected
    ; 8 - Copyrighted
    ; 9 - Original
    ; On Failure empty string and sets @ERROR:
    ; 1 - Info not found
    ; Author(s): YDY (Lazycat) <[email='mpc@nm.ru'][/email]>
    ; Version: 1.2.00
    ; Date: 30.12.2004
    ; Note(s): None
    ;
    ;===============================================================================

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _GetMP3Info($file)
    Local $data[10], $offset = 1, $isValid = 0, $isVBR = 0
    Local $aVersion = StringSplit("MPEG 2.5|Undefined|MPEG 2.5|MPEG 1", "|")
    Local $aLayer = StringSplit("Undefined|Layer III|Layer II|Layer I", "|")
    Local $sBitrate = ""
    Local $sFrequency = ""
    Local $aChanMode = StringSplit("Stereo|Joint stereo|Dual channel|Mono", "|")
    Local $aFlags = StringSplit("No|Yes", "|")
    Local $head, $nVer, $nLay

    [/autoit] [autoit][/autoit] [autoit]

    If _FileReadAtOffsetHEX ($file, 1, 3) = "494433" Then ; ID3v2 tag found
    $offset = _HEXToSSInt(_FileReadAtOffsetHEX ($file, 7, 4)) + 10 ; End of ID3v2 tag
    Endif

    [/autoit] [autoit][/autoit] [autoit]

    For $ic = $offset to 4096 + $offset
    $marker = _FileReadAtOffsetHEX ($file, $ic, 2)
    $marker = StringLeft($marker, 3)
    If StringInStr("FFF,FFE", $marker) Then ; Assume that is frame start
    $head = _HexToBin(_FileReadAtOffsetHEX ($file, $ic, 4))
    $nVer = _GetRBits($head, 19, 2)
    $nLay = _GetRBits($head, 17, 2)
    If ($nVer <> 1) and ($nLay <> 0) Then
    If _FileReadAtOffsetHEX ($file, $ic+36, 4) = "58696E67" Then $isVBR = 1 ; Is this a right way?..
    $isValid = 1
    Exitloop
    Endif
    Endif
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If not $isValid Then
    SetError(1) ; Frame not found (not mp3 data?)
    Return ("")
    Endif

    [/autoit] [autoit][/autoit] [autoit]

    Select
    Case $nVer = 3
    $sFrequency = "44100|48000|32000|Undefined"
    Case $nVer = 2
    $sFrequency = "22050|24000|16000|Undefined"
    Case $nVer = 0
    $sFrequency = "11025|12000|8000|Undefined"
    EndSelect
    Local $aFrequency = StringSplit($sFrequency, "|")
    $data[3] = _GetData($aFrequency, _GetRBits($head, 10, 2))

    [/autoit] [autoit][/autoit] [autoit]

    Local $pad = 0, $bitrate, $framesize, $frames, $length, $fps
    If _GetRBits($head, 9, 1) Then $pad = 1

    [/autoit] [autoit][/autoit] [autoit]

    If $isVBR Then
    $data[2] = "Variable"
    Else
    Select
    Case $nVer = 3 and $nLay = 3
    $sBitrate = "Free|32|64|96|128|160|192|224|256|288|320|352|384|416|448|Undefined"
    Case $nVer = 3 and $nLay = 2
    $sBitrate = "Free|32|48|56|64|80|96|112|128|160|192|224|256|320|384|Undefined"
    Case $nVer = 3 and $nLay = 1
    $sBitrate = "Free|32|40|48|56|64|80|96|112|128|160|192|224|256|320|Undefined"
    Case $nVer = 2 and $nLay = 3
    $sBitrate = "Free|32|48|56|64|80|96|112|128|144|160|176|192|224|256|Undefined"
    Case ($nVer = 2 and $nLay = 2) or ($nVer = 2 and $nLay = 1)
    $sBitrate = "Free|8|16|24|32|40|48|56|64|80|96|112|128|144|160|Undefined"
    EndSelect
    Local $aBitrate = StringSplit($sBitrate, "|")
    $data[2] = _GetData($aBitrate, _GetRBits($head, 12, 4))
    $bitrate = 1000 * $data[2]
    If $nLay = 3 Then
    $framesize = (((12 * $bitrate) / $data[3]) + $pad) * 4
    $fps = $data[3]/384
    Else
    $framesize = ((144 * $bitrate) / $data[3]) + $pad
    $fps = $data[3]/1152
    Endif
    $frames = FileGetSize($file) / $framesize
    $length = $frames / $fps
    Endif

    [/autoit] [autoit][/autoit] [autoit]

    $data[0] = _GetData($aVersion, $nVer)
    $data[1] = _GetData($aLayer, $nLay)
    $data[4] = _GetData($aChanMode, _GetRBits($head, 6, 2))
    $data[5] = StringFormat("%d:%02d", Int($length / 60), $length - Int($length / 60) * 60)
    $data[6] = Int($frames)
    $data[7] = _GetData($aFlags, not _GetRBits($head, 16, 1)) ; CRC
    $data[8] = _GetData($aFlags, _GetRBits($head, 3, 1)) ; Private
    $data[9] = _GetData($aFlags, _GetRBits($head, 2, 1)) ; Original
    Return($data)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Support functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    [/autoit] [autoit][/autoit] [autoit]

    Func _GetRBits($str, $pos, $size)
    Local $ic, $res = 0, $bStr = StringMid($str, 33 - $pos - $size, $size)
    For $ic = 0 to $size-1
    If StringMid($bStr, $size-$ic, 1) == "1" Then $res = $res + 2^$ic
    Next
    Return ($res)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _GetData(ByRef $array, $val)
    If $val > UBound($array)-1 Then Return("Undefined")
    Return ($array[$val+1])
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Common functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    [/autoit] [autoit][/autoit] [autoit]

    Func _HEXToSSInt($sHexStr)
    Local $iCnt, $iLen, $sTempStr = "", $iReturn = 0
    For $iCnt = 1 to StringLen($sHexStr) Step 2
    $sTempStr = $sTempStr & StringTrimLeft(_HexToBin(StringMid($sHexStr, $iCnt, 2)), 1)
    Next
    $iLen = StringLen($sTempStr)
    For $iCnt = 0 To $iLen - 1
    $iReturn = $iReturn + Number(StringMid($sTempStr, $iLen - $iCnt, 1)) * 2^$iCnt
    Next
    Return($iReturn)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _HexToBin($str)
    Local $res="", $i
    While StringLen($str) > 0
    $val = Dec(StringRight($str, 1))
    $str = StringTrimRight($str, 1)
    For $i = 1 to 4
    $res = String(Mod($val, 2)) & $res
    $val = Int($val/2)
    Next
    Wend
    Return ($res)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _FileReadAtOffsetHEX ($file, $offset, $bytes)
    Local $tfile = FileOpen($file, 0)
    Local $tstr = "", $i
    FileRead($tfile, $offset-1)
    For $i = $offset To $offset + $bytes - 1
    $tstr = $tstr & Hex(Asc(FileRead($tfile, 1)), 2)
    Next
    FileClose($tfile)
    Return ($tstr)
    Endfunc

    [/autoit] [autoit][/autoit] [autoit][/autoit]
  • Wunderbar, gibts auch ne Möglichkeit die Bitrate einer VBR-Codierten Datei zu berechnen?
    An sich eine wunderbare UDF

  • Bei einer VBR-codierten Mp3 haben alle Frames unterschiedliche Bitraten.
    Du müsstest alle Frame-Header auslesen und dann den Durchschnitt ausrechnen.
    oder nur ein paar und dann Minimum-Maximum Bitrate ermitteln.

    Die Bitrate ist in den ersten 4 Bits des 3 Bytes codiert

    es gibt auch commandline-tools (encspot.exe!?) die das für dich erledigen.

    lgE

    //EDIT: Du kannst auch die Bitrate aus der Dateiinfo auslesen mit der ExtProp.au3 UDF (oder so ähnlich)
    Das ist dann die Bitrate, die Windows ermittelt, vielleicht steht da auch Min/Max-Bitrate bei VBR´s!?

  • Hatte gerade mit einer VBR-Mp3 zu tun und mir ist folgendes aufgefallen:

    Die Mp3 hatte eine durchschnittliche Bitrate von 158kbit/s.
    VlC zeigte 128kbit/s, Windows 224kbit/s an! Beides konnte nicht stimmen.

    Die einfachste Möglichkeit, an die druchschnittliche Bitrate zu kommen, ist nun folgende:

    Spoiler anzeigen
    [autoit]

    #include "ExtProp.au3"
    $Mp3 = FileOpenDialog("Wähle eine Mp3-Datei aus", "", "Mp3 (*.mp3)", 1)
    $Size = FileGetSize($Mp3)
    $Length = _GetExtProperty($Mp3, 21)
    $Split = StringSplit($Length, ":")
    If @error Then Exit
    $Sec = Int($Split[3])
    $Sec += Int($Split[2]) * 60
    $Sec += Int($Split[1]) * 60 * 60
    $Bitrate = Round($Size / 1024 / $Sec * 8)
    MsgBox(0, $Mp3, $Bitrate)

    [/autoit]

    Die Bitrate wird anhand der Länge und Größe der Mp3 ausgerechnet
    $Size / 1024 : von Byte zu Kilobyte
    / Sec : Kilobyte pro Sekunde
    *8 : kiloByte zu KiloBit

    Allerdings ist das nur ein Näherungswert, da hier auch die ID3-Tags mitgerechnet werden!
    Ich glaube ITunes speichert hier gern Bilder in die Mp3 - ein 5s Lied mit einem ID3v2-Tag von 8mb verfälscht das Ergebnis natürlich sehr ;)

    ExtProp.au3

    Spoiler anzeigen
    [autoit]

    ;===============================================================================
    ; Function Name: GetExtProperty($sPath,$iProp)
    ; Description: Returns an extended property of a given file.
    ; Parameter(s): $sPath - The path to the file you are attempting to retrieve an extended property from.
    ; $iProp - The numerical value for the property you want returned. If $iProp is is set
    ; to -1 then all properties will be returned in a 1 dimensional array in their corresponding order.
    ; The properties are as follows:
    ; Name = 0
    ; Size = 1
    ; Type = 2
    ; DateModified = 3
    ; DateCreated = 4
    ; DateAccessed = 5
    ; Attributes = 6
    ; Status = 7
    ; Owner = 8
    ; Author = 9
    ; Title = 10
    ; Subject = 11
    ; Category = 12
    ; Pages = 13
    ; Comments = 14
    ; Copyright = 15
    ; Artist = 16
    ; AlbumTitle = 17
    ; Year = 18
    ; TrackNumber = 19
    ; Genre = 20
    ; Duration = 21
    ; BitRate = 22
    ; Protected = 23
    ; CameraModel = 24
    ; DatePictureTaken = 25
    ; Dimensions = 26
    ; Width = 27
    ; Height = 28
    ; Company = 30
    ; Description = 31
    ; FileVersion = 32
    ; ProductName = 33
    ; ProductVersion = 34
    ; Requirement(s): File specified in $spath must exist.
    ; Return Value(s): On Success - The extended file property, or if $iProp = -1 then an array with all properties
    ; On Failure - 0, @Error - 1 (If file does not exist)
    ; Author(s): Simucal ([email='Simucal@gmail.com'][/email])
    ; Note(s):
    ;
    ;===============================================================================
    Func _GetExtProperty($sPath, $iProp)
    Local $iExist, $sFile, $sDir, $oShellApp, $oDir, $oFile, $aProperty, $sProperty
    $iExist = FileExists($sPath)
    If $iExist = 0 Then
    SetError(1)
    Return 0
    Else
    $sFile = StringTrimLeft($sPath, StringInStr($sPath, "\", 0, -1))
    $sDir = StringTrimRight($sPath, (StringLen($sPath) - StringInStr($sPath, "\", 0, -1)))
    $oShellApp = ObjCreate ("shell.application")
    $oDir = $oShellApp.NameSpace ($sDir)
    $oFile = $oDir.Parsename ($sFile)
    If $iProp = -1 Then
    Local $aProperty[35]
    For $i = 0 To 34
    $aProperty[$i] = $oDir.GetDetailsOf ($oFile, $i)
    Next
    Return $aProperty
    Else
    $sProperty = $oDir.GetDetailsOf ($oFile, $iProp)
    If $sProperty = "" Then
    Return 0
    Else
    Return $sProperty
    EndIf
    EndIf
    EndIf
    EndFunc ;==>_GetExtProperty

    [/autoit]

    lgE