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.ac3.php // 0012 // module for analyzing AC-3 (aka Dolby Digital) audio files // 0013 // dependencies: NONE // 0014 // /// 0015 ///////////////////////////////////////////////////////////////// 0016 0017 0018 class getid3_ac3 extends getid3_handler 0019 { 0020 private $AC3header = array(); 0021 private $BSIoffset = 0; 0022 0023 const syncword = "\x0B\x77"; 0024 0025 public function Analyze() { 0026 $info = &$this->getid3->info; 0027 0028 ///AH 0029 $info['ac3']['raw']['bsi'] = array(); 0030 $thisfile_ac3 = &$info['ac3']; 0031 $thisfile_ac3_raw = &$thisfile_ac3['raw']; 0032 $thisfile_ac3_raw_bsi = &$thisfile_ac3_raw['bsi']; 0033 0034 0035 // http://www.atsc.org/standards/a_52a.pdf 0036 0037 $info['fileformat'] = 'ac3'; 0038 0039 // An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames 0040 // Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256 0041 // new audio samples per channel. A synchronization information (SI) header at the beginning 0042 // of each frame contains information needed to acquire and maintain synchronization. A 0043 // bit stream information (BSI) header follows SI, and contains parameters describing the coded 0044 // audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the 0045 // end of each frame is an error check field that includes a CRC word for error detection. An 0046 // additional CRC word is located in the SI header, the use of which, by a decoder, is optional. 0047 // 0048 // syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC 0049 0050 // syncinfo() { 0051 // syncword 16 0052 // crc1 16 0053 // fscod 2 0054 // frmsizecod 6 0055 // } /* end of syncinfo */ 0056 0057 $this->fseek($info['avdataoffset']); 0058 $this->AC3header['syncinfo'] = $this->fread(5); 0059 0060 if (strpos($this->AC3header['syncinfo'], self::syncword) === 0) { 0061 $thisfile_ac3_raw['synchinfo']['synchword'] = self::syncword; 0062 $offset = 2; 0063 } else { 0064 if (!$this->isDependencyFor('matroska')) { 0065 unset($info['fileformat'], $info['ac3']); 0066 return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)).'"'); 0067 } 0068 $offset = 0; 0069 $this->fseek(-2, SEEK_CUR); 0070 } 0071 0072 $info['audio']['dataformat'] = 'ac3'; 0073 $info['audio']['bitrate_mode'] = 'cbr'; 0074 $info['audio']['lossless'] = false; 0075 0076 $thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2)); 0077 $ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], ($offset + 2), 1)); 0078 $thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6; 0079 $thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F); 0080 0081 $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']); 0082 if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) { 0083 $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate']; 0084 } 0085 0086 $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']); 0087 $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']); 0088 $info['audio']['bitrate'] = $thisfile_ac3['bitrate']; 0089 0090 $this->AC3header['bsi'] = getid3_lib::BigEndian2Bin($this->fread(15)); 0091 $ac3_bsi_offset = 0; 0092 0093 $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); 0094 if ($thisfile_ac3_raw_bsi['bsid'] > 8) { 0095 // Decoders which can decode version 8 will thus be able to decode version numbers less than 8. 0096 // If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used. 0097 // Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8. 0098 $this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8'); 0099 unset($info['ac3']); 0100 return false; 0101 } 0102 0103 $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3); 0104 $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3); 0105 0106 $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']); 0107 $ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']); 0108 foreach($ac3_coding_mode as $key => $value) { 0109 $thisfile_ac3[$key] = $value; 0110 } 0111 switch ($thisfile_ac3_raw_bsi['acmod']) { 0112 case 0: 0113 case 1: 0114 $info['audio']['channelmode'] = 'mono'; 0115 break; 0116 case 3: 0117 case 4: 0118 $info['audio']['channelmode'] = 'stereo'; 0119 break; 0120 default: 0121 $info['audio']['channelmode'] = 'surround'; 0122 break; 0123 } 0124 $info['audio']['channels'] = $thisfile_ac3['num_channels']; 0125 0126 if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) { 0127 // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream. 0128 $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2); 0129 $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']); 0130 } 0131 0132 if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) { 0133 // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream. 0134 $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2); 0135 $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']); 0136 } 0137 0138 if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) { 0139 // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround. 0140 $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2); 0141 $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']); 0142 } 0143 0144 $thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1); 0145 $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon']; 0146 if ($thisfile_ac3_raw_bsi['lfeon']) { 0147 //$info['audio']['channels']++; 0148 $info['audio']['channels'] .= '.1'; 0149 } 0150 0151 $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']); 0152 0153 // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. 0154 // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. 0155 $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5); 0156 $thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB'; 0157 0158 $thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1); 0159 if ($thisfile_ac3_raw_bsi['compre_flag']) { 0160 $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8); 0161 $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']); 0162 } 0163 0164 $thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1); 0165 if ($thisfile_ac3_raw_bsi['langcode_flag']) { 0166 $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8); 0167 } 0168 0169 $thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1); 0170 if ($thisfile_ac3_raw_bsi['audprodie']) { 0171 $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5); 0172 $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2); 0173 0174 $thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB'; 0175 $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']); 0176 } 0177 0178 if ($thisfile_ac3_raw_bsi['acmod'] == 0x00) { 0179 // If acmod is 0, then two completely independent program channels (dual mono) 0180 // are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case, 0181 // a number of additional items are present in BSI or audblk to fully describe Ch2. 0182 0183 // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. 0184 // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. 0185 $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5); 0186 $thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB'; 0187 0188 $thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1); 0189 if ($thisfile_ac3_raw_bsi['compre_flag2']) { 0190 $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8); 0191 $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']); 0192 } 0193 0194 $thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1); 0195 if ($thisfile_ac3_raw_bsi['langcode_flag2']) { 0196 $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8); 0197 } 0198 0199 $thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1); 0200 if ($thisfile_ac3_raw_bsi['audprodie2']) { 0201 $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5); 0202 $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2); 0203 0204 $thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB'; 0205 $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']); 0206 } 0207 0208 } 0209 0210 $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1); 0211 0212 $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1); 0213 0214 $thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1); 0215 if ($thisfile_ac3_raw_bsi['timecode1_flag']) { 0216 $thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14); 0217 } 0218 0219 $thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1); 0220 if ($thisfile_ac3_raw_bsi['timecode2_flag']) { 0221 $thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14); 0222 } 0223 0224 $thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1); 0225 if ($thisfile_ac3_raw_bsi['addbsi_flag']) { 0226 $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6); 0227 0228 $this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length'])); 0229 0230 $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8); 0231 $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8; 0232 } 0233 0234 return true; 0235 } 0236 0237 private function readHeaderBSI($length) { 0238 $data = substr($this->AC3header['bsi'], $this->BSIoffset, $length); 0239 $this->BSIoffset += $length; 0240 0241 return bindec($data); 0242 } 0243 0244 public static function sampleRateCodeLookup($fscod) { 0245 static $sampleRateCodeLookup = array( 0246 0 => 48000, 0247 1 => 44100, 0248 2 => 32000, 0249 3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute. 0250 ); 0251 return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false); 0252 } 0253 0254 public static function serviceTypeLookup($bsmod, $acmod) { 0255 static $serviceTypeLookup = array(); 0256 if (empty($serviceTypeLookup)) { 0257 for ($i = 0; $i <= 7; $i++) { 0258 $serviceTypeLookup[0][$i] = 'main audio service: complete main (CM)'; 0259 $serviceTypeLookup[1][$i] = 'main audio service: music and effects (ME)'; 0260 $serviceTypeLookup[2][$i] = 'associated service: visually impaired (VI)'; 0261 $serviceTypeLookup[3][$i] = 'associated service: hearing impaired (HI)'; 0262 $serviceTypeLookup[4][$i] = 'associated service: dialogue (D)'; 0263 $serviceTypeLookup[5][$i] = 'associated service: commentary (C)'; 0264 $serviceTypeLookup[6][$i] = 'associated service: emergency (E)'; 0265 } 0266 0267 $serviceTypeLookup[7][1] = 'associated service: voice over (VO)'; 0268 for ($i = 2; $i <= 7; $i++) { 0269 $serviceTypeLookup[7][$i] = 'main audio service: karaoke'; 0270 } 0271 } 0272 return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false); 0273 } 0274 0275 public static function audioCodingModeLookup($acmod) { 0276 // array(channel configuration, # channels (not incl LFE), channel order) 0277 static $audioCodingModeLookup = array ( 0278 0 => array('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'), 0279 1 => array('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'), 0280 2 => array('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'), 0281 3 => array('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'), 0282 4 => array('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'), 0283 5 => array('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'), 0284 6 => array('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'), 0285 7 => array('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR'), 0286 ); 0287 return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false); 0288 } 0289 0290 public static function centerMixLevelLookup($cmixlev) { 0291 static $centerMixLevelLookup; 0292 if (empty($centerMixLevelLookup)) { 0293 $centerMixLevelLookup = array( 0294 0 => pow(2, -3.0 / 6), // 0.707 (-3.0 dB) 0295 1 => pow(2, -4.5 / 6), // 0.595 (-4.5 dB) 0296 2 => pow(2, -6.0 / 6), // 0.500 (-6.0 dB) 0297 3 => 'reserved' 0298 ); 0299 } 0300 return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false); 0301 } 0302 0303 public static function surroundMixLevelLookup($surmixlev) { 0304 static $surroundMixLevelLookup; 0305 if (empty($surroundMixLevelLookup)) { 0306 $surroundMixLevelLookup = array( 0307 0 => pow(2, -3.0 / 6), 0308 1 => pow(2, -6.0 / 6), 0309 2 => 0, 0310 3 => 'reserved' 0311 ); 0312 } 0313 return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false); 0314 } 0315 0316 public static function dolbySurroundModeLookup($dsurmod) { 0317 static $dolbySurroundModeLookup = array( 0318 0 => 'not indicated', 0319 1 => 'Not Dolby Surround encoded', 0320 2 => 'Dolby Surround encoded', 0321 3 => 'reserved' 0322 ); 0323 return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false); 0324 } 0325 0326 public static function channelsEnabledLookup($acmod, $lfeon) { 0327 $lookup = array( 0328 'ch1'=>(bool) ($acmod == 0), 0329 'ch2'=>(bool) ($acmod == 0), 0330 'left'=>(bool) ($acmod > 1), 0331 'right'=>(bool) ($acmod > 1), 0332 'center'=>(bool) ($acmod & 0x01), 0333 'surround_mono'=>false, 0334 'surround_left'=>false, 0335 'surround_right'=>false, 0336 'lfe'=>$lfeon); 0337 switch ($acmod) { 0338 case 4: 0339 case 5: 0340 $lookup['surround_mono'] = true; 0341 break; 0342 case 6: 0343 case 7: 0344 $lookup['surround_left'] = true; 0345 $lookup['surround_right'] = true; 0346 break; 0347 } 0348 return $lookup; 0349 } 0350 0351 public static function heavyCompression($compre) { 0352 // The first four bits indicate gain changes in 6.02dB increments which can be 0353 // implemented with an arithmetic shift operation. The following four bits 0354 // indicate linear gain changes, and require a 5-bit multiply. 0355 // We will represent the two 4-bit fields of compr as follows: 0356 // X0 X1 X2 X3 . Y4 Y5 Y6 Y7 0357 // The meaning of the X values is most simply described by considering X to represent a 4-bit 0358 // signed integer with values from -8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The 0359 // following table shows this in detail. 0360 0361 // Meaning of 4 msb of compr 0362 // 7 +48.16 dB 0363 // 6 +42.14 dB 0364 // 5 +36.12 dB 0365 // 4 +30.10 dB 0366 // 3 +24.08 dB 0367 // 2 +18.06 dB 0368 // 1 +12.04 dB 0369 // 0 +6.02 dB 0370 // -1 0 dB 0371 // -2 -6.02 dB 0372 // -3 -12.04 dB 0373 // -4 -18.06 dB 0374 // -5 -24.08 dB 0375 // -6 -30.10 dB 0376 // -7 -36.12 dB 0377 // -8 -42.14 dB 0378 0379 $fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT); 0380 if ($fourbit{0} == '1') { 0381 $log_gain = -8 + bindec(substr($fourbit, 1)); 0382 } else { 0383 $log_gain = bindec(substr($fourbit, 1)); 0384 } 0385 $log_gain = ($log_gain + 1) * getid3_lib::RGADamplitude2dB(2); 0386 0387 // The value of Y is a linear representation of a gain change of up to -6 dB. Y is considered to 0388 // be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can 0389 // represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain 0390 // changes from -0.28 dB to -6.02 dB. 0391 0392 $lin_gain = (16 + ($compre & 0x0F)) / 32; 0393 0394 // The combination of X and Y values allows compr to indicate gain changes from 0395 // 48.16 - 0.28 = +47.89 dB, to 0396 // -42.14 - 6.02 = -48.16 dB. 0397 0398 return $log_gain - $lin_gain; 0399 } 0400 0401 public static function roomTypeLookup($roomtyp) { 0402 static $roomTypeLookup = array( 0403 0 => 'not indicated', 0404 1 => 'large room, X curve monitor', 0405 2 => 'small room, flat monitor', 0406 3 => 'reserved' 0407 ); 0408 return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false); 0409 } 0410 0411 public static function frameSizeLookup($frmsizecod, $fscod) { 0412 $padding = (bool) ($frmsizecod % 2); 0413 $framesizeid = floor($frmsizecod / 2); 0414 0415 static $frameSizeLookup = array(); 0416 if (empty($frameSizeLookup)) { 0417 $frameSizeLookup = array ( 0418 0 => array(128, 138, 192), 0419 1 => array(40, 160, 174, 240), 0420 2 => array(48, 192, 208, 288), 0421 3 => array(56, 224, 242, 336), 0422 4 => array(64, 256, 278, 384), 0423 5 => array(80, 320, 348, 480), 0424 6 => array(96, 384, 416, 576), 0425 7 => array(112, 448, 486, 672), 0426 8 => array(128, 512, 556, 768), 0427 9 => array(160, 640, 696, 960), 0428 10 => array(192, 768, 834, 1152), 0429 11 => array(224, 896, 974, 1344), 0430 12 => array(256, 1024, 1114, 1536), 0431 13 => array(320, 1280, 1392, 1920), 0432 14 => array(384, 1536, 1670, 2304), 0433 15 => array(448, 1792, 1950, 2688), 0434 16 => array(512, 2048, 2228, 3072), 0435 17 => array(576, 2304, 2506, 3456), 0436 18 => array(640, 2560, 2786, 3840) 0437 ); 0438 } 0439 if (($fscod == 1) && $padding) { 0440 // frame lengths are padded by 1 word (16 bits) at 44100 0441 $frameSizeLookup[$frmsizecod] += 2; 0442 } 0443 return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false); 0444 } 0445 0446 public static function bitrateLookup($frmsizecod) { 0447 $framesizeid = floor($frmsizecod / 2); 0448 0449 static $bitrateLookup = array( 0450 0 => 32000, 0451 1 => 40000, 0452 2 => 48000, 0453 3 => 56000, 0454 4 => 64000, 0455 5 => 80000, 0456 6 => 96000, 0457 7 => 112000, 0458 8 => 128000, 0459 9 => 160000, 0460 10 => 192000, 0461 11 => 224000, 0462 12 => 256000, 0463 13 => 320000, 0464 14 => 384000, 0465 15 => 448000, 0466 16 => 512000, 0467 17 => 576000, 0468 18 => 640000 0469 ); 0470 return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false); 0471 } 0472 0473 0474 }