mp3文件的时间长度
时间:2020-03-06 14:34:58 来源:igfitidea点击:
在不使用外部库的情况下确定给定mp3文件长度(以秒为单位)的最简单方法是什么? (高度赞赏python来源)
解决方案
我们可以使用pymad。它是一个外部库,但不要落入"此处未发明"陷阱。我们不希望使用任何外部库的任何特殊原因?
import mad mf = mad.MadFile("foo.mp3") track_length_in_milliseconds = mf.total_time()
在这里发现。
--
如果我们真的不想使用外部库,请在这里查看并查看他的工作方式。警告:这很复杂。
我们可能会计算文件中的帧数。每个帧都有一个起始代码,尽管我无法收集起始代码的确切值,也没有MPEG规范。每个帧都有一定的长度,对于MPEG1层II,大约为40ms。
此方法适用于CBR文件(恒定比特率),而VBR文件的工作原理则完全不同。
从以下文档中:
对于第I层,我们向我们提交以下公式:
FrameLengthInBytes =(12 * BitRate / SampleRate + Padding)* 4
对于第二层和第三层文件,请使用以下公式:
FrameLengthInBytes = 144 * BitRate / SampleRate +填充
有关MPEG音频帧头的信息
Simple, parse MP3 binary blob to calculate something, in Python
这听起来像是一个很高的要求。我不了解Python,但是这是我曾经尝试编写的另一个程序中重构的一些代码。
注意:它是用C ++语言编写的(很抱歉,这就是我所拥有的)。同样,按原样,它将仅处理恒定比特率的MPEG 1音频第3层文件。那应该涵盖了大多数,但是我不能保证在所有情况下都能正常工作。希望这可以实现我们想要的功能,并希望将其重构为Python比从头开始做起来容易。
// determines the duration, in seconds, of an MP3; // assumes MPEG 1 (not 2 or 2.5) Audio Layer 3 (not 1 or 2) // constant bit rate (not variable) #include <iostream> #include <fstream> #include <cstdlib> using namespace std; //Bitrates, assuming MPEG 1 Audio Layer 3 const int bitrates[16] = { 0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 0 }; //Intel processors are little-endian; //search Google or see: http://en.wikipedia.org/wiki/Endian int reverse(int i) { int toReturn = 0; toReturn |= ((i & 0x000000FF) << 24); toReturn |= ((i & 0x0000FF00) << 8); toReturn |= ((i & 0x00FF0000) >> 8); toReturn |= ((i & 0xFF000000) >> 24); return toReturn; } //In short, data in ID3v2 tags are stored as //"syncsafe integers". This is so the tag info //isn't mistaken for audio data, and attempted to //be "played". For more info, have fun Googling it. int syncsafe(int i) { int toReturn = 0; toReturn |= ((i & 0x7F000000) >> 24); toReturn |= ((i & 0x007F0000) >> 9); toReturn |= ((i & 0x00007F00) << 6); toReturn |= ((i & 0x0000007F) << 21); return toReturn; } //How much room does ID3 version 1 tag info //take up at the end of this file (if any)? int id3v1size(ifstream& infile) { streampos savePos = infile.tellg(); //get to 128 bytes from file end infile.seekg(0, ios::end); streampos length = infile.tellg() - (streampos)128; infile.seekg(length); int size; char buffer[3] = {0}; infile.read(buffer, 3); if( buffer[0] == 'T' && buffer[1] == 'A' && buffer[2] == 'G' ) size = 128; //found tag data else size = 0; //nothing there infile.seekg(savePos); return size; } //how much room does ID3 version 2 tag info //take up at the beginning of this file (if any) int id3v2size(ifstream& infile) { streampos savePos = infile.tellg(); infile.seekg(0, ios::beg); char buffer[6] = {0}; infile.read(buffer, 6); if( buffer[0] != 'I' || buffer[1] != 'D' || buffer[2] != '3' ) { //no tag data infile.seekg(savePos); return 0; } int size = 0; infile.read(reinterpret_cast<char*>(&size), sizeof(size)); size = syncsafe(size); infile.seekg(savePos); //"size" doesn't include the 10 byte ID3v2 header return size + 10; } int main(int argCount, char* argValues[]) { //you'll have to change this ifstream infile("C:/Music/Bush - Comedown.mp3", ios::binary); if(!infile.is_open()) { infile.close(); cout << "Error opening file" << endl; system("PAUSE"); return 0; } //determine beginning and end of primary frame data (not ID3 tags) infile.seekg(0, ios::end); streampos dataEnd = infile.tellg(); infile.seekg(0, ios::beg); streampos dataBegin = 0; dataEnd -= id3v1size(infile); dataBegin += id3v2size(infile); infile.seekg(dataBegin,ios::beg); //determine bitrate based on header for first frame of audio data int headerBytes = 0; infile.read(reinterpret_cast<char*>(&headerBytes),sizeof(headerBytes)); headerBytes = reverse(headerBytes); int bitrate = bitrates[(int)((headerBytes >> 12) & 0xF)]; //calculate duration, in seconds int duration = (dataEnd - dataBegin)/(bitrate/8); infile.close(); //print duration in minutes : seconds cout << duration/60 << ":" << duration%60 << endl; system("PAUSE"); return 0; }