有许多lib可以使用mp3标签,但我只需要2个功能 - 分割2个部分的mp3文件,第二个合并5个mp3。
你能提出什么建议吗? 谢谢!
答案 0 :(得分:91)
我为这个确切的用例编写了一个库(pydub):
from pydub import AudioSegment
sound = AudioSegment.from_mp3("/path/to/file.mp3")
# len() and slicing are in milliseconds
halfway_point = len(sound) / 2
second_half = sound[halfway_point:]
# Concatenation is just adding
second_half_3_times = second_half + second_half + second_half
# writing mp3 files is a one liner
second_half_3_times.export("/path/to/new/file.mp3", format="mp3")
答案 1 :(得分:6)
查看维基百科上的MP3 file structure。在python中使用二进制读取模式来编辑MP3文件。 s = open(file_name, 'rb').read()
会将整个文件放入一个表示文件中原始字节的字符串对象(例如\xeb\xfe\x80
)。然后,您可以使用括号s[n]
搜索和编辑字符串,使用indeces寻址字节偏移量。最后,只需在新文件中对所需的MP3帧进行二进制写入,将ID3标题附加到要组成每个文件的帧集上。
答案 2 :(得分:2)
查看GStreamer及其Python包装器Gst-Python。
答案 3 :(得分:1)
这是我尝试使用python分割MP3而不重新编码的尝试。并非所有MP3文件都受支持,我很乐意提出建议或进行改进。该脚本经过硬编码,可以在55秒时拆分,但是代码演示了一般原理。
from __future__ import print_function
import struct
import sys
#MP3 frames are not independent because of the byte reservoir. This script does not account for
#that in determining where to do the split.
def SplitMp3(fi, splitSec, out):
#Constants for MP3
bitrates = {0x0: "free", 0x1: 32, 0x2: 40, 0x3: 48, 0x4: 56, 0x5: 64, 0x6: 80, 0x7: 96, 0x8: 112,
0x9: 128, 0xa: 160, 0xb: 192, 0xc: 224, 0xd: 256, 0xe: 320, 0xf: "bad"}
freqrates = {0x0: 44100, 0x1: 48000, 0x2: 32000, 0x3: "reserved"}
countMpegFrames = 0
frameDuration = 0.026
unrecognizedBytes = 0
splitFrame = int(round(splitSec / frameDuration))
while True:
startPos = fi.tell()
#Check for 3 byte headers
id3Start = fi.read(3)
if len(id3Start) == 3:
if id3Start == b'TAG':
print ("Found ID3 v1/1.1 header")
fi.seek(startPos + 256)
continue
if id3Start == b'ID3':
#Possibly a ID3v2 header
majorVer, minorVer, flags, encSize = struct.unpack(">BBBI", fi.read(7))
if majorVer != 0xFF and minorVer != 0xFF:
encSize1 = (encSize & 0x7f000000) >> 24
encSize2 = (encSize & 0x7f0000) >> 16
encSize3 = (encSize & 0x7f00) >> 8
encSize4 = (encSize & 0x7f)
if encSize1 < 0x80 and encSize2 < 0x80 and encSize3 < 0x80 and encSize4 < 0x80:
size = ((encSize & 0x7f000000) >> 3) + ((encSize & 0x7f0000) >> 2) + ((encSize & 0x7f00) >> 1) + (encSize & 0x7f)
unsync = (flags >> 7) & 0x1
extendedHeader = (flags >> 6) & 0x1
experimental = (flags >> 5) & 0x1
print ("Found ID3v2 header")
print ("version", majorVer, minorVer, unsync, extendedHeader, experimental)
print ("size", size)
#TODO extendedHeader not supported yet
fi.seek(startPos + 10 + size)
continue
#Check for 4 byte headers
fi.seek(startPos)
headerRaw = fi.read(4)
if len(headerRaw) == 4:
headerWord = struct.unpack(">I", headerRaw)[0]
#Check for MPEG-1 audio frame
if headerWord & 0xfff00000 == 0xfff00000:
print ("Possible MPEG-1 audio header", hex(headerWord))
countMpegFrames += 1
ver = (headerWord & 0xf0000) >> 16
bitrateEnc = (headerWord & 0xf000) >> 12
freqEnc = (headerWord & 0xf00) >> 8
mode = (headerWord & 0xf0) >> 4
cpy = (headerWord & 0xf)
if ver & 0xe == 0xa and freqEnc != 0xf:
print ("Probably an MP3 frame")
bitrate = bitrates[bitrateEnc]
freq = freqrates[freqEnc >> 2]
padding = ((freqEnc >> 1) & 0x1) == 1
print ("bitrate", bitrate, "kbps")
print ("freq", freq, "Hz")
print ("padding", padding)
frameLen = int((144 * bitrate * 1000 / freq ) + padding)
#Copy frame to output
fi.seek(startPos)
frameData = fi.read(frameLen)
if countMpegFrames >= splitFrame:
out.write(frameData)
fi.seek(startPos + frameLen)
continue
else:
raise RuntimeError("Unsupported format:", hex(ver), "header:", hex(headerWord))
#If no header can be detected, move on to the next byte
fi.seek(startPos)
nextByteRaw = fi.read(1)
if len(nextByteRaw) == 0:
break #End of file
unrecognizedBytes += 1
print ("unrecognizedBytes", unrecognizedBytes)
print ("countMpegFrames", countMpegFrames)
print ("duration", countMpegFrames * frameDuration, "sec")
if __name__=="__main__":
fi = open(sys.argv[1], "rb")
out = open("test.mp3", "wb")
SplitMp3(fi, 55.0, out)
out.close()
合并将是从两个单独的MP3输入文件中提取和添加帧的类似情况。
答案 4 :(得分:-4)
使用unix split命令:
split -b 200k file.mp3 output_
这将输出output_a,output_b,output_c,..
然后你可以通过重命名来获取mp3文件
for file in ./output_*; do mv "$file" "$(basename $file).mp3"; done
这将输出output_a.mp3,output_b.mp3,output_c.mp3 ...所有这些(最后一个,可能除外)都是200kb大小,output_x的总大小与文件相同。 MP3
您可以使用du
(磁盘使用情况)命令获取文件的字节数,然后决定要剪切的字节数。
du -sh file.mp3
然后加入使用cat命令:
cat output_2.mp3 output_3.mp3 output_4.mp3 > output.mp3
当然你可以将所有这些放在shell脚本中并从python中调用它。