【问题标题】:Slicing mp3 files with python用python切片mp3文件
【发布时间】:2021-02-11 07:46:44
【问题描述】:

首先,这个问题是从这个答案answer 推断出来的。在那个答案中,我们可以使用 Python 拆分 mp3 文件。该代码很有用,但用于拆分两部分。例如,如果我想将第 30.00 秒分割到音频的结尾,这很酷,但如果我想从 30.00 分割到 35.00,它就没有用了。在那个答案的下面有一条关于如何修剪音频的评论,就像我说的那样,具体的一块。当我暗示代码说明时,它看起来像这样:

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, firstSplit_sec,secondSplit_sec, 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
    firstSplitFrame = int(round(firstSplit_sec / frameDuration))
    secondSplitFrame = int(round(secondSplit_sec / 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 (secondSplitFrame >= countMpegFrames) and (countMpegFrames >= firstSplitFrame):
                        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")

当我使用这个函数时,它会产生松散的输出。例如,如果我想将 0.0 拆分为 41.00 它会给我 0.00 到 37.00 ,并且这种松散度会随着切片的数量而增加。我一直在努力理解代码的某些部分。所以我问我该如何解决这种松散?我错过了什么吗?

注意:我已经尝试过 pydub 和类似的模块。但它们没用。总是给内存错误和慢。这真的很快。

【问题讨论】:

    标签: python mp3


    【解决方案1】:

    我找不到松散问题的解决方案,因此我使用 ffmpeg 进行切片。

    subprocess.call(["ffmpeg","-i",input_file,"-acodec","copy","-loglevel","quiet","-ss",str(start),"-to",str(end),"-metadata","title={}".format(name),output_file+".mp3"])
    

    【讨论】:

      猜你喜欢
      • 2018-02-14
      • 2010-12-20
      • 1970-01-01
      • 2017-06-29
      • 1970-01-01
      • 2021-11-26
      • 1970-01-01
      • 2011-06-04
      相关资源
      最近更新 更多