annotate e2gallerypro/e2upload/Backend/Assets/getid3/module.audio.aac_adts.php @ 20:1038db2374ec judyates

change address
author Robert McIntyre <rlm@mit.edu>
date Sun, 08 Sep 2013 00:47:09 -0400
parents 3f6b44aa6b35
children
rev   line source
rlm@3 1 <?php
rlm@3 2 // +----------------------------------------------------------------------+
rlm@3 3 // | PHP version 5 |
rlm@3 4 // +----------------------------------------------------------------------+
rlm@3 5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen |
rlm@3 6 // +----------------------------------------------------------------------+
rlm@3 7 // | This source file is subject to version 2 of the GPL license, |
rlm@3 8 // | that is bundled with this package in the file license.txt and is |
rlm@3 9 // | available through the world-wide-web at the following url: |
rlm@3 10 // | http://www.gnu.org/copyleft/gpl.html |
rlm@3 11 // +----------------------------------------------------------------------+
rlm@3 12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
rlm@3 13 // +----------------------------------------------------------------------+
rlm@3 14 // | Authors: James Heinrich <infoØgetid3*org> |
rlm@3 15 // | Allan Hansen <ahØartemis*dk> |
rlm@3 16 // +----------------------------------------------------------------------+
rlm@3 17 // | module.audio.aac_adts.php |
rlm@3 18 // | Module for analyzing AAC files with ADTS header. |
rlm@3 19 // | dependencies: NONE |
rlm@3 20 // +----------------------------------------------------------------------+
rlm@3 21 //
rlm@3 22 // $Id: module.audio.aac_adts.php,v 1.4 2006/11/02 10:48:01 ah Exp $
rlm@3 23
rlm@3 24
rlm@3 25
rlm@3 26 class getid3_aac_adts extends getid3_handler
rlm@3 27 {
rlm@3 28
rlm@3 29 public $option_max_frames_to_scan = 1000000;
rlm@3 30 public $option_return_extended_info = false;
rlm@3 31
rlm@3 32
rlm@3 33 private $decbin_cache;
rlm@3 34 private $bitrate_cache;
rlm@3 35
rlm@3 36
rlm@3 37
rlm@3 38 public function __construct(getID3 $getid3) {
rlm@3 39
rlm@3 40 parent::__construct($getid3);
rlm@3 41
rlm@3 42 // Populate bindec_cache
rlm@3 43 for ($i = 0; $i < 256; $i++) {
rlm@3 44 $this->decbin_cache[chr($i)] = str_pad(decbin($i), 8, '0', STR_PAD_LEFT);
rlm@3 45 }
rlm@3 46
rlm@3 47 // Init cache
rlm@3 48 $this->bitrate_cache = array ();
rlm@3 49
rlm@3 50 // Fast scanning?
rlm@3 51 if (!$getid3->option_accurate_results) {
rlm@3 52 $this->option_max_frames_to_scan = 200;
rlm@3 53 $getid3->warning('option_accurate_results set to false - bitrate and playing time are not accurate.');
rlm@3 54 }
rlm@3 55 }
rlm@3 56
rlm@3 57
rlm@3 58
rlm@3 59 public function Analyze() {
rlm@3 60
rlm@3 61 $getid3 = $this->getid3;
rlm@3 62
rlm@3 63 // based loosely on code from AACfile by Jurgen Faul <jfaulØgmx.de>
rlm@3 64 // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
rlm@3 65
rlm@3 66
rlm@3 67 // http://faac.sourceforge.net/wiki/index.php?page=ADTS
rlm@3 68
rlm@3 69 // * ADTS Fixed Header: these don't change from frame to frame
rlm@3 70 // syncword 12 always: '111111111111'
rlm@3 71 // ID 1 0: MPEG-4, 1: MPEG-2
rlm@3 72 // layer 2 always: '00'
rlm@3 73 // protection_absent 1
rlm@3 74 // profile 2
rlm@3 75 // sampling_frequency_index 4
rlm@3 76 // private_bit 1
rlm@3 77 // channel_configuration 3
rlm@3 78 // original/copy 1
rlm@3 79 // home 1
rlm@3 80 // emphasis 2 only if ID == 0 (ie MPEG-4)
rlm@3 81
rlm@3 82 // * ADTS Variable Header: these can change from frame to frame
rlm@3 83 // copyright_identification_bit 1
rlm@3 84 // copyright_identification_start 1
rlm@3 85 // aac_frame_length 13 length of the frame including header (in bytes)
rlm@3 86 // adts_buffer_fullness 11 0x7FF indicates VBR
rlm@3 87 // no_raw_data_blocks_in_frame 2
rlm@3 88
rlm@3 89 // * ADTS Error check
rlm@3 90 // crc_check 16 only if protection_absent == 0
rlm@3 91
rlm@3 92 $getid3->info['aac']['header'] = array () ;
rlm@3 93 $info_aac = &$getid3->info['aac'];
rlm@3 94 $info_aac_header = & $info_aac['header'];
rlm@3 95
rlm@3 96 $byte_offset = $frame_number = 0;
rlm@3 97
rlm@3 98 while (true) {
rlm@3 99
rlm@3 100 // Breaks out when end-of-file encountered, or invalid data found,
rlm@3 101 // or MaxFramesToScan frames have been scanned
rlm@3 102
rlm@3 103 fseek($getid3->fp, $byte_offset, SEEK_SET);
rlm@3 104
rlm@3 105 // First get substring
rlm@3 106 $sub_string = fread($getid3->fp, 10);
rlm@3 107 $sub_string_length = strlen($sub_string);
rlm@3 108 if ($sub_string_length != 10) {
rlm@3 109 throw new getid3_exception('Failed to read 10 bytes at offset '.(ftell($getid3->fp) - $sub_string_length).' (only read '.$sub_string_length.' bytes)');
rlm@3 110 }
rlm@3 111
rlm@3 112 // Initialise $aac_header_bitstream
rlm@3 113 $aac_header_bitstream = '';
rlm@3 114
rlm@3 115 // Loop thru substring chars
rlm@3 116 for ($i = 0; $i < 10; $i++) {
rlm@3 117 $aac_header_bitstream .= $this->decbin_cache[$sub_string[$i]];
rlm@3 118 }
rlm@3 119
rlm@3 120 $sync_test = bindec(substr($aac_header_bitstream, 0, 12));
rlm@3 121 $bit_offset = 12;
rlm@3 122
rlm@3 123 if ($sync_test != 0x0FFF) {
rlm@3 124 throw new getid3_exception('Synch pattern (0x0FFF) not found at offset '.(ftell($getid3->fp) - 10).' (found 0x0'.strtoupper(dechex($sync_test)).' instead)');
rlm@3 125 }
rlm@3 126
rlm@3 127 // Only gather info once - this takes time to do 1000 times!
rlm@3 128 if ($frame_number > 0) {
rlm@3 129
rlm@3 130 // MPEG-4: 20, // MPEG-2: 18
rlm@3 131 $bit_offset += $aac_header_bitstream[$bit_offset] ? 18 : 20;
rlm@3 132 }
rlm@3 133
rlm@3 134 // Gather info for first frame only - this takes time to do 1000 times!
rlm@3 135 else {
rlm@3 136
rlm@3 137 $info_aac['header_type'] = 'ADTS';
rlm@3 138 $info_aac_header['synch'] = $sync_test;
rlm@3 139 $getid3->info['fileformat'] = 'aac';
rlm@3 140 $getid3->info['audio']['dataformat'] = 'aac';
rlm@3 141
rlm@3 142 $info_aac_header['mpeg_version'] = $aac_header_bitstream{$bit_offset++} == '0' ? 4 : 2;
rlm@3 143 $info_aac_header['layer'] = bindec(substr($aac_header_bitstream, $bit_offset, 2));
rlm@3 144 $bit_offset += 2;
rlm@3 145
rlm@3 146 if ($info_aac_header['layer'] != 0) {
rlm@3 147 throw new getid3_exception('Layer error - expected 0x00, found 0x'.dechex($info_aac_header['layer']).' instead');
rlm@3 148 }
rlm@3 149
rlm@3 150 $info_aac_header['crc_present'] = $aac_header_bitstream{$bit_offset++} == '0' ? true : false;
rlm@3 151
rlm@3 152 $info_aac_header['profile_id'] = bindec(substr($aac_header_bitstream, $bit_offset, 2));
rlm@3 153 $bit_offset += 2;
rlm@3 154
rlm@3 155 $info_aac_header['profile_text'] = getid3_aac_adts::AACprofileLookup($info_aac_header['profile_id'], $info_aac_header['mpeg_version']);
rlm@3 156
rlm@3 157 $info_aac_header['sample_frequency_index'] = bindec(substr($aac_header_bitstream, $bit_offset, 4));
rlm@3 158 $bit_offset += 4;
rlm@3 159
rlm@3 160 $info_aac_header['sample_frequency'] = getid3_aac_adts::AACsampleRateLookup($info_aac_header['sample_frequency_index']);
rlm@3 161
rlm@3 162 $getid3->info['audio']['sample_rate'] = $info_aac_header['sample_frequency'];
rlm@3 163
rlm@3 164 $info_aac_header['private'] = $aac_header_bitstream{$bit_offset++} == 1;
rlm@3 165
rlm@3 166 $info_aac_header['channel_configuration'] = $getid3->info['audio']['channels'] = bindec(substr($aac_header_bitstream, $bit_offset, 3));
rlm@3 167 $bit_offset += 3;
rlm@3 168
rlm@3 169 $info_aac_header['original'] = $aac_header_bitstream{$bit_offset++} == 1;
rlm@3 170 $info_aac_header['home'] = $aac_header_bitstream{$bit_offset++} == 1;
rlm@3 171
rlm@3 172 if ($info_aac_header['mpeg_version'] == 4) {
rlm@3 173 $info_aac_header['emphasis'] = bindec(substr($aac_header_bitstream, $bit_offset, 2));
rlm@3 174 $bit_offset += 2;
rlm@3 175 }
rlm@3 176
rlm@3 177 if ($this->option_return_extended_info) {
rlm@3 178
rlm@3 179 $info_aac[$frame_number]['copyright_id_bit'] = $aac_header_bitstream{$bit_offset++} == 1;
rlm@3 180 $info_aac[$frame_number]['copyright_id_start'] = $aac_header_bitstream{$bit_offset++} == 1;
rlm@3 181
rlm@3 182 } else {
rlm@3 183 $bit_offset += 2;
rlm@3 184 }
rlm@3 185 }
rlm@3 186
rlm@3 187 $frame_length = bindec(substr($aac_header_bitstream, $bit_offset, 13));
rlm@3 188
rlm@3 189 if (!isset($this->bitrate_cache[$frame_length])) {
rlm@3 190 $this->bitrate_cache[$frame_length] = ($info_aac_header['sample_frequency'] / 1024) * $frame_length * 8;
rlm@3 191 }
rlm@3 192 @$info_aac['bitrate_distribution'][$this->bitrate_cache[$frame_length]]++;
rlm@3 193
rlm@3 194 $info_aac[$frame_number]['aac_frame_length'] = $frame_length;
rlm@3 195 $bit_offset += 13;
rlm@3 196
rlm@3 197 $info_aac[$frame_number]['adts_buffer_fullness'] = bindec(substr($aac_header_bitstream, $bit_offset, 11));
rlm@3 198 $bit_offset += 11;
rlm@3 199
rlm@3 200 $getid3->info['audio']['bitrate_mode'] = ($info_aac[$frame_number]['adts_buffer_fullness'] == 0x07FF) ? 'vbr' : 'cbr';
rlm@3 201
rlm@3 202 $info_aac[$frame_number]['num_raw_data_blocks'] = bindec(substr($aac_header_bitstream, $bit_offset, 2));
rlm@3 203 $bit_offset += 2;
rlm@3 204
rlm@3 205 if ($info_aac_header['crc_present']) {
rlm@3 206 $bit_offset += 16;
rlm@3 207 }
rlm@3 208
rlm@3 209 if (!$this->option_return_extended_info) {
rlm@3 210 unset($info_aac[$frame_number]);
rlm@3 211 }
rlm@3 212
rlm@3 213 $byte_offset += $frame_length;
rlm@3 214 if ((++$frame_number < $this->option_max_frames_to_scan) && (($byte_offset + 10) < $getid3->info['avdataend'])) {
rlm@3 215
rlm@3 216 // keep scanning
rlm@3 217
rlm@3 218 } else {
rlm@3 219
rlm@3 220 $info_aac['frames'] = $frame_number;
rlm@3 221 $getid3->info['playtime_seconds'] = ($getid3->info['avdataend'] / $byte_offset) * (($frame_number * 1024) / $info_aac_header['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds
rlm@3 222 $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds'];
rlm@3 223 ksort($info_aac['bitrate_distribution']);
rlm@3 224
rlm@3 225 $getid3->info['audio']['encoder_options'] = $info_aac['header_type'].' '.$info_aac_header['profile_text'];
rlm@3 226
rlm@3 227 return true;
rlm@3 228 }
rlm@3 229 }
rlm@3 230 }
rlm@3 231
rlm@3 232
rlm@3 233
rlm@3 234 public static function AACsampleRateLookup($samplerate_id) {
rlm@3 235
rlm@3 236 static $lookup = array (
rlm@3 237 0 => 96000,
rlm@3 238 1 => 88200,
rlm@3 239 2 => 64000,
rlm@3 240 3 => 48000,
rlm@3 241 4 => 44100,
rlm@3 242 5 => 32000,
rlm@3 243 6 => 24000,
rlm@3 244 7 => 22050,
rlm@3 245 8 => 16000,
rlm@3 246 9 => 12000,
rlm@3 247 10 => 11025,
rlm@3 248 11 => 8000,
rlm@3 249 12 => 0,
rlm@3 250 13 => 0,
rlm@3 251 14 => 0,
rlm@3 252 15 => 0
rlm@3 253 );
rlm@3 254 return (isset($lookup[$samplerate_id]) ? $lookup[$samplerate_id] : 'invalid');
rlm@3 255 }
rlm@3 256
rlm@3 257
rlm@3 258
rlm@3 259 public static function AACprofileLookup($profile_id, $mpeg_version) {
rlm@3 260
rlm@3 261 static $lookup = array (
rlm@3 262 2 => array (
rlm@3 263 0 => 'Main profile',
rlm@3 264 1 => 'Low Complexity profile (LC)',
rlm@3 265 2 => 'Scalable Sample Rate profile (SSR)',
rlm@3 266 3 => '(reserved)'
rlm@3 267 ),
rlm@3 268 4 => array (
rlm@3 269 0 => 'AAC_MAIN',
rlm@3 270 1 => 'AAC_LC',
rlm@3 271 2 => 'AAC_SSR',
rlm@3 272 3 => 'AAC_LTP'
rlm@3 273 )
rlm@3 274 );
rlm@3 275 return (isset($lookup[$mpeg_version][$profile_id]) ? $lookup[$mpeg_version][$profile_id] : 'invalid');
rlm@3 276 }
rlm@3 277
rlm@3 278
rlm@3 279 }
rlm@3 280
rlm@3 281
rlm@3 282 ?>