【问题标题】:PHP Function to get MP3 duration获取 MP3 持续时间的 PHP 函数
【发布时间】:2012-08-16 16:42:25
【问题描述】:

是否有任何 PHP 函数可以为我提供 MP3 持续时间。我查看了 ID 3 功能,但在此期间我看不到任何东西,除此之外,id3 是某种标签,在所有 MP3 中都不会存在,因此使用它没有任何意义。

【问题讨论】:

    标签: php mp3


    【解决方案1】:

    这应该对你有用,注意 getduration 函数:http://www.zedwood.com/article/127/php-calculate-duration-of-mp3

    【讨论】:

    • 好的,适用于 PHP5 而不是 PHP4,所以不确定你能否获得更多“现代”
    • 工作正常,但有时会返回 Severity: Warning --> fseek(): stream does not support seek
    【解决方案2】:

    安装getid3,但如果你只需要duration,你可以删除除这些模块之外的所有模块:

    • module.audio.mp3.php
    • module.tag.id3v1.php
    • module.tag.apetag.php
    • module.tag.id3v2.php

    使用如下代码访问持续时间:

    $getID3 = new getID3;
    $ThisFileInfo = $getID3->analyze($pathName);
    $len= @$ThisFileInfo['playtime_string']; // playtime in minutes:seconds, formatted string
    

    Sourceforge获取它

    【讨论】:

    【解决方案3】:

    我已经过了这么多时间,但是没有 getID3 (http://getid3.sourceforge.net/) 来获取音频文件的持续时间是不可能的。

    1) 首先使用以下链接下载 getID3 库:

     https://github.com/JamesHeinrich/getID3/archive/master.zip
    

    2) 试试下面的代码:

        <?php
           include("getid3/getid3.php");
           $filename = 'bcd4ecc6bf521da9b9a2d8b9616d1505.wav';
           $getID3 = new getID3;
           $file = $getID3->analyze($filename);
           $playtime_seconds = $file['playtime_seconds'];
           echo gmdate("H:i:s", $playtime_seconds);
        ?>
    

    【讨论】:

      【解决方案4】:

      您可以使用 ffmpeg 获取 mp3 或许多其他音频/视频文件的时长。

      1. 在您的服务器中安装 ffmpeg。
      2. 确保 php shell_exec 在您的 php 中不受限制。

            // Discriminate only the audio/video files you want
            if(preg_match('/[^?#]+\.(?:wma|mp3|wav|mp4)/', strtolower($file))){
                $filepath = /* your file path */;
                // execute ffmpeg form linux shell and grab duration from output
                $result = shell_exec("ffmpeg -i ".$filepath.' 2>&1 | grep -o \'Duration: [0-9:.]*\'');
                $duration = str_replace('Duration: ', '', $result); // 00:05:03.25
        
                //get the duration in seconds
                $timeArr = preg_split('/:/', str_replace('s', '', $duration[0]));
                $t = $this->_times[$file] = (($timeArr[3])? $timeArr[3]*1 + $timeArr[2] * 60 + $timeArr[1] * 60 * 60 : $timeArr[2] + $timeArr[1] * 60)*1000;
        
            }
        

      【讨论】:

      • 对于那些无法搜索的远程 URL 来说似乎是一种很好的思维方式。
      • 这对我来说是一个很好的答案,因为它不需要加载整个文件来获取持续时间。并可用于远程文件。
      【解决方案5】:
      <?php
      class MP3File
      {
      protected $filename;
      public function __construct($filename)
      {
          $this->filename = $filename;
      }
      
      public static function formatTime($duration) //as hh:mm:ss
      {
          //return sprintf("%d:%02d", $duration/60, $duration%60);
          $hours = floor($duration / 3600);
          $minutes = floor( ($duration - ($hours * 3600)) / 60);
          $seconds = $duration - ($hours * 3600) - ($minutes * 60);
          return sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds);
      }
      
      //Read first mp3 frame only...  use for CBR constant bit rate MP3s
      public function getDurationEstimate()
      {
          return $this->getDuration($use_cbr_estimate=true);
      }
      
      //Read entire file, frame by frame... ie: Variable Bit Rate (VBR)
      public function getDuration($use_cbr_estimate=false)
      {
          $fd = fopen($this->filename, "rb");
      
          $duration=0;
          $block = fread($fd, 100);
          $offset = $this->skipID3v2Tag($block);
          fseek($fd, $offset, SEEK_SET);
          while (!feof($fd))
          {
              $block = fread($fd, 10);
              if (strlen($block)<10) { break; }
              //looking for 1111 1111 111 (frame synchronization bits)
              else if ($block[0]=="\xff" && (ord($block[1])&0xe0) )
              {
                  $info = self::parseFrameHeader(substr($block, 0, 4));
                  if (empty($info['Framesize'])) { return $duration; } //some corrupt mp3 files
                  fseek($fd, $info['Framesize']-10, SEEK_CUR);
                  $duration += ( $info['Samples'] / $info['Sampling Rate'] );
              }
              else if (substr($block, 0, 3)=='TAG')
              {
                  fseek($fd, 128-10, SEEK_CUR);//skip over id3v1 tag size
              }
              else
              {
                  fseek($fd, -9, SEEK_CUR);
              }
              if ($use_cbr_estimate && !empty($info))
              { 
                  return $this->estimateDuration($info['Bitrate'],$offset); 
              }
          }
          return round($duration);
      }
      
      private function estimateDuration($bitrate,$offset)
      {
          $kbps = ($bitrate*1000)/8;
          $datasize = filesize($this->filename) - $offset;
          return round($datasize / $kbps);
      }
      
      private function skipID3v2Tag(&$block)
      {
          if (substr($block, 0,3)=="ID3")
          {
              $id3v2_major_version = ord($block[3]);
              $id3v2_minor_version = ord($block[4]);
              $id3v2_flags = ord($block[5]);
              $flag_unsynchronisation  = $id3v2_flags & 0x80 ? 1 : 0;
              $flag_extended_header    = $id3v2_flags & 0x40 ? 1 : 0;
              $flag_experimental_ind   = $id3v2_flags & 0x20 ? 1 : 0;
              $flag_footer_present     = $id3v2_flags & 0x10 ? 1 : 0;
              $z0 = ord($block[6]);
              $z1 = ord($block[7]);
              $z2 = ord($block[8]);
              $z3 = ord($block[9]);
              if ( (($z0&0x80)==0) && (($z1&0x80)==0) && (($z2&0x80)==0) && (($z3&0x80)==0) )
              {
                  $header_size = 10;
                  $tag_size = (($z0&0x7f) * 2097152) + (($z1&0x7f) * 16384) + (($z2&0x7f) * 128) + ($z3&0x7f);
                  $footer_size = $flag_footer_present ? 10 : 0;
                  return $header_size + $tag_size + $footer_size;//bytes to skip
              }
          }
          return 0;
      }
      
      public static function parseFrameHeader($fourbytes)
      {
          static $versions = array(
              0x0=>'2.5',0x1=>'x',0x2=>'2',0x3=>'1', // x=>'reserved'
          );
          static $layers = array(
              0x0=>'x',0x1=>'3',0x2=>'2',0x3=>'1', // x=>'reserved'
          );
          static $bitrates = array(
              'V1L1'=>array(0,32,64,96,128,160,192,224,256,288,320,352,384,416,448),
              'V1L2'=>array(0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384),
              'V1L3'=>array(0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320),
              'V2L1'=>array(0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256),
              'V2L2'=>array(0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160),
              'V2L3'=>array(0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160),
          );
          static $sample_rates = array(
              '1'   => array(44100,48000,32000),
              '2'   => array(22050,24000,16000),
              '2.5' => array(11025,12000, 8000),
          );
          static $samples = array(
              1 => array( 1 => 384, 2 =>1152, 3 =>1152, ), //MPEGv1,     Layers 1,2,3
              2 => array( 1 => 384, 2 =>1152, 3 => 576, ), //MPEGv2/2.5, Layers 1,2,3
          );
          //$b0=ord($fourbytes[0]);//will always be 0xff
          $b1=ord($fourbytes[1]);
          $b2=ord($fourbytes[2]);
          $b3=ord($fourbytes[3]);
      
          $version_bits = ($b1 & 0x18) >> 3;
          $version = $versions[$version_bits];
          $simple_version =  ($version=='2.5' ? 2 : $version);
      
          $layer_bits = ($b1 & 0x06) >> 1;
          $layer = $layers[$layer_bits];
      
          $protection_bit = ($b1 & 0x01);
          $bitrate_key = sprintf('V%dL%d', $simple_version , $layer);
          $bitrate_idx = ($b2 & 0xf0) >> 4;
          $bitrate = isset($bitrates[$bitrate_key][$bitrate_idx]) ? $bitrates[$bitrate_key][$bitrate_idx] : 0;
      
          $sample_rate_idx = ($b2 & 0x0c) >> 2;//0xc => b1100
          $sample_rate = isset($sample_rates[$version][$sample_rate_idx]) ? $sample_rates[$version][$sample_rate_idx] : 0;
          $padding_bit = ($b2 & 0x02) >> 1;
          $private_bit = ($b2 & 0x01);
          $channel_mode_bits = ($b3 & 0xc0) >> 6;
          $mode_extension_bits = ($b3 & 0x30) >> 4;
          $copyright_bit = ($b3 & 0x08) >> 3;
          $original_bit = ($b3 & 0x04) >> 2;
          $emphasis = ($b3 & 0x03);
      
          $info = array();
          $info['Version'] = $version;//MPEGVersion
          $info['Layer'] = $layer;
          //$info['Protection Bit'] = $protection_bit; //0=> protected by 2 byte CRC, 1=>not protected
          $info['Bitrate'] = $bitrate;
          $info['Sampling Rate'] = $sample_rate;
          $info['Framesize'] = self::framesize($layer, $bitrate, $sample_rate, $padding_bit);
          $info['Samples'] = $samples[$simple_version][$layer];
          return $info;
      }
      
      private static function framesize($layer, $bitrate,$sample_rate,$padding_bit)
      {
          if ($layer==1)
              return intval(((12 * $bitrate*1000 /$sample_rate) + $padding_bit) * 4);
          else //layer 2, 3
              return intval(((144 * $bitrate*1000)/$sample_rate) + $padding_bit);
      }
      }
      ?>
      <?php
      $mp3file = new MP3File("Chal_Halke.mp3");//http://www.npr.org/rss/podcast.php?id=510282
      $duration1 = $mp3file->getDurationEstimate();//(faster) for CBR only
      $duration2 = $mp3file->getDuration();//(slower) for VBR (or CBR)
      echo "duration: $duration1 seconds"."\n";
      
      ?>
      

      【讨论】:

        【解决方案6】:

        没有本地 php 函数可以做到这一点。

        根据您的服务器环境,您可以使用MP3Info 等工具。

        $length = shell_exec('mp3info -p "%S" sample.mp3');   // total time in seconds
        

        【讨论】:

          【解决方案7】:

          MP3 长度不会存储在任何地方(以“普通”MP3 格式),因为 MP3 被设计为“分割”成帧,而这些帧仍可播放。

          http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm

          如果您没有可依赖的 ID 标签,您需要做的(有执行此操作的工具和 PHP 类)是读取整个 MP3 文件并计算每个帧的持续时间。

          【讨论】:

            【解决方案8】:
            $getID3 = new getID3;
            $ThisFileInfo = $getID3->analyze($pathName);
            
            // playtime in minutes:seconds, formatted string
            $len = @$ThisFileInfo['playtime_string']; 
            
            //don't get playtime_string, but get playtime_seconds
            $len = @$ThisFileInfo['playtime_seconds']*1000; //*1000 as calculate millisecond
            

            希望对你有帮助。

            【讨论】:

              【解决方案9】:

              最后,我根据自己的计算开发了一个解决方案。此解决方案最适合 mp3WAV 文件格式。然而,预计会有微小的精度变化。解决方案在 PHP 中。我从WAV得到一点线索

              function calculateFileSize($file){
              
                  $ratio = 16000; //bytespersec
              
                  if (!$file) {
              
                      exit("Verify file name and it's path");
              
                  }
              
                  $file_size = filesize($file);
              
                  if (!$file_size)
                      exit("Verify file, something wrong with your file");
              
                  $duration = ($file_size / $ratio);
                  $minutes = floor($duration / 60);
                  $seconds = $duration - ($minutes * 60);
                  $seconds = round($seconds);
                  echo "$minutes:$seconds minutes";
              
              }
              
              $file = 'apple-classic.mp3'; //Enter File Name mp3/wav
              calculateFileSize($file);
              

              【讨论】:

                【解决方案10】:

                如前所述,我为 mp3WAV 文件提供了一个解决方案,现在这个解决方案专门针对唯一的 WAV 文件,其中包含更多精度,但评估时间比早期解决方案长。

                function calculateWavDuration( $file ) {
                
                    $fp = fopen($file, 'r');
                
                    if (fread($fp, 4) == "RIFF") {
                
                        fseek($fp, 20);
                        $raw_header = fread($fp, 16);
                        $header = unpack('vtype/vchannels/Vsamplerate/Vbytespersec/valignment/vbits', $raw_header);
                        $pos = ftell($fp);
                
                        while (fread($fp, 4) != "data" && !feof($fp)) {
                
                            $pos++;
                            fseek($fp, $pos);
                
                        }
                
                        $raw_header = fread($fp, 4);
                        $data = unpack('Vdatasize', $raw_header);
                        $sec = $data[datasize] / $header[bytespersec];
                        $minutes = intval(($sec / 60) % 60);
                        $seconds = intval($sec % 60);
                
                        return str_pad($minutes, 2, "0", STR_PAD_LEFT) . ":" . str_pad($seconds, 2, "0", STR_PAD_LEFT);
                
                    }
                
                }
                
                $file = '1.wav'; //Enter File wav
                calculateWavDuration($file);
                

                【讨论】:

                  【解决方案11】:

                  如果您安装了 FFMpeg,使用 FFProbe 获取持续时间非常简单

                  $filepath = 'example.mp3';
                  $ffprobe = \FFMpeg\FFProbe::create();
                  $duration = $ffprobe->format($filepath)->get('duration');
                  
                  echo gmdate('H:i:s', $duration);
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-05-12
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-12-30
                    • 1970-01-01
                    • 2011-06-20
                    相关资源
                    最近更新 更多