time length of an mp3 file

前端 未结 6 2038
别那么骄傲
别那么骄傲 2020-12-01 07:11

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

相关标签:
6条回答
  • 2020-12-01 07:17

    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;
    }
    
    0 讨论(0)
  • 2020-12-01 07:25

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

    mpg321 -t

    ffmpeg -i

    midentify (mplayer basically) see Using mplayer to determine length of audio/video file

    mencoder (pass it invalid params, it will spit out an error message but also give you info on the file in question, ex $ mencoder inputfile.mp3 -o fake)

    mediainfo program http://mediainfo.sourceforge.net/en

    exiftool

    the linux "file" command

    mp3info

    sox

    refs: https://superuser.com/questions/36871/linux-command-line-utility-to-determine-mp3-bitrate

    http://www.ruby-forum.com/topic/139468

    mp3 length in milliseconds

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

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

    Cheers!

    0 讨论(0)
  • 2020-12-01 07:26

    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.

    0 讨论(0)
  • 2020-12-01 07:31

    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
    
    0 讨论(0)
  • 2020-12-01 07:32

    simply use mutagen

    $pip install mutagen
    

    use it in python shell:

    from mutagen.mp3 import MP3
    audio = MP3(file_path)
    print audio.info.length
    
    0 讨论(0)
  • 2020-12-01 07:36

    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

    0 讨论(0)
提交回复
热议问题