File indexing completed on 2024-12-22 05:33:12
0001 <?php 0002 ///////////////////////////////////////////////////////////////// 0003 /// getID3() by James Heinrich <info@getid3.org> // 0004 // available at http://getid3.sourceforge.net // 0005 // or http://www.getid3.org // 0006 // also https://github.com/JamesHeinrich/getID3 // 0007 ///////////////////////////////////////////////////////////////// 0008 // See readme.txt for more details // 0009 ///////////////////////////////////////////////////////////////// 0010 // // 0011 // module.audio.aa.php // 0012 // module for analyzing Audible Audiobook files // 0013 // dependencies: NONE // 0014 // /// 0015 ///////////////////////////////////////////////////////////////// 0016 0017 0018 class getid3_amr extends getid3_handler 0019 { 0020 0021 public function Analyze() { 0022 $info = &$this->getid3->info; 0023 0024 $this->fseek($info['avdataoffset']); 0025 $AMRheader = $this->fread(6); 0026 0027 $magic = '#!AMR'."\x0A"; 0028 if (substr($AMRheader, 0, 6) != $magic) { 0029 $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AMRheader, 0, 6)).'"'; 0030 return false; 0031 } 0032 0033 // shortcut 0034 $info['amr'] = array(); 0035 $thisfile_amr = &$info['amr']; 0036 0037 $info['fileformat'] = 'amr'; 0038 $info['audio']['dataformat'] = 'amr'; 0039 $info['audio']['bitrate_mode'] = 'vbr'; // within a small predefined range: 4.75kbps to 12.2kbps 0040 $info['audio']['bits_per_sample'] = 13; // http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec: "Sampling frequency 8 kHz/13-bit (160 samples for 20 ms frames), filtered to 200–3400 Hz" 0041 $info['audio']['sample_rate'] = 8000; // http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec: "Sampling frequency 8 kHz/13-bit (160 samples for 20 ms frames), filtered to 200–3400 Hz" 0042 $info['audio']['channels'] = 1; 0043 $thisfile_amr['frame_mode_count'] = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0); 0044 0045 $buffer = ''; 0046 do { 0047 if ((strlen($buffer) < $this->getid3->fread_buffer_size()) && !feof($this->getid3->fp)) { 0048 $buffer .= $this->fread($this->getid3->fread_buffer_size() * 2); 0049 } 0050 $AMR_frame_header = ord(substr($buffer, 0, 1)); 0051 $codec_mode_request = ($AMR_frame_header & 0x78) >> 3; // The 2nd bit through 5th bit (counting the most significant bit as the first bit) comprise the CMR (Codec Mode Request), values 0-7 being valid for AMR. The top bit of the CMR can actually be ignored, though it is used when AMR forms RTP payloads. The lower 3-bits of the header are reserved and are not used. Viewing the header from most significant bit to least significant bit, the encoding is XCCCCXXX, where Xs are reserved (typically 0) and the Cs are the CMR. 0052 if ($codec_mode_request > 7) { 0053 $info['error'][] = ''; 0054 break; 0055 } 0056 $thisfile_amr['frame_mode_count'][$codec_mode_request]++; 0057 $buffer = substr($buffer, $this->amr_mode_bytes_per_frame($codec_mode_request)); 0058 } while (strlen($buffer) > 0); 0059 0060 $info['playtime_seconds'] = array_sum($thisfile_amr['frame_mode_count']) * 0.020; // each frame contain 160 samples and is 20 milliseconds long 0061 $info['audio']['bitrate'] = (8 * ($info['avdataend'] - $info['avdataoffset'])) / $info['playtime_seconds']; // bitrate could be calculated from average bitrate by distributation of frame types. That would give effective audio bitrate, this gives overall file bitrate which will be a little bit higher since every frame will waste 8 bits for header, plus a few bits for octet padding 0062 $info['bitrate'] = $info['audio']['bitrate']; 0063 0064 return true; 0065 } 0066 0067 0068 public function amr_mode_bitrate($key) { 0069 static $amr_mode_bitrate = array( 0070 0 => 4750, 0071 1 => 5150, 0072 2 => 5900, 0073 3 => 6700, 0074 4 => 7400, 0075 5 => 7950, 0076 6 => 10200, 0077 7 => 12200, 0078 ); 0079 return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false); 0080 } 0081 0082 public function amr_mode_bytes_per_frame($key) { 0083 static $amr_mode_bitrate = array( 0084 0 => 13, // 1-byte frame header + 95 bits [padded to: 12 bytes] audio data 0085 1 => 14, // 1-byte frame header + 103 bits [padded to: 13 bytes] audio data 0086 2 => 16, // 1-byte frame header + 118 bits [padded to: 15 bytes] audio data 0087 3 => 18, // 1-byte frame header + 134 bits [padded to: 17 bytes] audio data 0088 4 => 20, // 1-byte frame header + 148 bits [padded to: 19 bytes] audio data 0089 5 => 21, // 1-byte frame header + 159 bits [padded to: 20 bytes] audio data 0090 6 => 27, // 1-byte frame header + 204 bits [padded to: 26 bytes] audio data 0091 7 => 32, // 1-byte frame header + 244 bits [padded to: 31 bytes] audio data 0092 ); 0093 return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false); 0094 } 0095 0096 0097 }