Files

38 lines
1.4 KiB
Python

"""MPEG Layer III duration without external tools."""
_BR1 = [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320]
_BR2 = [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160]
_SR = {3: [44100, 48000, 32000], 2: [22050, 24000, 16000], 0: [11025, 12000, 8000]}
def mp3_duration(path):
"""Duration of an MPEG Layer III file by walking frame headers (works for VBR)."""
with open(path, "rb") as fh:
data = fh.read()
i = 0
if data[:3] == b"ID3" and len(data) >= 10:
i = 10 + ((data[6] & 0x7f) << 21 | (data[7] & 0x7f) << 14 | (data[8] & 0x7f) << 7 | (data[9] & 0x7f))
samples = 0.0
first = True
n = len(data)
while i + 4 <= n:
h = int.from_bytes(data[i:i + 4], "big")
ver, layer, bri, sri = (h >> 19) & 3, (h >> 17) & 3, (h >> 12) & 15, (h >> 10) & 3
if (h >> 21) & 0x7ff != 0x7ff or ver == 1 or layer != 1 or bri in (0, 15) or sri == 3:
i += 1
continue
sr = _SR[ver][sri]
pad = (h >> 9) & 1
if ver == 3:
flen, spf = 144000 * _BR1[bri] // sr + pad, 1152
else:
flen, spf = 72000 * _BR2[bri] // sr + pad, 576
if first:
first = False
if b"Xing" in data[i:i + 64] or b"Info" in data[i:i + 64]:
i += flen
continue
samples += spf / sr
i += flen
return samples