mp3 文件的时间长度

发布于 2024-07-05 13:03:15 字数 78 浏览 6 评论 0原文

不使用外部库确定给定 mp3 文件的长度(以秒为单位)的最简单方法是什么? (高度赞赏Python源代码)

What is the simplest way to determine the length (in seconds) of a given mp3 file, without using outside libraries? (python source highly appreciated)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

笑忘罢 2024-07-12 13:03:15

您可以使用 pymad。 它是一个外部库,但不要陷入“Not Invented Here”的陷阱。 您不需要任何外部库有什么特殊原因吗?

import mad

mf = mad.MadFile("foo.mp3")
track_length_in_milliseconds = mf.total_time()    

发现此处

--

如果您确实不想使用外部库,请查看此处并查看他是如何做到的。 警告:这很复杂。

You can use pymad. It's an external library, but don't fall for the Not Invented Here trap. Any particular reason you don't want any external libraries?

import mad

mf = mad.MadFile("foo.mp3")
track_length_in_milliseconds = mf.total_time()    

Spotted here.

--

If you really don't want to use an external library, have a look here and check out how he's done it. Warning: it's complicated.

祁梦 2024-07-12 13:03:15

为了 Google 关注者的缘故,这里还有一些外部库:

参考:

(使其成为供其他人添加的 wiki)。

和库:.net:naudio,java:jlayer,c:libmad

干杯!

For google followers' sake, here are a few more external libs:

refs:

(making this a wiki for others to add to).

and libs: .net: naudio, java: jlayer, c: libmad

Cheers!

烟雨扶苏 2024-07-12 13:03:15

<块引用>

简单,用 Python 解析 MP3 二进制 blob 来计算一些内容

这听起来是一个相当艰巨的任务。 我不懂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;
}

Simple, parse MP3 binary blob to calculate something, in Python

That sounds like a pretty tall order. I don't know Python, but here's some code I've refactored from another program I once tried to write.

Note: It's in C++ (sorry, it's what I've got). Also, as-is, it'll only handle constant bit rate MPEG 1 Audio Layer 3 files. That should cover most, but I can't make any guarantee as to this working in all situations. Hopefully this does what you want, and hopefully refactoring it into Python is easier than doing it from scratch.

// 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;
}
南冥有猫 2024-07-12 13:03:15

只需使用 mutagen

$pip install mutagen

在 python shell 中使用它:

from mutagen.mp3 import MP3
audio = MP3(file_path)
print audio.info.length

simply use mutagen

$pip install mutagen

use it in python shell:

from mutagen.mp3 import MP3
audio = MP3(file_path)
print audio.info.length
策马西风 2024-07-12 13:03:15

还要看看audioread(一些linux发行版包括ubuntu都有软件包),https://github.com/sampsyo/audioread

audio = audioread.audio_open('/path/to/mp3')
print audio.channels, audio.samplerate, audio.duration

Also take a look at audioread (some linux distros including ubuntu have packages), https://github.com/sampsyo/audioread

audio = audioread.audio_open('/path/to/mp3')
print audio.channels, audio.samplerate, audio.duration
白鸥掠海 2024-07-12 13:03:15

您可以计算文件中的帧数。 每个帧都有一个起始码,尽管我无法记住起始码的确切值,而且我也没有 MPEG 规范。 每帧都有一定的长度,对于 MPEG1 第二层来说约为 40ms。

此方法适用于 CBR 文件(恒定比特率),VBR 文件的工作原理则完全不同。

从下面的文档中:

对于 Layer I 文件,我们使用以下公式:

FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4

对于 Layer II 和 Layer II 文件, 我们使用以下公式: III 文件使用以下公式:

FrameLengthInBytes = 144 * BitRate / SampleRate + Padding

有关 MPEG 音频帧标头的信息< /a>

You might count the number of frames in the file. Each frame has a start code, although I can't recollect the exact value of the start code and I don't have MPEG specs laying around. Each frame has a certain length, around 40ms for MPEG1 layer II.

This method works for CBR-files (Constant Bit Rate), how VBR-files work is a completely different story.

From the document below:

For Layer I files us this formula:

FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4

For Layer II & III files use this formula:

FrameLengthInBytes = 144 * BitRate / SampleRate + Padding

Information about MPEG Audio Frame Header

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文