File indexing completed on 2024-05-12 17:25:57

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-video.riff.php                                 //
0012 // module for analyzing RIFF files                             //
0013 // multiple formats supported by this module:                  //
0014 //    Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack v3, 8SVX   //
0015 // dependencies: module.audio.mp3.php                          //
0016 //               module.audio.ac3.php                          //
0017 //               module.audio.dts.php                          //
0018 //                                                            ///
0019 /////////////////////////////////////////////////////////////////
0020 
0021 /**
0022 * @todo Parse AC-3/DTS audio inside WAVE correctly
0023 * @todo Rewrite RIFF parser totally
0024 */
0025 
0026 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
0027 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
0028 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
0029 
0030 class getid3_riff extends getid3_handler {
0031 
0032   protected $container = 'riff'; // default
0033 
0034   public function Analyze() {
0035     $info = &$this->getid3->info;
0036 
0037     // initialize these values to an empty array, otherwise they default to NULL
0038     // and you can't append array values to a NULL value
0039     $info['riff'] = array('raw'=>array());
0040 
0041     // Shortcuts
0042     $thisfile_riff             = &$info['riff'];
0043     $thisfile_riff_raw         = &$thisfile_riff['raw'];
0044     $thisfile_audio            = &$info['audio'];
0045     $thisfile_video            = &$info['video'];
0046     $thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
0047     $thisfile_riff_audio       = &$thisfile_riff['audio'];
0048     $thisfile_riff_video       = &$thisfile_riff['video'];
0049 
0050     $Original['avdataoffset'] = $info['avdataoffset'];
0051     $Original['avdataend']    = $info['avdataend'];
0052 
0053     $this->fseek($info['avdataoffset']);
0054     $RIFFheader = $this->fread(12);
0055     $offset = $this->ftell();
0056     $RIFFtype    = substr($RIFFheader, 0, 4);
0057     $RIFFsize    = substr($RIFFheader, 4, 4);
0058     $RIFFsubtype = substr($RIFFheader, 8, 4);
0059 
0060     switch ($RIFFtype) {
0061 
0062       case 'FORM':  // AIFF, AIFC
0063         //$info['fileformat']   = 'aiff';
0064         $this->container = 'aiff';
0065         $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
0066         $thisfile_riff[$RIFFsubtype]  = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
0067         break;
0068 
0069       case 'RIFF':  // AVI, WAV, etc
0070       case 'SDSS':  // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
0071       case 'RMP3':  // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
0072         //$info['fileformat']   = 'riff';
0073         $this->container = 'riff';
0074         $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
0075         if ($RIFFsubtype == 'RMP3') {
0076           // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
0077           $RIFFsubtype = 'WAVE';
0078         }
0079         if ($RIFFsubtype != 'AMV ') {
0080           // AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
0081           // Handled separately in ParseRIFFAMV()
0082           $thisfile_riff[$RIFFsubtype]  = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
0083         }
0084         if (($info['avdataend'] - $info['filesize']) == 1) {
0085           // LiteWave appears to incorrectly *not* pad actual output file
0086           // to nearest WORD boundary so may appear to be short by one
0087           // byte, in which case - skip warning
0088           $info['avdataend'] = $info['filesize'];
0089         }
0090 
0091         $nextRIFFoffset = $Original['avdataoffset'] + 8 + $thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset
0092         while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) {
0093           try {
0094             $this->fseek($nextRIFFoffset);
0095           } catch (getid3_exception $e) {
0096             if ($e->getCode() == 10) {
0097               //$this->warning('RIFF parser: '.$e->getMessage());
0098               $this->error('AVI extends beyond '.round(PHP_INT_MAX / 1073741824).'GB and PHP filesystem functions cannot read that far, playtime may be wrong');
0099               $this->warning('[avdataend] value may be incorrect, multiple AVIX chunks may be present');
0100               break;
0101             } else {
0102               throw $e;
0103             }
0104           }
0105           $nextRIFFheader = $this->fread(12);
0106           if ($nextRIFFoffset == ($info['avdataend'] - 1)) {
0107             if (substr($nextRIFFheader, 0, 1) == "\x00") {
0108               // RIFF padded to WORD boundary, we're actually already at the end
0109               break;
0110             }
0111           }
0112           $nextRIFFheaderID =                         substr($nextRIFFheader, 0, 4);
0113           $nextRIFFsize     = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4));
0114           $nextRIFFtype     =                         substr($nextRIFFheader, 8, 4);
0115           $chunkdata = array();
0116           $chunkdata['offset'] = $nextRIFFoffset + 8;
0117           $chunkdata['size']   = $nextRIFFsize;
0118           $nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
0119 
0120           switch ($nextRIFFheaderID) {
0121             case 'RIFF':
0122               $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset);
0123               if (!isset($thisfile_riff[$nextRIFFtype])) {
0124                 $thisfile_riff[$nextRIFFtype] = array();
0125               }
0126               $thisfile_riff[$nextRIFFtype][] = $chunkdata;
0127               break;
0128 
0129             case 'AMV ':
0130               unset($info['riff']);
0131               $info['amv'] = $this->ParseRIFFAMV($chunkdata['offset'] + 4, $nextRIFFoffset);
0132               break;
0133 
0134             case 'JUNK':
0135               // ignore
0136               $thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
0137               break;
0138 
0139             case 'IDVX':
0140               $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunkdata['size']));
0141               break;
0142 
0143             default:
0144               if ($info['filesize'] == ($chunkdata['offset'] - 8 + 128)) {
0145                 $DIVXTAG = $nextRIFFheader.$this->fread(128 - 12);
0146                 if (substr($DIVXTAG, -7) == 'DIVXTAG') {
0147                   // DIVXTAG is supposed to be inside an IDVX chunk in a LIST chunk, but some bad encoders just slap it on the end of a file
0148                   $this->warning('Found wrongly-structured DIVXTAG at offset '.($this->ftell() - 128).', parsing anyway');
0149                   $info['divxtag']['comments'] = self::ParseDIVXTAG($DIVXTAG);
0150                   break 2;
0151                 }
0152               }
0153               $this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file');
0154               break 2;
0155 
0156           }
0157 
0158         }
0159         if ($RIFFsubtype == 'WAVE') {
0160           $thisfile_riff_WAVE = &$thisfile_riff['WAVE'];
0161         }
0162         break;
0163 
0164       default:
0165         $this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead');
0166         //unset($info['fileformat']);
0167         return false;
0168     }
0169 
0170     $streamindex = 0;
0171     switch ($RIFFsubtype) {
0172 
0173       // http://en.wikipedia.org/wiki/Wav
0174       case 'WAVE':
0175         $info['fileformat'] = 'wav';
0176 
0177         if (empty($thisfile_audio['bitrate_mode'])) {
0178           $thisfile_audio['bitrate_mode'] = 'cbr';
0179         }
0180         if (empty($thisfile_audio_dataformat)) {
0181           $thisfile_audio_dataformat = 'wav';
0182         }
0183 
0184         if (isset($thisfile_riff_WAVE['data'][0]['offset'])) {
0185           $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] + 8;
0186           $info['avdataend']    = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size'];
0187         }
0188         if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
0189 
0190           $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
0191           $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
0192           if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) {
0193             $info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero';
0194             return false;
0195           }
0196           $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
0197           unset($thisfile_riff_audio[$streamindex]['raw']);
0198           $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
0199 
0200           $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
0201           if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
0202             $info['warning'][] = 'Audio codec = '.$thisfile_audio['codec'];
0203           }
0204           $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
0205 
0206           if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV)
0207             $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
0208           }
0209 
0210           $thisfile_audio['lossless'] = false;
0211           if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
0212             switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
0213 
0214               case 0x0001:  // PCM
0215                 $thisfile_audio['lossless'] = true;
0216                 break;
0217 
0218               case 0x2000:  // AC-3
0219                 $thisfile_audio_dataformat = 'ac3';
0220                 break;
0221 
0222               default:
0223                 // do nothing
0224                 break;
0225 
0226             }
0227           }
0228           $thisfile_audio['streams'][$streamindex]['wformattag']   = $thisfile_audio['wformattag'];
0229           $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
0230           $thisfile_audio['streams'][$streamindex]['lossless']     = $thisfile_audio['lossless'];
0231           $thisfile_audio['streams'][$streamindex]['dataformat']   = $thisfile_audio_dataformat;
0232         }
0233 
0234         if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
0235 
0236           // shortcuts
0237           $rgadData = &$thisfile_riff_WAVE['rgad'][0]['data'];
0238           $thisfile_riff_raw['rgad']    = array('track'=>array(), 'album'=>array());
0239           $thisfile_riff_raw_rgad       = &$thisfile_riff_raw['rgad'];
0240           $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track'];
0241           $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album'];
0242 
0243           $thisfile_riff_raw_rgad['fPeakAmplitude']      = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4));
0244           $thisfile_riff_raw_rgad['nRadioRgAdjust']      =        $this->EitherEndian2Int(substr($rgadData, 4, 2));
0245           $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] =        $this->EitherEndian2Int(substr($rgadData, 6, 2));
0246 
0247           $nRadioRgAdjustBitstring      = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
0248           $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
0249           $thisfile_riff_raw_rgad_track['name']       = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
0250           $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
0251           $thisfile_riff_raw_rgad_track['signbit']    = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
0252           $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
0253           $thisfile_riff_raw_rgad_album['name']       = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
0254           $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
0255           $thisfile_riff_raw_rgad_album['signbit']    = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
0256           $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
0257 
0258           $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude'];
0259           if (($thisfile_riff_raw_rgad_track['name'] != 0) && ($thisfile_riff_raw_rgad_track['originator'] != 0)) {
0260             $thisfile_riff['rgad']['track']['name']            = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']);
0261             $thisfile_riff['rgad']['track']['originator']      = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']);
0262             $thisfile_riff['rgad']['track']['adjustment']      = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']);
0263           }
0264           if (($thisfile_riff_raw_rgad_album['name'] != 0) && ($thisfile_riff_raw_rgad_album['originator'] != 0)) {
0265             $thisfile_riff['rgad']['album']['name']       = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']);
0266             $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']);
0267             $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']);
0268           }
0269         }
0270 
0271         if (isset($thisfile_riff_WAVE['fact'][0]['data'])) {
0272           $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4));
0273 
0274           // This should be a good way of calculating exact playtime,
0275           // but some sample files have had incorrect number of samples,
0276           // so cannot use this method
0277 
0278           // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
0279           //     $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
0280           // }
0281         }
0282         if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
0283           $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
0284         }
0285 
0286         if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
0287           // shortcut
0288           $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
0289 
0290           $thisfile_riff_WAVE_bext_0['title']          =                         trim(substr($thisfile_riff_WAVE_bext_0['data'],   0, 256));
0291           $thisfile_riff_WAVE_bext_0['author']         =                         trim(substr($thisfile_riff_WAVE_bext_0['data'], 256,  32));
0292           $thisfile_riff_WAVE_bext_0['reference']      =                         trim(substr($thisfile_riff_WAVE_bext_0['data'], 288,  32));
0293           $thisfile_riff_WAVE_bext_0['origin_date']    =                              substr($thisfile_riff_WAVE_bext_0['data'], 320,  10);
0294           $thisfile_riff_WAVE_bext_0['origin_time']    =                              substr($thisfile_riff_WAVE_bext_0['data'], 330,   8);
0295           $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338,   8));
0296           $thisfile_riff_WAVE_bext_0['bwf_version']    = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346,   1));
0297           $thisfile_riff_WAVE_bext_0['reserved']       =                              substr($thisfile_riff_WAVE_bext_0['data'], 347, 254);
0298           $thisfile_riff_WAVE_bext_0['coding_history'] =         explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
0299           if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
0300             if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
0301               list($dummy, $bext_timestamp['year'], $bext_timestamp['month'],  $bext_timestamp['day'])    = $matches_bext_date;
0302               list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
0303               $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
0304             } else {
0305               $info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid';
0306             }
0307           } else {
0308             $info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid';
0309           }
0310           $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
0311           $thisfile_riff['comments']['title'][]  = $thisfile_riff_WAVE_bext_0['title'];
0312         }
0313 
0314         if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
0315           // shortcut
0316           $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0];
0317 
0318           $thisfile_riff_WAVE_MEXT_0['raw']['sound_information']      = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2));
0319           $thisfile_riff_WAVE_MEXT_0['flags']['homogenous']           = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0001);
0320           if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) {
0321             $thisfile_riff_WAVE_MEXT_0['flags']['padding']          = ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0002) ? false : true;
0322             $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44']         =        (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0004);
0323             $thisfile_riff_WAVE_MEXT_0['flags']['free_format']      =        (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0008);
0324 
0325             $thisfile_riff_WAVE_MEXT_0['nominal_frame_size']        = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
0326           }
0327           $thisfile_riff_WAVE_MEXT_0['anciliary_data_length']         = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2));
0328           $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def']     = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2));
0329           $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left']  = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0001);
0330           $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free']  = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0002);
0331           $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0004);
0332         }
0333 
0334         if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
0335           // shortcut
0336           $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0];
0337 
0338           $thisfile_riff_WAVE_cart_0['version']              =                              substr($thisfile_riff_WAVE_cart_0['data'],   0,  4);
0339           $thisfile_riff_WAVE_cart_0['title']                =                         trim(substr($thisfile_riff_WAVE_cart_0['data'],   4, 64));
0340           $thisfile_riff_WAVE_cart_0['artist']               =                         trim(substr($thisfile_riff_WAVE_cart_0['data'],  68, 64));
0341           $thisfile_riff_WAVE_cart_0['cut_id']               =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64));
0342           $thisfile_riff_WAVE_cart_0['client_id']            =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64));
0343           $thisfile_riff_WAVE_cart_0['category']             =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64));
0344           $thisfile_riff_WAVE_cart_0['classification']       =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64));
0345           $thisfile_riff_WAVE_cart_0['out_cue']              =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64));
0346           $thisfile_riff_WAVE_cart_0['start_date']           =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10));
0347           $thisfile_riff_WAVE_cart_0['start_time']           =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 462,  8));
0348           $thisfile_riff_WAVE_cart_0['end_date']             =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10));
0349           $thisfile_riff_WAVE_cart_0['end_time']             =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 480,  8));
0350           $thisfile_riff_WAVE_cart_0['producer_app_id']      =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64));
0351           $thisfile_riff_WAVE_cart_0['producer_app_version'] =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64));
0352           $thisfile_riff_WAVE_cart_0['user_defined_text']    =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64));
0353           $thisfile_riff_WAVE_cart_0['zero_db_reference']    = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680,  4), true);
0354           for ($i = 0; $i < 8; $i++) {
0355             $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] =                  substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8), 4);
0356             $thisfile_riff_WAVE_cart_0['post_time'][$i]['timer_value']  = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8) + 4, 4));
0357           }
0358           $thisfile_riff_WAVE_cart_0['url']              =                 trim(substr($thisfile_riff_WAVE_cart_0['data'],  748, 1024));
0359           $thisfile_riff_WAVE_cart_0['tag_text']         = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
0360 
0361           $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
0362           $thisfile_riff['comments']['title'][]  = $thisfile_riff_WAVE_cart_0['title'];
0363         }
0364 
0365         if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) {
0366           // SoundMiner metadata
0367 
0368           // shortcuts
0369           $thisfile_riff_WAVE_SNDM_0      = &$thisfile_riff_WAVE['SNDM'][0];
0370           $thisfile_riff_WAVE_SNDM_0_data = &$thisfile_riff_WAVE_SNDM_0['data'];
0371           $SNDM_startoffset = 0;
0372           $SNDM_endoffset   = $thisfile_riff_WAVE_SNDM_0['size'];
0373 
0374           while ($SNDM_startoffset < $SNDM_endoffset) {
0375             $SNDM_thisTagOffset = 0;
0376             $SNDM_thisTagSize      = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4));
0377             $SNDM_thisTagOffset += 4;
0378             $SNDM_thisTagKey       =                           substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4);
0379             $SNDM_thisTagOffset += 4;
0380             $SNDM_thisTagDataSize  = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
0381             $SNDM_thisTagOffset += 2;
0382             $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
0383             $SNDM_thisTagOffset += 2;
0384             $SNDM_thisTagDataText =                            substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize);
0385             $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
0386 
0387             if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) {
0388               $info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
0389               break;
0390             } elseif ($SNDM_thisTagSize <= 0) {
0391               $info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
0392               break;
0393             }
0394             $SNDM_startoffset += $SNDM_thisTagSize;
0395 
0396             $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText;
0397             if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) {
0398               $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
0399             } else {
0400               $info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
0401             }
0402           }
0403 
0404           $tagmapping = array(
0405             'tracktitle'=>'title',
0406             'category'  =>'genre',
0407             'cdtitle'   =>'album',
0408             'tracktitle'=>'title',
0409           );
0410           foreach ($tagmapping as $fromkey => $tokey) {
0411             if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
0412               $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey];
0413             }
0414           }
0415         }
0416 
0417         if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) {
0418           // requires functions simplexml_load_string and get_object_vars
0419           if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) {
0420             $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML;
0421             if (isset($parsedXML['SPEED']['MASTER_SPEED'])) {
0422               @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']);
0423               $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000);
0424             }
0425             if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) {
0426               @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']);
0427               $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000);
0428             }
0429             if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
0430               $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
0431               $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE'];
0432               $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds']       / 3600);
0433               $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600))      / 60);
0434               $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60));
0435               $f =       ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
0436               $thisfile_riff_WAVE['iXML'][0]['timecode_string']       = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s,       $f);
0437               $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d',   $h, $m, $s, round($f));
0438             }
0439             unset($parsedXML);
0440           }
0441         }
0442 
0443 
0444 
0445         if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
0446           $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
0447           $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
0448         }
0449 
0450         if (!empty($info['wavpack'])) {
0451           $thisfile_audio_dataformat = 'wavpack';
0452           $thisfile_audio['bitrate_mode'] = 'vbr';
0453           $thisfile_audio['encoder']      = 'WavPack v'.$info['wavpack']['version'];
0454 
0455           // Reset to the way it was - RIFF parsing will have messed this up
0456           $info['avdataend']        = $Original['avdataend'];
0457           $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
0458 
0459           $this->fseek($info['avdataoffset'] - 44);
0460           $RIFFdata = $this->fread(44);
0461           $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata,  4, 4)) +  8;
0462           $OrignalRIFFdataSize   = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
0463 
0464           if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
0465             $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
0466             $this->fseek($info['avdataend']);
0467             $RIFFdata .= $this->fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
0468           }
0469 
0470           // move the data chunk after all other chunks (if any)
0471           // so that the RIFF parser doesn't see EOF when trying
0472           // to skip over the data chunk
0473           $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
0474           $getid3_riff = new getid3_riff($this->getid3);
0475           $getid3_riff->ParseRIFFdata($RIFFdata);
0476           unset($getid3_riff);
0477         }
0478 
0479         if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
0480           switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
0481             case 0x0001: // PCM
0482               if (!empty($info['ac3'])) {
0483                 // Dolby Digital WAV files masquerade as PCM-WAV, but they're not
0484                 $thisfile_audio['wformattag']  = 0x2000;
0485                 $thisfile_audio['codec']       = self::wFormatTagLookup($thisfile_audio['wformattag']);
0486                 $thisfile_audio['lossless']    = false;
0487                 $thisfile_audio['bitrate']     = $info['ac3']['bitrate'];
0488                 $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate'];
0489               }
0490               if (!empty($info['dts'])) {
0491                 // Dolby DTS files masquerade as PCM-WAV, but they're not
0492                 $thisfile_audio['wformattag']  = 0x2001;
0493                 $thisfile_audio['codec']       = self::wFormatTagLookup($thisfile_audio['wformattag']);
0494                 $thisfile_audio['lossless']    = false;
0495                 $thisfile_audio['bitrate']     = $info['dts']['bitrate'];
0496                 $thisfile_audio['sample_rate'] = $info['dts']['sample_rate'];
0497               }
0498               break;
0499             case 0x08AE: // ClearJump LiteWave
0500               $thisfile_audio['bitrate_mode'] = 'vbr';
0501               $thisfile_audio_dataformat   = 'litewave';
0502 
0503               //typedef struct tagSLwFormat {
0504               //  WORD    m_wCompFormat;     // low byte defines compression method, high byte is compression flags
0505               //  DWORD   m_dwScale;         // scale factor for lossy compression
0506               //  DWORD   m_dwBlockSize;     // number of samples in encoded blocks
0507               //  WORD    m_wQuality;        // alias for the scale factor
0508               //  WORD    m_wMarkDistance;   // distance between marks in bytes
0509               //  WORD    m_wReserved;
0510               //
0511               //  //following paramters are ignored if CF_FILESRC is not set
0512               //  DWORD   m_dwOrgSize;       // original file size in bytes
0513               //  WORD    m_bFactExists;     // indicates if 'fact' chunk exists in the original file
0514               //  DWORD   m_dwRiffChunkSize; // riff chunk size in the original file
0515               //
0516               //  PCMWAVEFORMAT m_OrgWf;     // original wave format
0517               // }SLwFormat, *PSLwFormat;
0518 
0519               // shortcut
0520               $thisfile_riff['litewave']['raw'] = array();
0521               $riff_litewave     = &$thisfile_riff['litewave'];
0522               $riff_litewave_raw = &$riff_litewave['raw'];
0523 
0524               $flags = array(
0525                 'compression_method' => 1,
0526                 'compression_flags'  => 1,
0527                 'm_dwScale'          => 4,
0528                 'm_dwBlockSize'      => 4,
0529                 'm_wQuality'         => 2,
0530                 'm_wMarkDistance'    => 2,
0531                 'm_wReserved'        => 2,
0532                 'm_dwOrgSize'        => 4,
0533                 'm_bFactExists'      => 2,
0534                 'm_dwRiffChunkSize'  => 4,
0535               );
0536               $litewave_offset = 18;
0537               foreach ($flags as $flag => $length) {
0538                 $riff_litewave_raw[$flag] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], $litewave_offset, $length));
0539                 $litewave_offset += $length;
0540               }
0541 
0542               //$riff_litewave['quality_factor'] = intval(round((2000 - $riff_litewave_raw['m_dwScale']) / 20));
0543               $riff_litewave['quality_factor'] = $riff_litewave_raw['m_wQuality'];
0544 
0545               $riff_litewave['flags']['raw_source']    = ($riff_litewave_raw['compression_flags'] & 0x01) ? false : true;
0546               $riff_litewave['flags']['vbr_blocksize'] = ($riff_litewave_raw['compression_flags'] & 0x02) ? false : true;
0547               $riff_litewave['flags']['seekpoints']    =        (bool) ($riff_litewave_raw['compression_flags'] & 0x04);
0548 
0549               $thisfile_audio['lossless']        = (($riff_litewave_raw['m_wQuality'] == 100) ? true : false);
0550               $thisfile_audio['encoder_options'] = '-q'.$riff_litewave['quality_factor'];
0551               break;
0552 
0553             default:
0554               break;
0555           }
0556         }
0557         if ($info['avdataend'] > $info['filesize']) {
0558           switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') {
0559             case 'wavpack': // WavPack
0560             case 'lpac':    // LPAC
0561             case 'ofr':     // OptimFROG
0562             case 'ofs':     // OptimFROG DualStream
0563               // lossless compressed audio formats that keep original RIFF headers - skip warning
0564               break;
0565 
0566             case 'litewave':
0567               if (($info['avdataend'] - $info['filesize']) == 1) {
0568                 // LiteWave appears to incorrectly *not* pad actual output file
0569                 // to nearest WORD boundary so may appear to be short by one
0570                 // byte, in which case - skip warning
0571               } else {
0572                 // Short by more than one byte, throw warning
0573                 $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
0574                 $info['avdataend'] = $info['filesize'];
0575               }
0576               break;
0577 
0578             default:
0579               if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) {
0580                 // output file appears to be incorrectly *not* padded to nearest WORD boundary
0581                 // Output less severe warning
0582                 $info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
0583                 $info['avdataend'] = $info['filesize'];
0584               } else {
0585                 // Short by more than one byte, throw warning
0586                 $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
0587                 $info['avdataend'] = $info['filesize'];
0588               }
0589               break;
0590           }
0591         }
0592         if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
0593           if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
0594             $info['avdataend']--;
0595             $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
0596           }
0597         }
0598         if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) {
0599           unset($thisfile_audio['bits_per_sample']);
0600           if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) {
0601             $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
0602           }
0603         }
0604         break;
0605 
0606       // http://en.wikipedia.org/wiki/Audio_Video_Interleave
0607       case 'AVI ':
0608         $info['fileformat'] = 'avi';
0609         $info['mime_type']  = 'video/avi';
0610 
0611         $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
0612         $thisfile_video['dataformat']   = 'avi';
0613 
0614         if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
0615           $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
0616           if (isset($thisfile_riff['AVIX'])) {
0617             $info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size'];
0618           } else {
0619             $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size'];
0620           }
0621           if ($info['avdataend'] > $info['filesize']) {
0622             $info['warning'][] = 'Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)';
0623             $info['avdataend'] = $info['filesize'];
0624           }
0625         }
0626 
0627         if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) {
0628           //$bIndexType = array(
0629           //  0x00 => 'AVI_INDEX_OF_INDEXES',
0630           //  0x01 => 'AVI_INDEX_OF_CHUNKS',
0631           //  0x80 => 'AVI_INDEX_IS_DATA',
0632           //);
0633           //$bIndexSubtype = array(
0634           //  0x01 => array(
0635           //    0x01 => 'AVI_INDEX_2FIELD',
0636           //  ),
0637           //);
0638           foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) {
0639             $ahsisd = &$thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data'];
0640 
0641             $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($ahsisd,  0, 2));
0642             $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']  = $this->EitherEndian2Int(substr($ahsisd,  2, 1));
0643             $thisfile_riff_raw['indx'][$streamnumber]['bIndexType']     = $this->EitherEndian2Int(substr($ahsisd,  3, 1));
0644             $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse']  = $this->EitherEndian2Int(substr($ahsisd,  4, 4));
0645             $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId']      =                         substr($ahsisd,  8, 4);
0646             $thisfile_riff_raw['indx'][$streamnumber]['dwReserved']     = $this->EitherEndian2Int(substr($ahsisd, 12, 4));
0647 
0648             //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name']    =    $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']];
0649             //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']];
0650 
0651             unset($ahsisd);
0652           }
0653         }
0654         if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
0655           $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
0656 
0657           // shortcut
0658           $thisfile_riff_raw['avih'] = array();
0659           $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih'];
0660 
0661           $thisfile_riff_raw_avih['dwMicroSecPerFrame']    = $this->EitherEndian2Int(substr($avihData,  0, 4)); // frame display rate (or 0L)
0662           if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
0663             $info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
0664             return false;
0665           }
0666 
0667           $flags = array(
0668             'dwMaxBytesPerSec',       // max. transfer rate
0669             'dwPaddingGranularity',   // pad to multiples of this size; normally 2K.
0670             'dwFlags',                // the ever-present flags
0671             'dwTotalFrames',          // # frames in file
0672             'dwInitialFrames',        //
0673             'dwStreams',              //
0674             'dwSuggestedBufferSize',  //
0675             'dwWidth',                //
0676             'dwHeight',               //
0677             'dwScale',                //
0678             'dwRate',                 //
0679             'dwStart',                //
0680             'dwLength',               //
0681           );
0682           $avih_offset = 4;
0683           foreach ($flags as $flag) {
0684             $thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4));
0685             $avih_offset += 4;
0686           }
0687 
0688           $flags = array(
0689             'hasindex'     => 0x00000010,
0690             'mustuseindex' => 0x00000020,
0691             'interleaved'  => 0x00000100,
0692             'trustcktype'  => 0x00000800,
0693             'capturedfile' => 0x00010000,
0694             'copyrighted'  => 0x00020010,
0695           );
0696                     foreach ($flags as $flag => $value) {
0697             $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
0698           }
0699 
0700           // shortcut
0701           $thisfile_riff_video[$streamindex] = array();
0702           $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
0703 
0704           if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
0705             $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
0706             $thisfile_video['resolution_x']             = $thisfile_riff_video_current['frame_width'];
0707           }
0708           if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
0709             $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
0710             $thisfile_video['resolution_y']              = $thisfile_riff_video_current['frame_height'];
0711           }
0712           if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
0713             $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
0714             $thisfile_video['total_frames']              = $thisfile_riff_video_current['total_frames'];
0715           }
0716 
0717           $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
0718           $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate'];
0719         }
0720         if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
0721           if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
0722             for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
0723               if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
0724                 $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
0725                 $strhfccType = substr($strhData,  0, 4);
0726 
0727                 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
0728                   $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
0729 
0730                   // shortcut
0731                   $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
0732 
0733                   switch ($strhfccType) {
0734                     case 'auds':
0735                       $thisfile_audio['bitrate_mode'] = 'cbr';
0736                       $thisfile_audio_dataformat      = 'wav';
0737                       if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) {
0738                         $streamindex = count($thisfile_riff_audio);
0739                       }
0740 
0741                       $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($strfData);
0742                       $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
0743 
0744                       // shortcut
0745                       $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
0746                       $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex];
0747 
0748                       if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
0749                         unset($thisfile_audio_streams_currentstream['bits_per_sample']);
0750                       }
0751                       $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
0752                       unset($thisfile_audio_streams_currentstream['raw']);
0753 
0754                       // shortcut
0755                       $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
0756 
0757                       unset($thisfile_riff_audio[$streamindex]['raw']);
0758                       $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
0759 
0760                       $thisfile_audio['lossless'] = false;
0761                       switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
0762                         case 0x0001:  // PCM
0763                           $thisfile_audio_dataformat  = 'wav';
0764                           $thisfile_audio['lossless'] = true;
0765                           break;
0766 
0767                         case 0x0050: // MPEG Layer 2 or Layer 1
0768                           $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2
0769                           break;
0770 
0771                         case 0x0055: // MPEG Layer 3
0772                           $thisfile_audio_dataformat = 'mp3';
0773                           break;
0774 
0775                         case 0x00FF: // AAC
0776                           $thisfile_audio_dataformat = 'aac';
0777                           break;
0778 
0779                         case 0x0161: // Windows Media v7 / v8 / v9
0780                         case 0x0162: // Windows Media Professional v9
0781                         case 0x0163: // Windows Media Lossess v9
0782                           $thisfile_audio_dataformat = 'wma';
0783                           break;
0784 
0785                         case 0x2000: // AC-3
0786                           $thisfile_audio_dataformat = 'ac3';
0787                           break;
0788 
0789                         case 0x2001: // DTS
0790                           $thisfile_audio_dataformat = 'dts';
0791                           break;
0792 
0793                         default:
0794                           $thisfile_audio_dataformat = 'wav';
0795                           break;
0796                       }
0797                       $thisfile_audio_streams_currentstream['dataformat']   = $thisfile_audio_dataformat;
0798                       $thisfile_audio_streams_currentstream['lossless']     = $thisfile_audio['lossless'];
0799                       $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
0800                       break;
0801 
0802 
0803                     case 'iavs':
0804                     case 'vids':
0805                       // shortcut
0806                       $thisfile_riff_raw['strh'][$i]                  = array();
0807                       $thisfile_riff_raw_strh_current                 = &$thisfile_riff_raw['strh'][$i];
0808 
0809                       $thisfile_riff_raw_strh_current['fccType']               =                         substr($strhData,  0, 4);  // same as $strhfccType;
0810                       $thisfile_riff_raw_strh_current['fccHandler']            =                         substr($strhData,  4, 4);
0811                       $thisfile_riff_raw_strh_current['dwFlags']               = $this->EitherEndian2Int(substr($strhData,  8, 4)); // Contains AVITF_* flags
0812                       $thisfile_riff_raw_strh_current['wPriority']             = $this->EitherEndian2Int(substr($strhData, 12, 2));
0813                       $thisfile_riff_raw_strh_current['wLanguage']             = $this->EitherEndian2Int(substr($strhData, 14, 2));
0814                       $thisfile_riff_raw_strh_current['dwInitialFrames']       = $this->EitherEndian2Int(substr($strhData, 16, 4));
0815                       $thisfile_riff_raw_strh_current['dwScale']               = $this->EitherEndian2Int(substr($strhData, 20, 4));
0816                       $thisfile_riff_raw_strh_current['dwRate']                = $this->EitherEndian2Int(substr($strhData, 24, 4));
0817                       $thisfile_riff_raw_strh_current['dwStart']               = $this->EitherEndian2Int(substr($strhData, 28, 4));
0818                       $thisfile_riff_raw_strh_current['dwLength']              = $this->EitherEndian2Int(substr($strhData, 32, 4));
0819                       $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4));
0820                       $thisfile_riff_raw_strh_current['dwQuality']             = $this->EitherEndian2Int(substr($strhData, 40, 4));
0821                       $thisfile_riff_raw_strh_current['dwSampleSize']          = $this->EitherEndian2Int(substr($strhData, 44, 4));
0822                       $thisfile_riff_raw_strh_current['rcFrame']               = $this->EitherEndian2Int(substr($strhData, 48, 4));
0823 
0824                       $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strh_current['fccHandler']);
0825                       $thisfile_video['fourcc']             = $thisfile_riff_raw_strh_current['fccHandler'];
0826                       if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
0827                         $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
0828                         $thisfile_video['fourcc']             = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
0829                       }
0830                       $thisfile_video['codec']              = $thisfile_riff_video_current['codec'];
0831                       $thisfile_video['pixel_aspect_ratio'] = (float) 1;
0832                       switch ($thisfile_riff_raw_strh_current['fccHandler']) {
0833                         case 'HFYU': // Huffman Lossless Codec
0834                         case 'IRAW': // Intel YUV Uncompressed
0835                         case 'YUY2': // Uncompressed YUV 4:2:2
0836                           $thisfile_video['lossless'] = true;
0837                           break;
0838 
0839                         default:
0840                           $thisfile_video['lossless'] = false;
0841                           break;
0842                       }
0843 
0844                       switch ($strhfccType) {
0845                         case 'vids':
0846                           $thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($this->container == 'riff'));
0847                           $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
0848 
0849                           if ($thisfile_riff_video_current['codec'] == 'DV') {
0850                             $thisfile_riff_video_current['dv_type'] = 2;
0851                           }
0852                           break;
0853 
0854                         case 'iavs':
0855                           $thisfile_riff_video_current['dv_type'] = 1;
0856                           break;
0857                       }
0858                       break;
0859 
0860                     default:
0861                       $info['warning'][] = 'Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"';
0862                       break;
0863 
0864                   }
0865                 }
0866               }
0867 
0868               if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
0869 
0870                 $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
0871                 if (self::fourccLookup($thisfile_video['fourcc'])) {
0872                   $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_video['fourcc']);
0873                   $thisfile_video['codec']              = $thisfile_riff_video_current['codec'];
0874                 }
0875 
0876                 switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) {
0877                   case 'HFYU': // Huffman Lossless Codec
0878                   case 'IRAW': // Intel YUV Uncompressed
0879                   case 'YUY2': // Uncompressed YUV 4:2:2
0880                     $thisfile_video['lossless']        = true;
0881                     //$thisfile_video['bits_per_sample'] = 24;
0882                     break;
0883 
0884                   default:
0885                     $thisfile_video['lossless']        = false;
0886                     //$thisfile_video['bits_per_sample'] = 24;
0887                     break;
0888                 }
0889 
0890               }
0891             }
0892           }
0893         }
0894         break;
0895 
0896 
0897       case 'AMV ':
0898         $info['fileformat'] = 'amv';
0899         $info['mime_type']  = 'video/amv';
0900 
0901         $thisfile_video['bitrate_mode']    = 'vbr'; // it's MJPEG, presumably contant-quality encoding, thereby VBR
0902         $thisfile_video['dataformat']      = 'mjpeg';
0903         $thisfile_video['codec']           = 'mjpeg';
0904         $thisfile_video['lossless']        = false;
0905         $thisfile_video['bits_per_sample'] = 24;
0906 
0907         $thisfile_audio['dataformat']   = 'adpcm';
0908         $thisfile_audio['lossless']     = false;
0909         break;
0910 
0911 
0912       // http://en.wikipedia.org/wiki/CD-DA
0913       case 'CDDA':
0914         $info['fileformat'] = 'cda';
0915           unset($info['mime_type']);
0916 
0917         $thisfile_audio_dataformat      = 'cda';
0918 
0919         $info['avdataoffset'] = 44;
0920 
0921         if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
0922           // shortcut
0923           $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0];
0924 
0925           $thisfile_riff_CDDA_fmt_0['unknown1']           = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'],  0, 2));
0926           $thisfile_riff_CDDA_fmt_0['track_num']          = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'],  2, 2));
0927           $thisfile_riff_CDDA_fmt_0['disc_id']            = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'],  4, 4));
0928           $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'],  8, 4));
0929           $thisfile_riff_CDDA_fmt_0['playtime_frames']    = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4));
0930           $thisfile_riff_CDDA_fmt_0['unknown6']           = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4));
0931           $thisfile_riff_CDDA_fmt_0['unknown7']           = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4));
0932 
0933           $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
0934           $thisfile_riff_CDDA_fmt_0['playtime_seconds']     = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
0935           $info['comments']['track']                = $thisfile_riff_CDDA_fmt_0['track_num'];
0936           $info['playtime_seconds']                 = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
0937 
0938           // hardcoded data for CD-audio
0939           $thisfile_audio['lossless']        = true;
0940           $thisfile_audio['sample_rate']     = 44100;
0941           $thisfile_audio['channels']        = 2;
0942           $thisfile_audio['bits_per_sample'] = 16;
0943           $thisfile_audio['bitrate']         = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
0944           $thisfile_audio['bitrate_mode']    = 'cbr';
0945         }
0946         break;
0947 
0948             // http://en.wikipedia.org/wiki/AIFF
0949       case 'AIFF':
0950       case 'AIFC':
0951         $info['fileformat'] = 'aiff';
0952         $info['mime_type']  = 'audio/x-aiff';
0953 
0954         $thisfile_audio['bitrate_mode'] = 'cbr';
0955         $thisfile_audio_dataformat      = 'aiff';
0956         $thisfile_audio['lossless']     = true;
0957 
0958         if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
0959           $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
0960           $info['avdataend']    = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
0961           if ($info['avdataend'] > $info['filesize']) {
0962             if (($info['avdataend'] == ($info['filesize'] + 1)) && (($info['filesize'] % 2) == 1)) {
0963               // structures rounded to 2-byte boundary, but dumb encoders
0964               // forget to pad end of file to make this actually work
0965             } else {
0966               $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';
0967             }
0968             $info['avdataend'] = $info['filesize'];
0969           }
0970         }
0971 
0972         if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
0973 
0974           // shortcut
0975           $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
0976 
0977           $thisfile_riff_audio['channels']         =         getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data,  0,  2), true);
0978           $thisfile_riff_audio['total_samples']    =         getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data,  2,  4), false);
0979           $thisfile_riff_audio['bits_per_sample']  =         getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data,  6,  2), true);
0980           $thisfile_riff_audio['sample_rate']      = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data,  8, 10));
0981 
0982           if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) {
0983             $thisfile_riff_audio['codec_fourcc'] =                                   substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18,  4);
0984             $CodecNameSize                       =         getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22,  1), false);
0985             $thisfile_riff_audio['codec_name']   =                                   substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23,  $CodecNameSize);
0986             switch ($thisfile_riff_audio['codec_name']) {
0987               case 'NONE':
0988                 $thisfile_audio['codec']    = 'Pulse Code Modulation (PCM)';
0989                 $thisfile_audio['lossless'] = true;
0990                 break;
0991 
0992               case '':
0993                 switch ($thisfile_riff_audio['codec_fourcc']) {
0994                   // http://developer.apple.com/qa/snd/snd07.html
0995                   case 'sowt':
0996                     $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
0997                     $thisfile_audio['lossless'] = true;
0998                     break;
0999 
1000                   case 'twos':
1001                     $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
1002                     $thisfile_audio['lossless'] = true;
1003                     break;
1004 
1005                   default:
1006                     break;
1007                 }
1008                 break;
1009 
1010               default:
1011                 $thisfile_audio['codec']    = $thisfile_riff_audio['codec_name'];
1012                 $thisfile_audio['lossless'] = false;
1013                 break;
1014             }
1015           }
1016 
1017           $thisfile_audio['channels']        = $thisfile_riff_audio['channels'];
1018           if ($thisfile_riff_audio['bits_per_sample'] > 0) {
1019             $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample'];
1020           }
1021           $thisfile_audio['sample_rate']     = $thisfile_riff_audio['sample_rate'];
1022           if ($thisfile_audio['sample_rate'] == 0) {
1023             $info['error'][] = 'Corrupted AIFF file: sample_rate == zero';
1024             return false;
1025           }
1026           $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
1027         }
1028 
1029         if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
1030           $offset = 0;
1031           $CommentCount                                   = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
1032           $offset += 2;
1033           for ($i = 0; $i < $CommentCount; $i++) {
1034             $info['comments_raw'][$i]['timestamp']      = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false);
1035             $offset += 4;
1036             $info['comments_raw'][$i]['marker_id']      = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
1037             $offset += 2;
1038             $CommentLength                              = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
1039             $offset += 2;
1040             $info['comments_raw'][$i]['comment']        =                           substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
1041             $offset += $CommentLength;
1042 
1043             $info['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($info['comments_raw'][$i]['timestamp']);
1044             $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment'];
1045           }
1046         }
1047 
1048         $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
1049         foreach ($CommentsChunkNames as $key => $value) {
1050           if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
1051             $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
1052           }
1053         }
1054 /*
1055         if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
1056           getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
1057           $getid3_temp = new getID3();
1058           $getid3_temp->openfile($this->getid3->filename);
1059           $getid3_id3v2 = new getid3_id3v2($getid3_temp);
1060           $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
1061           if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
1062             $info['id3v2'] = $getid3_temp->info['id3v2'];
1063           }
1064           unset($getid3_temp, $getid3_id3v2);
1065         }
1066 */
1067         break;
1068 
1069       // http://en.wikipedia.org/wiki/8SVX
1070       case '8SVX':
1071         $info['fileformat'] = '8svx';
1072         $info['mime_type']  = 'audio/8svx';
1073 
1074         $thisfile_audio['bitrate_mode']    = 'cbr';
1075         $thisfile_audio_dataformat         = '8svx';
1076         $thisfile_audio['bits_per_sample'] = 8;
1077         $thisfile_audio['channels']        = 1; // overridden below, if need be
1078 
1079         if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
1080           $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
1081           $info['avdataend']    = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
1082           if ($info['avdataend'] > $info['filesize']) {
1083             $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';
1084           }
1085         }
1086 
1087         if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
1088           // shortcut
1089           $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0];
1090 
1091           $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples']  =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'],  0, 4));
1092           $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples']   =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'],  4, 4));
1093           $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'],  8, 4));
1094           $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec']     =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2));
1095           $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave']          =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1));
1096           $thisfile_riff_RIFFsubtype_VHDR_0['sCompression']      =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1));
1097           $thisfile_riff_RIFFsubtype_VHDR_0['Volume']            = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4));
1098 
1099           $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
1100 
1101           switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
1102             case 0:
1103               $thisfile_audio['codec']    = 'Pulse Code Modulation (PCM)';
1104               $thisfile_audio['lossless'] = true;
1105               $ActualBitsPerSample        = 8;
1106               break;
1107 
1108             case 1:
1109               $thisfile_audio['codec']    = 'Fibonacci-delta encoding';
1110               $thisfile_audio['lossless'] = false;
1111               $ActualBitsPerSample        = 4;
1112               break;
1113 
1114             default:
1115               $info['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"';
1116               break;
1117           }
1118         }
1119 
1120         if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) {
1121           $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4));
1122           switch ($ChannelsIndex) {
1123             case 6: // Stereo
1124               $thisfile_audio['channels'] = 2;
1125               break;
1126 
1127             case 2: // Left channel only
1128             case 4: // Right channel only
1129               $thisfile_audio['channels'] = 1;
1130               break;
1131 
1132             default:
1133               $info['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"';
1134               break;
1135           }
1136 
1137         }
1138 
1139         $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
1140         foreach ($CommentsChunkNames as $key => $value) {
1141           if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
1142             $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
1143           }
1144         }
1145 
1146         $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels'];
1147         if (!empty($thisfile_audio['bitrate'])) {
1148           $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8);
1149         }
1150         break;
1151 
1152       case 'CDXA':
1153         $info['fileformat'] = 'vcd'; // Asume Video CD
1154         $info['mime_type']  = 'video/mpeg';
1155 
1156         if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
1157           getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
1158 
1159           $getid3_temp = new getID3();
1160           $getid3_temp->openfile($this->getid3->filename);
1161           $getid3_mpeg = new getid3_mpeg($getid3_temp);
1162           $getid3_mpeg->Analyze();
1163           if (empty($getid3_temp->info['error'])) {
1164             $info['audio']   = $getid3_temp->info['audio'];
1165             $info['video']   = $getid3_temp->info['video'];
1166             $info['mpeg']    = $getid3_temp->info['mpeg'];
1167             $info['warning'] = $getid3_temp->info['warning'];
1168           }
1169           unset($getid3_temp, $getid3_mpeg);
1170         }
1171         break;
1172 
1173 
1174       default:
1175         $info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead';
1176         //unset($info['fileformat']);
1177     }
1178 
1179     switch ($RIFFsubtype) {
1180       case 'WAVE':
1181       case 'AIFF':
1182       case 'AIFC':
1183         $ID3v2_key_good = 'id3 ';
1184         $ID3v2_keys_bad = array('ID3 ', 'tag ');
1185         foreach ($ID3v2_keys_bad as $ID3v2_key_bad) {
1186           if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) {
1187             $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad];
1188             $info['warning'][] = 'mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"';
1189           }
1190         }
1191 
1192         if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) {
1193           getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
1194 
1195           $getid3_temp = new getID3();
1196           $getid3_temp->openfile($this->getid3->filename);
1197           $getid3_id3v2 = new getid3_id3v2($getid3_temp);
1198           $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
1199           if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
1200             $info['id3v2'] = $getid3_temp->info['id3v2'];
1201           }
1202           unset($getid3_temp, $getid3_id3v2);
1203         }
1204         break;
1205     }
1206 
1207     if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) {
1208       $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4));
1209     }
1210     if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
1211       self::parseComments($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
1212     }
1213     if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) {
1214       self::parseComments($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']);
1215     }
1216 
1217     if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) {
1218       $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version'];
1219     }
1220 
1221     if (!isset($info['playtime_seconds'])) {
1222       $info['playtime_seconds'] = 0;
1223     }
1224     if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
1225       // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
1226       $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
1227     } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
1228       $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
1229     }
1230 
1231     if ($info['playtime_seconds'] > 0) {
1232       if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
1233 
1234         if (!isset($info['bitrate'])) {
1235           $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1236         }
1237 
1238       } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
1239 
1240         if (!isset($thisfile_audio['bitrate'])) {
1241           $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1242         }
1243 
1244       } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
1245 
1246         if (!isset($thisfile_video['bitrate'])) {
1247           $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1248         }
1249 
1250       }
1251     }
1252 
1253 
1254     if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) {
1255 
1256       $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1257       $thisfile_audio['bitrate'] = 0;
1258       $thisfile_video['bitrate'] = $info['bitrate'];
1259       foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) {
1260         $thisfile_video['bitrate'] -= $audioinfoarray['bitrate'];
1261         $thisfile_audio['bitrate'] += $audioinfoarray['bitrate'];
1262       }
1263       if ($thisfile_video['bitrate'] <= 0) {
1264         unset($thisfile_video['bitrate']);
1265       }
1266       if ($thisfile_audio['bitrate'] <= 0) {
1267         unset($thisfile_audio['bitrate']);
1268       }
1269     }
1270 
1271     if (isset($info['mpeg']['audio'])) {
1272       $thisfile_audio_dataformat      = 'mp'.$info['mpeg']['audio']['layer'];
1273       $thisfile_audio['sample_rate']  = $info['mpeg']['audio']['sample_rate'];
1274       $thisfile_audio['channels']     = $info['mpeg']['audio']['channels'];
1275       $thisfile_audio['bitrate']      = $info['mpeg']['audio']['bitrate'];
1276       $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1277       if (!empty($info['mpeg']['audio']['codec'])) {
1278         $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'].' '.$thisfile_audio['codec'];
1279       }
1280       if (!empty($thisfile_audio['streams'])) {
1281         foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) {
1282           if ($streamdata['dataformat'] == $thisfile_audio_dataformat) {
1283             $thisfile_audio['streams'][$streamnumber]['sample_rate']  = $thisfile_audio['sample_rate'];
1284             $thisfile_audio['streams'][$streamnumber]['channels']     = $thisfile_audio['channels'];
1285             $thisfile_audio['streams'][$streamnumber]['bitrate']      = $thisfile_audio['bitrate'];
1286             $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
1287             $thisfile_audio['streams'][$streamnumber]['codec']        = $thisfile_audio['codec'];
1288           }
1289         }
1290       }
1291       $getid3_mp3 = new getid3_mp3($this->getid3);
1292       $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions();
1293       unset($getid3_mp3);
1294     }
1295 
1296 
1297     if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) {
1298       switch ($thisfile_audio_dataformat) {
1299         case 'ac3':
1300           // ignore bits_per_sample
1301           break;
1302 
1303         default:
1304           $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
1305           break;
1306       }
1307     }
1308 
1309 
1310     if (empty($thisfile_riff_raw)) {
1311       unset($thisfile_riff['raw']);
1312     }
1313     if (empty($thisfile_riff_audio)) {
1314       unset($thisfile_riff['audio']);
1315     }
1316     if (empty($thisfile_riff_video)) {
1317       unset($thisfile_riff['video']);
1318     }
1319 
1320     return true;
1321   }
1322 
1323   public function ParseRIFFAMV($startoffset, $maxoffset) {
1324     // AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
1325 
1326     // https://code.google.com/p/amv-codec-tools/wiki/AmvDocumentation
1327     //typedef struct _amvmainheader {
1328     //FOURCC fcc; // 'amvh'
1329     //DWORD cb;
1330     //DWORD dwMicroSecPerFrame;
1331     //BYTE reserve[28];
1332     //DWORD dwWidth;
1333     //DWORD dwHeight;
1334     //DWORD dwSpeed;
1335     //DWORD reserve0;
1336     //DWORD reserve1;
1337     //BYTE bTimeSec;
1338     //BYTE bTimeMin;
1339     //WORD wTimeHour;
1340     //} AMVMAINHEADER;
1341 
1342     $info = &$this->getid3->info;
1343     $RIFFchunk = false;
1344 
1345     try {
1346 
1347       $this->fseek($startoffset);
1348       $maxoffset = min($maxoffset, $info['avdataend']);
1349       $AMVheader = $this->fread(284);
1350       if (substr($AMVheader,   0,  8) != 'hdrlamvh') {
1351         throw new Exception('expecting "hdrlamv" at offset '.($startoffset +   0).', found "'.substr($AMVheader,   0, 8).'"');
1352       }
1353       if (substr($AMVheader,   8,  4) != "\x38\x00\x00\x00") { // "amvh" chunk size, hardcoded to 0x38 = 56 bytes
1354         throw new Exception('expecting "0x38000000" at offset '.($startoffset +   8).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader,   8, 4)).'"');
1355       }
1356       $RIFFchunk = array();
1357       $RIFFchunk['amvh']['us_per_frame']   = getid3_lib::LittleEndian2Int(substr($AMVheader,  12,  4));
1358       $RIFFchunk['amvh']['reserved28']     =                              substr($AMVheader,  16, 28);  // null? reserved?
1359       $RIFFchunk['amvh']['resolution_x']   = getid3_lib::LittleEndian2Int(substr($AMVheader,  44,  4));
1360       $RIFFchunk['amvh']['resolution_y']   = getid3_lib::LittleEndian2Int(substr($AMVheader,  48,  4));
1361       $RIFFchunk['amvh']['frame_rate_int'] = getid3_lib::LittleEndian2Int(substr($AMVheader,  52,  4));
1362       $RIFFchunk['amvh']['reserved0']      = getid3_lib::LittleEndian2Int(substr($AMVheader,  56,  4)); // 1? reserved?
1363       $RIFFchunk['amvh']['reserved1']      = getid3_lib::LittleEndian2Int(substr($AMVheader,  60,  4)); // 0? reserved?
1364       $RIFFchunk['amvh']['runtime_sec']    = getid3_lib::LittleEndian2Int(substr($AMVheader,  64,  1));
1365       $RIFFchunk['amvh']['runtime_min']    = getid3_lib::LittleEndian2Int(substr($AMVheader,  65,  1));
1366       $RIFFchunk['amvh']['runtime_hrs']    = getid3_lib::LittleEndian2Int(substr($AMVheader,  66,  2));
1367 
1368       $info['video']['frame_rate']   = 1000000 / $RIFFchunk['amvh']['us_per_frame'];
1369       $info['video']['resolution_x'] = $RIFFchunk['amvh']['resolution_x'];
1370       $info['video']['resolution_y'] = $RIFFchunk['amvh']['resolution_y'];
1371       $info['playtime_seconds']      = ($RIFFchunk['amvh']['runtime_hrs'] * 3600) + ($RIFFchunk['amvh']['runtime_min'] * 60) + $RIFFchunk['amvh']['runtime_sec'];
1372 
1373       // the rest is all hardcoded(?) and does not appear to be useful until you get to audio info at offset 256, even then everything is probably hardcoded
1374 
1375       if (substr($AMVheader,  68, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x38\x00\x00\x00") {
1376         throw new Exception('expecting "LIST<0x00000000>strlstrh<0x38000000>" at offset '.($startoffset +  68).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader,  68, 20)).'"');
1377       }
1378       // followed by 56 bytes of null: substr($AMVheader,  88, 56) -> 144
1379       if (substr($AMVheader, 144,  8) != 'strf'."\x24\x00\x00\x00") {
1380         throw new Exception('expecting "strf<0x24000000>" at offset '.($startoffset + 144).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 144,  8)).'"');
1381       }
1382       // followed by 36 bytes of null: substr($AMVheader, 144, 36) -> 180
1383 
1384       if (substr($AMVheader, 188, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x30\x00\x00\x00") {
1385         throw new Exception('expecting "LIST<0x00000000>strlstrh<0x30000000>" at offset '.($startoffset + 188).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 188, 20)).'"');
1386       }
1387       // followed by 48 bytes of null: substr($AMVheader, 208, 48) -> 256
1388       if (substr($AMVheader, 256,  8) != 'strf'."\x14\x00\x00\x00") {
1389         throw new Exception('expecting "strf<0x14000000>" at offset '.($startoffset + 256).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 256,  8)).'"');
1390       }
1391       // followed by 20 bytes of a modified WAVEFORMATEX:
1392       // typedef struct {
1393       // WORD wFormatTag;       //(Fixme: this is equal to PCM's 0x01 format code)
1394       // WORD nChannels;        //(Fixme: this is always 1)
1395       // DWORD nSamplesPerSec;  //(Fixme: for all known sample files this is equal to 22050)
1396       // DWORD nAvgBytesPerSec; //(Fixme: for all known sample files this is equal to 44100)
1397       // WORD nBlockAlign;      //(Fixme: this seems to be 2 in AMV files, is this correct ?)
1398       // WORD wBitsPerSample;   //(Fixme: this seems to be 16 in AMV files instead of the expected 4)
1399       // WORD cbSize;           //(Fixme: this seems to be 0 in AMV files)
1400       // WORD reserved;
1401       // } WAVEFORMATEX;
1402       $RIFFchunk['strf']['wformattag']      = getid3_lib::LittleEndian2Int(substr($AMVheader,  264,  2));
1403       $RIFFchunk['strf']['nchannels']       = getid3_lib::LittleEndian2Int(substr($AMVheader,  266,  2));
1404       $RIFFchunk['strf']['nsamplespersec']  = getid3_lib::LittleEndian2Int(substr($AMVheader,  268,  4));
1405       $RIFFchunk['strf']['navgbytespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader,  272,  4));
1406       $RIFFchunk['strf']['nblockalign']     = getid3_lib::LittleEndian2Int(substr($AMVheader,  276,  2));
1407       $RIFFchunk['strf']['wbitspersample']  = getid3_lib::LittleEndian2Int(substr($AMVheader,  278,  2));
1408       $RIFFchunk['strf']['cbsize']          = getid3_lib::LittleEndian2Int(substr($AMVheader,  280,  2));
1409       $RIFFchunk['strf']['reserved']        = getid3_lib::LittleEndian2Int(substr($AMVheader,  282,  2));
1410 
1411 
1412       $info['audio']['lossless']        = false;
1413       $info['audio']['sample_rate']     = $RIFFchunk['strf']['nsamplespersec'];
1414       $info['audio']['channels']        = $RIFFchunk['strf']['nchannels'];
1415       $info['audio']['bits_per_sample'] = $RIFFchunk['strf']['wbitspersample'];
1416       $info['audio']['bitrate']         = $info['audio']['sample_rate'] * $info['audio']['channels'] * $info['audio']['bits_per_sample'];
1417       $info['audio']['bitrate_mode']    = 'cbr';
1418 
1419 
1420     } catch (getid3_exception $e) {
1421       if ($e->getCode() == 10) {
1422         $this->warning('RIFFAMV parser: '.$e->getMessage());
1423       } else {
1424         throw $e;
1425       }
1426     }
1427 
1428     return $RIFFchunk;
1429   }
1430 
1431 
1432   public function ParseRIFF($startoffset, $maxoffset) {
1433     $info = &$this->getid3->info;
1434 
1435     $RIFFchunk = false;
1436     $FoundAllChunksWeNeed = false;
1437 
1438     try {
1439       $this->fseek($startoffset);
1440       $maxoffset = min($maxoffset, $info['avdataend']);
1441       while ($this->ftell() < $maxoffset) {
1442         $chunknamesize = $this->fread(8);
1443         //$chunkname =                          substr($chunknamesize, 0, 4);
1444         $chunkname = str_replace("\x00", '_', substr($chunknamesize, 0, 4));  // note: chunk names of 4 null bytes do appear to be legal (has been observed inside INFO and PRMI chunks, for example), but makes traversing array keys more difficult
1445         $chunksize =  $this->EitherEndian2Int(substr($chunknamesize, 4, 4));
1446         //if (strlen(trim($chunkname, "\x00")) < 4) {
1447         if (strlen($chunkname) < 4) {
1448           $this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.');
1449           break;
1450         }
1451         if (($chunksize == 0) && ($chunkname != 'JUNK')) {
1452           $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.');
1453           break;
1454         }
1455         if (($chunksize % 2) != 0) {
1456           // all structures are packed on word boundaries
1457           $chunksize++;
1458         }
1459 
1460         switch ($chunkname) {
1461           case 'LIST':
1462             $listname = $this->fread(4);
1463             if (preg_match('#^(movi|rec )$#i', $listname)) {
1464               $RIFFchunk[$listname]['offset'] = $this->ftell() - 4;
1465               $RIFFchunk[$listname]['size']   = $chunksize;
1466 
1467               if (!$FoundAllChunksWeNeed) {
1468                 $WhereWeWere      = $this->ftell();
1469                 $AudioChunkHeader = $this->fread(12);
1470                 $AudioChunkStreamNum  =                              substr($AudioChunkHeader, 0, 2);
1471                 $AudioChunkStreamType =                              substr($AudioChunkHeader, 2, 2);
1472                 $AudioChunkSize       = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4));
1473 
1474                 if ($AudioChunkStreamType == 'wb') {
1475                   $FirstFourBytes = substr($AudioChunkHeader, 8, 4);
1476                   if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) {
1477                     // MP3
1478                     if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
1479                       $getid3_temp = new getID3();
1480                       $getid3_temp->openfile($this->getid3->filename);
1481                       $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
1482                       $getid3_temp->info['avdataend']    = $this->ftell() + $AudioChunkSize;
1483                       $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
1484                       $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
1485                       if (isset($getid3_temp->info['mpeg']['audio'])) {
1486                         $info['mpeg']['audio']         = $getid3_temp->info['mpeg']['audio'];
1487                         $info['audio']                 = $getid3_temp->info['audio'];
1488                         $info['audio']['dataformat']   = 'mp'.$info['mpeg']['audio']['layer'];
1489                         $info['audio']['sample_rate']  = $info['mpeg']['audio']['sample_rate'];
1490                         $info['audio']['channels']     = $info['mpeg']['audio']['channels'];
1491                         $info['audio']['bitrate']      = $info['mpeg']['audio']['bitrate'];
1492                         $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1493                         //$info['bitrate']               = $info['audio']['bitrate'];
1494                       }
1495                       unset($getid3_temp, $getid3_mp3);
1496                     }
1497 
1498                   } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) {
1499 
1500                     // AC3
1501                     $getid3_temp = new getID3();
1502                     $getid3_temp->openfile($this->getid3->filename);
1503                     $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
1504                     $getid3_temp->info['avdataend']    = $this->ftell() + $AudioChunkSize;
1505                     $getid3_ac3 = new getid3_ac3($getid3_temp);
1506                     $getid3_ac3->Analyze();
1507                     if (empty($getid3_temp->info['error'])) {
1508                       $info['audio']   = $getid3_temp->info['audio'];
1509                       $info['ac3']     = $getid3_temp->info['ac3'];
1510                       if (!empty($getid3_temp->info['warning'])) {
1511                         foreach ($getid3_temp->info['warning'] as $key => $value) {
1512                           $info['warning'][] = $value;
1513                         }
1514                       }
1515                     }
1516                     unset($getid3_temp, $getid3_ac3);
1517                   }
1518                 }
1519                 $FoundAllChunksWeNeed = true;
1520                 $this->fseek($WhereWeWere);
1521               }
1522               $this->fseek($chunksize - 4, SEEK_CUR);
1523 
1524             } else {
1525 
1526               if (!isset($RIFFchunk[$listname])) {
1527                 $RIFFchunk[$listname] = array();
1528               }
1529               $LISTchunkParent    = $listname;
1530               $LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize;
1531               if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) {
1532                 $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk);
1533               }
1534 
1535             }
1536             break;
1537 
1538           default:
1539             if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) {
1540               $this->fseek($chunksize, SEEK_CUR);
1541               break;
1542             }
1543             $thisindex = 0;
1544             if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) {
1545               $thisindex = count($RIFFchunk[$chunkname]);
1546             }
1547             $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8;
1548             $RIFFchunk[$chunkname][$thisindex]['size']   = $chunksize;
1549             switch ($chunkname) {
1550               case 'data':
1551                 $info['avdataoffset'] = $this->ftell();
1552                 $info['avdataend']    = $info['avdataoffset'] + $chunksize;
1553 
1554                 $testData = $this->fread(36);
1555                 if ($testData === '') {
1556                   break;
1557                 }
1558                 if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) {
1559 
1560                   // Probably is MP3 data
1561                   if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
1562                     $getid3_temp = new getID3();
1563                     $getid3_temp->openfile($this->getid3->filename);
1564                     $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1565                     $getid3_temp->info['avdataend']    = $info['avdataend'];
1566                     $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
1567                     $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
1568                     if (empty($getid3_temp->info['error'])) {
1569                       $info['audio'] = $getid3_temp->info['audio'];
1570                       $info['mpeg']  = $getid3_temp->info['mpeg'];
1571                     }
1572                     unset($getid3_temp, $getid3_mp3);
1573                   }
1574 
1575                 } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) {
1576 
1577                   // This is probably AC-3 data
1578                   $getid3_temp = new getID3();
1579                   if ($isRegularAC3) {
1580                     $getid3_temp->openfile($this->getid3->filename);
1581                     $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1582                     $getid3_temp->info['avdataend']    = $info['avdataend'];
1583                   }
1584                   $getid3_ac3 = new getid3_ac3($getid3_temp);
1585                   if ($isRegularAC3) {
1586                     $getid3_ac3->Analyze();
1587                   } else {
1588                     // Dolby Digital WAV
1589                     // AC-3 content, but not encoded in same format as normal AC-3 file
1590                     // For one thing, byte order is swapped
1591                     $ac3_data = '';
1592                     for ($i = 0; $i < 28; $i += 2) {
1593                       $ac3_data .= substr($testData, 8 + $i + 1, 1);
1594                       $ac3_data .= substr($testData, 8 + $i + 0, 1);
1595                     }
1596                     $getid3_ac3->AnalyzeString($ac3_data);
1597                   }
1598 
1599                   if (empty($getid3_temp->info['error'])) {
1600                     $info['audio'] = $getid3_temp->info['audio'];
1601                     $info['ac3']   = $getid3_temp->info['ac3'];
1602                     if (!empty($getid3_temp->info['warning'])) {
1603                       foreach ($getid3_temp->info['warning'] as $newerror) {
1604                         $this->warning('getid3_ac3() says: ['.$newerror.']');
1605                       }
1606                     }
1607                   }
1608                   unset($getid3_temp, $getid3_ac3);
1609 
1610                 } elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts::$syncwords)).')/', $testData)) {
1611 
1612                   // This is probably DTS data
1613                   $getid3_temp = new getID3();
1614                   $getid3_temp->openfile($this->getid3->filename);
1615                   $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1616                   $getid3_dts = new getid3_dts($getid3_temp);
1617                   $getid3_dts->Analyze();
1618                   if (empty($getid3_temp->info['error'])) {
1619                     $info['audio']            = $getid3_temp->info['audio'];
1620                     $info['dts']              = $getid3_temp->info['dts'];
1621                     $info['playtime_seconds'] = $getid3_temp->info['playtime_seconds']; // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing
1622                     if (!empty($getid3_temp->info['warning'])) {
1623                       foreach ($getid3_temp->info['warning'] as $newerror) {
1624                         $this->warning('getid3_dts() says: ['.$newerror.']');
1625                       }
1626                     }
1627                   }
1628 
1629                   unset($getid3_temp, $getid3_dts);
1630 
1631                 } elseif (substr($testData, 0, 4) == 'wvpk') {
1632 
1633                   // This is WavPack data
1634                   $info['wavpack']['offset'] = $info['avdataoffset'];
1635                   $info['wavpack']['size']   = getid3_lib::LittleEndian2Int(substr($testData, 4, 4));
1636                   $this->parseWavPackHeader(substr($testData, 8, 28));
1637 
1638                 } else {
1639                   // This is some other kind of data (quite possibly just PCM)
1640                   // do nothing special, just skip it
1641                 }
1642                 $nextoffset = $info['avdataend'];
1643                 $this->fseek($nextoffset);
1644                 break;
1645 
1646               case 'iXML':
1647               case 'bext':
1648               case 'cart':
1649               case 'fmt ':
1650               case 'strh':
1651               case 'strf':
1652               case 'indx':
1653               case 'MEXT':
1654               case 'DISP':
1655                 // always read data in
1656               case 'JUNK':
1657                 // should be: never read data in
1658                 // but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc)
1659                 if ($chunksize < 1048576) {
1660                   if ($chunksize > 0) {
1661                     $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
1662                     if ($chunkname == 'JUNK') {
1663                       if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) {
1664                         // only keep text characters [chr(32)-chr(127)]
1665                         $info['riff']['comments']['junk'][] = trim($matches[1]);
1666                       }
1667                       // but if nothing there, ignore
1668                       // remove the key in either case
1669                       unset($RIFFchunk[$chunkname][$thisindex]['data']);
1670                     }
1671                   }
1672                 } else {
1673                   $this->warning('Chunk "'.$chunkname.'" at offset '.$this->ftell().' is unexpectedly larger than 1MB (claims to be '.number_format($chunksize).' bytes), skipping data');
1674                   $this->fseek($chunksize, SEEK_CUR);
1675                 }
1676                 break;
1677 
1678               //case 'IDVX':
1679               //  $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
1680               //  break;
1681 
1682               default:
1683                 if (!empty($LISTchunkParent) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
1684                   $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
1685                   $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size']   = $RIFFchunk[$chunkname][$thisindex]['size'];
1686                   unset($RIFFchunk[$chunkname][$thisindex]['offset']);
1687                   unset($RIFFchunk[$chunkname][$thisindex]['size']);
1688                   if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
1689                     unset($RIFFchunk[$chunkname][$thisindex]);
1690                   }
1691                   if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) {
1692                     unset($RIFFchunk[$chunkname]);
1693                   }
1694                   $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize);
1695                 } elseif ($chunksize < 2048) {
1696                   // only read data in if smaller than 2kB
1697                   $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
1698                 } else {
1699                   $this->fseek($chunksize, SEEK_CUR);
1700                 }
1701                 break;
1702             }
1703             break;
1704         }
1705       }
1706 
1707     } catch (getid3_exception $e) {
1708       if ($e->getCode() == 10) {
1709         $this->warning('RIFF parser: '.$e->getMessage());
1710       } else {
1711         throw $e;
1712       }
1713     }
1714 
1715     return $RIFFchunk;
1716   }
1717 
1718   public function ParseRIFFdata(&$RIFFdata) {
1719     $info = &$this->getid3->info;
1720     if ($RIFFdata) {
1721       $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3');
1722       $fp_temp  = fopen($tempfile, 'wb');
1723       $RIFFdataLength = strlen($RIFFdata);
1724       $NewLengthString = getid3_lib::LittleEndian2String($RIFFdataLength, 4);
1725       for ($i = 0; $i < 4; $i++) {
1726         $RIFFdata[($i + 4)] = $NewLengthString[$i];
1727       }
1728       fwrite($fp_temp, $RIFFdata);
1729       fclose($fp_temp);
1730 
1731       $getid3_temp = new getID3();
1732       $getid3_temp->openfile($tempfile);
1733       $getid3_temp->info['filesize']     = $RIFFdataLength;
1734       $getid3_temp->info['filenamepath'] = $info['filenamepath'];
1735       $getid3_temp->info['tags']         = $info['tags'];
1736       $getid3_temp->info['warning']      = $info['warning'];
1737       $getid3_temp->info['error']        = $info['error'];
1738       $getid3_temp->info['comments']     = $info['comments'];
1739       $getid3_temp->info['audio']        = (isset($info['audio']) ? $info['audio'] : array());
1740       $getid3_temp->info['video']        = (isset($info['video']) ? $info['video'] : array());
1741       $getid3_riff = new getid3_riff($getid3_temp);
1742       $getid3_riff->Analyze();
1743 
1744       $info['riff']     = $getid3_temp->info['riff'];
1745       $info['warning']  = $getid3_temp->info['warning'];
1746       $info['error']    = $getid3_temp->info['error'];
1747       $info['tags']     = $getid3_temp->info['tags'];
1748       $info['comments'] = $getid3_temp->info['comments'];
1749       unset($getid3_riff, $getid3_temp);
1750       unlink($tempfile);
1751     }
1752     return false;
1753   }
1754 
1755   public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
1756     $RIFFinfoKeyLookup = array(
1757       'IARL'=>'archivallocation',
1758       'IART'=>'artist',
1759       'ICDS'=>'costumedesigner',
1760       'ICMS'=>'commissionedby',
1761       'ICMT'=>'comment',
1762       'ICNT'=>'country',
1763       'ICOP'=>'copyright',
1764       'ICRD'=>'creationdate',
1765       'IDIM'=>'dimensions',
1766       'IDIT'=>'digitizationdate',
1767       'IDPI'=>'resolution',
1768       'IDST'=>'distributor',
1769       'IEDT'=>'editor',
1770       'IENG'=>'engineers',
1771       'IFRM'=>'accountofparts',
1772       'IGNR'=>'genre',
1773       'IKEY'=>'keywords',
1774       'ILGT'=>'lightness',
1775       'ILNG'=>'language',
1776       'IMED'=>'orignalmedium',
1777       'IMUS'=>'composer',
1778       'INAM'=>'title',
1779       'IPDS'=>'productiondesigner',
1780       'IPLT'=>'palette',
1781       'IPRD'=>'product',
1782       'IPRO'=>'producer',
1783       'IPRT'=>'part',
1784       'IRTD'=>'rating',
1785       'ISBJ'=>'subject',
1786       'ISFT'=>'software',
1787       'ISGN'=>'secondarygenre',
1788       'ISHP'=>'sharpness',
1789       'ISRC'=>'sourcesupplier',
1790       'ISRF'=>'digitizationsource',
1791       'ISTD'=>'productionstudio',
1792       'ISTR'=>'starring',
1793       'ITCH'=>'encoded_by',
1794       'IWEB'=>'url',
1795       'IWRI'=>'writer',
1796       '____'=>'comment',
1797     );
1798     foreach ($RIFFinfoKeyLookup as $key => $value) {
1799       if (isset($RIFFinfoArray[$key])) {
1800         foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) {
1801           if (trim($commentdata['data']) != '') {
1802             if (isset($CommentsTargetArray[$value])) {
1803               $CommentsTargetArray[$value][] =     trim($commentdata['data']);
1804             } else {
1805               $CommentsTargetArray[$value] = array(trim($commentdata['data']));
1806             }
1807           }
1808         }
1809       }
1810     }
1811     return true;
1812   }
1813 
1814   public static function parseWAVEFORMATex($WaveFormatExData) {
1815     // shortcut
1816     $WaveFormatEx['raw'] = array();
1817     $WaveFormatEx_raw    = &$WaveFormatEx['raw'];
1818 
1819     $WaveFormatEx_raw['wFormatTag']      = substr($WaveFormatExData,  0, 2);
1820     $WaveFormatEx_raw['nChannels']       = substr($WaveFormatExData,  2, 2);
1821     $WaveFormatEx_raw['nSamplesPerSec']  = substr($WaveFormatExData,  4, 4);
1822     $WaveFormatEx_raw['nAvgBytesPerSec'] = substr($WaveFormatExData,  8, 4);
1823     $WaveFormatEx_raw['nBlockAlign']     = substr($WaveFormatExData, 12, 2);
1824     $WaveFormatEx_raw['wBitsPerSample']  = substr($WaveFormatExData, 14, 2);
1825     if (strlen($WaveFormatExData) > 16) {
1826       $WaveFormatEx_raw['cbSize']      = substr($WaveFormatExData, 16, 2);
1827     }
1828     $WaveFormatEx_raw = array_map('getid3_lib::LittleEndian2Int', $WaveFormatEx_raw);
1829 
1830     $WaveFormatEx['codec']           = self::wFormatTagLookup($WaveFormatEx_raw['wFormatTag']);
1831     $WaveFormatEx['channels']        = $WaveFormatEx_raw['nChannels'];
1832     $WaveFormatEx['sample_rate']     = $WaveFormatEx_raw['nSamplesPerSec'];
1833     $WaveFormatEx['bitrate']         = $WaveFormatEx_raw['nAvgBytesPerSec'] * 8;
1834     $WaveFormatEx['bits_per_sample'] = $WaveFormatEx_raw['wBitsPerSample'];
1835 
1836     return $WaveFormatEx;
1837   }
1838 
1839   public function parseWavPackHeader($WavPackChunkData) {
1840     // typedef struct {
1841     //     char ckID [4];
1842     //     long ckSize;
1843     //     short version;
1844     //     short bits;                // added for version 2.00
1845     //     short flags, shift;        // added for version 3.00
1846     //     long total_samples, crc, crc2;
1847     //     char extension [4], extra_bc, extras [3];
1848     // } WavpackHeader;
1849 
1850     // shortcut
1851     $info = &$this->getid3->info;
1852     $info['wavpack']  = array();
1853     $thisfile_wavpack = &$info['wavpack'];
1854 
1855     $thisfile_wavpack['version']           = getid3_lib::LittleEndian2Int(substr($WavPackChunkData,  0, 2));
1856     if ($thisfile_wavpack['version'] >= 2) {
1857       $thisfile_wavpack['bits']          = getid3_lib::LittleEndian2Int(substr($WavPackChunkData,  2, 2));
1858     }
1859     if ($thisfile_wavpack['version'] >= 3) {
1860       $thisfile_wavpack['flags_raw']     = getid3_lib::LittleEndian2Int(substr($WavPackChunkData,  4, 2));
1861       $thisfile_wavpack['shift']         = getid3_lib::LittleEndian2Int(substr($WavPackChunkData,  6, 2));
1862       $thisfile_wavpack['total_samples'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData,  8, 4));
1863       $thisfile_wavpack['crc1']          = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 12, 4));
1864       $thisfile_wavpack['crc2']          = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 16, 4));
1865       $thisfile_wavpack['extension']     =                              substr($WavPackChunkData, 20, 4);
1866       $thisfile_wavpack['extra_bc']      = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 24, 1));
1867       for ($i = 0; $i <= 2; $i++) {
1868         $thisfile_wavpack['extras'][]  = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 25 + $i, 1));
1869       }
1870 
1871       // shortcut
1872       $thisfile_wavpack['flags'] = array();
1873       $thisfile_wavpack_flags = &$thisfile_wavpack['flags'];
1874 
1875       $thisfile_wavpack_flags['mono']                 = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001);
1876       $thisfile_wavpack_flags['fast_mode']            = (bool) ($thisfile_wavpack['flags_raw'] & 0x000002);
1877       $thisfile_wavpack_flags['raw_mode']             = (bool) ($thisfile_wavpack['flags_raw'] & 0x000004);
1878       $thisfile_wavpack_flags['calc_noise']           = (bool) ($thisfile_wavpack['flags_raw'] & 0x000008);
1879       $thisfile_wavpack_flags['high_quality']         = (bool) ($thisfile_wavpack['flags_raw'] & 0x000010);
1880       $thisfile_wavpack_flags['3_byte_samples']       = (bool) ($thisfile_wavpack['flags_raw'] & 0x000020);
1881       $thisfile_wavpack_flags['over_20_bits']         = (bool) ($thisfile_wavpack['flags_raw'] & 0x000040);
1882       $thisfile_wavpack_flags['use_wvc']              = (bool) ($thisfile_wavpack['flags_raw'] & 0x000080);
1883       $thisfile_wavpack_flags['noiseshaping']         = (bool) ($thisfile_wavpack['flags_raw'] & 0x000100);
1884       $thisfile_wavpack_flags['very_fast_mode']       = (bool) ($thisfile_wavpack['flags_raw'] & 0x000200);
1885       $thisfile_wavpack_flags['new_high_quality']     = (bool) ($thisfile_wavpack['flags_raw'] & 0x000400);
1886       $thisfile_wavpack_flags['cancel_extreme']       = (bool) ($thisfile_wavpack['flags_raw'] & 0x000800);
1887       $thisfile_wavpack_flags['cross_decorrelation']  = (bool) ($thisfile_wavpack['flags_raw'] & 0x001000);
1888       $thisfile_wavpack_flags['new_decorrelation']    = (bool) ($thisfile_wavpack['flags_raw'] & 0x002000);
1889       $thisfile_wavpack_flags['joint_stereo']         = (bool) ($thisfile_wavpack['flags_raw'] & 0x004000);
1890       $thisfile_wavpack_flags['extra_decorrelation']  = (bool) ($thisfile_wavpack['flags_raw'] & 0x008000);
1891       $thisfile_wavpack_flags['override_noiseshape']  = (bool) ($thisfile_wavpack['flags_raw'] & 0x010000);
1892       $thisfile_wavpack_flags['override_jointstereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x020000);
1893       $thisfile_wavpack_flags['copy_source_filetime'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x040000);
1894       $thisfile_wavpack_flags['create_exe']           = (bool) ($thisfile_wavpack['flags_raw'] & 0x080000);
1895     }
1896 
1897     return true;
1898   }
1899 
1900   public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
1901 
1902     $parsed['biSize']          = substr($BITMAPINFOHEADER,  0, 4); // number of bytes required by the BITMAPINFOHEADER structure
1903     $parsed['biWidth']         = substr($BITMAPINFOHEADER,  4, 4); // width of the bitmap in pixels
1904     $parsed['biHeight']        = substr($BITMAPINFOHEADER,  8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
1905     $parsed['biPlanes']        = substr($BITMAPINFOHEADER, 12, 2); // number of color planes on the target device. In most cases this value must be set to 1
1906     $parsed['biBitCount']      = substr($BITMAPINFOHEADER, 14, 2); // Specifies the number of bits per pixels
1907     $parsed['biSizeImage']     = substr($BITMAPINFOHEADER, 20, 4); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
1908     $parsed['biXPelsPerMeter'] = substr($BITMAPINFOHEADER, 24, 4); // horizontal resolution, in pixels per metre, of the target device
1909     $parsed['biYPelsPerMeter'] = substr($BITMAPINFOHEADER, 28, 4); // vertical resolution, in pixels per metre, of the target device
1910     $parsed['biClrUsed']       = substr($BITMAPINFOHEADER, 32, 4); // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
1911     $parsed['biClrImportant']  = substr($BITMAPINFOHEADER, 36, 4); // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
1912     $parsed = array_map('getid3_lib::'.($littleEndian ? 'Little' : 'Big').'Endian2Int', $parsed);
1913 
1914     $parsed['fourcc']          = substr($BITMAPINFOHEADER, 16, 4);  // compression identifier
1915 
1916     return $parsed;
1917   }
1918 
1919   public static function ParseDIVXTAG($DIVXTAG, $raw=false) {
1920     // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/
1921     // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip
1922     // 'Byte Layout:                   '1111111111111111
1923     // '32 for Movie - 1               '1111111111111111
1924     // '28 for Author - 6              '6666666666666666
1925     // '4  for year - 2                '6666666666662222
1926     // '3  for genre - 3               '7777777777777777
1927     // '48 for Comments - 7            '7777777777777777
1928     // '1  for Rating - 4              '7777777777777777
1929     // '5  for Future Additions - 0    '333400000DIVXTAG
1930     // '128 bytes total
1931 
1932     static $DIVXTAGgenre  = array(
1933        0 => 'Action',
1934        1 => 'Action/Adventure',
1935        2 => 'Adventure',
1936        3 => 'Adult',
1937        4 => 'Anime',
1938        5 => 'Cartoon',
1939        6 => 'Claymation',
1940        7 => 'Comedy',
1941        8 => 'Commercial',
1942        9 => 'Documentary',
1943       10 => 'Drama',
1944       11 => 'Home Video',
1945       12 => 'Horror',
1946       13 => 'Infomercial',
1947       14 => 'Interactive',
1948       15 => 'Mystery',
1949       16 => 'Music Video',
1950       17 => 'Other',
1951       18 => 'Religion',
1952       19 => 'Sci Fi',
1953       20 => 'Thriller',
1954       21 => 'Western',
1955     ),
1956     $DIVXTAGrating = array(
1957        0 => 'Unrated',
1958        1 => 'G',
1959        2 => 'PG',
1960        3 => 'PG-13',
1961        4 => 'R',
1962        5 => 'NC-17',
1963     );
1964 
1965     $parsed['title']     =        trim(substr($DIVXTAG,   0, 32));
1966     $parsed['artist']    =        trim(substr($DIVXTAG,  32, 28));
1967     $parsed['year']      = intval(trim(substr($DIVXTAG,  60,  4)));
1968     $parsed['comment']   =        trim(substr($DIVXTAG,  64, 48));
1969     $parsed['genre_id']  = intval(trim(substr($DIVXTAG, 112,  3)));
1970     $parsed['rating_id'] =         ord(substr($DIVXTAG, 115,  1));
1971     //$parsed['padding'] =             substr($DIVXTAG, 116,  5);  // 5-byte null
1972     //$parsed['magic']   =             substr($DIVXTAG, 121,  7);  // "DIVXTAG"
1973 
1974     $parsed['genre']  = (isset($DIVXTAGgenre[$parsed['genre_id']])   ? $DIVXTAGgenre[$parsed['genre_id']]   : $parsed['genre_id']);
1975     $parsed['rating'] = (isset($DIVXTAGrating[$parsed['rating_id']]) ? $DIVXTAGrating[$parsed['rating_id']] : $parsed['rating_id']);
1976 
1977     if (!$raw) {
1978       unset($parsed['genre_id'], $parsed['rating_id']);
1979       foreach ($parsed as $key => $value) {
1980         if (!$value === '') {
1981           unset($parsed['key']);
1982         }
1983       }
1984     }
1985 
1986     foreach ($parsed as $tag => $value) {
1987       $parsed[$tag] = array($value);
1988     }
1989 
1990     return $parsed;
1991   }
1992 
1993   public static function waveSNDMtagLookup($tagshortname) {
1994     $begin = __LINE__;
1995 
1996     /** This is not a comment!
1997 
1998       ©kwd keywords
1999       ©BPM bpm
2000       ©trt tracktitle
2001       ©des description
2002       ©gen category
2003       ©fin featuredinstrument
2004       ©LID longid
2005       ©bex bwdescription
2006       ©pub publisher
2007       ©cdt cdtitle
2008       ©alb library
2009       ©com composer
2010 
2011     */
2012 
2013     return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm');
2014   }
2015 
2016   public static function wFormatTagLookup($wFormatTag) {
2017 
2018     $begin = __LINE__;
2019 
2020     /** This is not a comment!
2021 
2022       0x0000  Microsoft Unknown Wave Format
2023       0x0001  Pulse Code Modulation (PCM)
2024       0x0002  Microsoft ADPCM
2025       0x0003  IEEE Float
2026       0x0004  Compaq Computer VSELP
2027       0x0005  IBM CVSD
2028       0x0006  Microsoft A-Law
2029       0x0007  Microsoft mu-Law
2030       0x0008  Microsoft DTS
2031       0x0010  OKI ADPCM
2032       0x0011  Intel DVI/IMA ADPCM
2033       0x0012  Videologic MediaSpace ADPCM
2034       0x0013  Sierra Semiconductor ADPCM
2035       0x0014  Antex Electronics G.723 ADPCM
2036       0x0015  DSP Solutions DigiSTD
2037       0x0016  DSP Solutions DigiFIX
2038       0x0017  Dialogic OKI ADPCM
2039       0x0018  MediaVision ADPCM
2040       0x0019  Hewlett-Packard CU
2041       0x0020  Yamaha ADPCM
2042       0x0021  Speech Compression Sonarc
2043       0x0022  DSP Group TrueSpeech
2044       0x0023  Echo Speech EchoSC1
2045       0x0024  Audiofile AF36
2046       0x0025  Audio Processing Technology APTX
2047       0x0026  AudioFile AF10
2048       0x0027  Prosody 1612
2049       0x0028  LRC
2050       0x0030  Dolby AC2
2051       0x0031  Microsoft GSM 6.10
2052       0x0032  MSNAudio
2053       0x0033  Antex Electronics ADPCME
2054       0x0034  Control Resources VQLPC
2055       0x0035  DSP Solutions DigiREAL
2056       0x0036  DSP Solutions DigiADPCM
2057       0x0037  Control Resources CR10
2058       0x0038  Natural MicroSystems VBXADPCM
2059       0x0039  Crystal Semiconductor IMA ADPCM
2060       0x003A  EchoSC3
2061       0x003B  Rockwell ADPCM
2062       0x003C  Rockwell Digit LK
2063       0x003D  Xebec
2064       0x0040  Antex Electronics G.721 ADPCM
2065       0x0041  G.728 CELP
2066       0x0042  MSG723
2067       0x0050  MPEG Layer-2 or Layer-1
2068       0x0052  RT24
2069       0x0053  PAC
2070       0x0055  MPEG Layer-3
2071       0x0059  Lucent G.723
2072       0x0060  Cirrus
2073       0x0061  ESPCM
2074       0x0062  Voxware
2075       0x0063  Canopus Atrac
2076       0x0064  G.726 ADPCM
2077       0x0065  G.722 ADPCM
2078       0x0066  DSAT
2079       0x0067  DSAT Display
2080       0x0069  Voxware Byte Aligned
2081       0x0070  Voxware AC8
2082       0x0071  Voxware AC10
2083       0x0072  Voxware AC16
2084       0x0073  Voxware AC20
2085       0x0074  Voxware MetaVoice
2086       0x0075  Voxware MetaSound
2087       0x0076  Voxware RT29HW
2088       0x0077  Voxware VR12
2089       0x0078  Voxware VR18
2090       0x0079  Voxware TQ40
2091       0x0080  Softsound
2092       0x0081  Voxware TQ60
2093       0x0082  MSRT24
2094       0x0083  G.729A
2095       0x0084  MVI MV12
2096       0x0085  DF G.726
2097       0x0086  DF GSM610
2098       0x0088  ISIAudio
2099       0x0089  Onlive
2100       0x0091  SBC24
2101       0x0092  Dolby AC3 SPDIF
2102       0x0093  MediaSonic G.723
2103       0x0094  Aculab PLC    Prosody 8kbps
2104       0x0097  ZyXEL ADPCM
2105       0x0098  Philips LPCBB
2106       0x0099  Packed
2107       0x00FF  AAC
2108       0x0100  Rhetorex ADPCM
2109       0x0101  IBM mu-law
2110       0x0102  IBM A-law
2111       0x0103  IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM)
2112       0x0111  Vivo G.723
2113       0x0112  Vivo Siren
2114       0x0123  Digital G.723
2115       0x0125  Sanyo LD ADPCM
2116       0x0130  Sipro Lab Telecom ACELP NET
2117       0x0131  Sipro Lab Telecom ACELP 4800
2118       0x0132  Sipro Lab Telecom ACELP 8V3
2119       0x0133  Sipro Lab Telecom G.729
2120       0x0134  Sipro Lab Telecom G.729A
2121       0x0135  Sipro Lab Telecom Kelvin
2122       0x0140  Windows Media Video V8
2123       0x0150  Qualcomm PureVoice
2124       0x0151  Qualcomm HalfRate
2125       0x0155  Ring Zero Systems TUB GSM
2126       0x0160  Microsoft Audio 1
2127       0x0161  Windows Media Audio V7 / V8 / V9
2128       0x0162  Windows Media Audio Professional V9
2129       0x0163  Windows Media Audio Lossless V9
2130       0x0200  Creative Labs ADPCM
2131       0x0202  Creative Labs Fastspeech8
2132       0x0203  Creative Labs Fastspeech10
2133       0x0210  UHER Informatic GmbH ADPCM
2134       0x0220  Quarterdeck
2135       0x0230  I-link Worldwide VC
2136       0x0240  Aureal RAW Sport
2137       0x0250  Interactive Products HSX
2138       0x0251  Interactive Products RPELP
2139       0x0260  Consistent Software CS2
2140       0x0270  Sony SCX
2141       0x0300  Fujitsu FM Towns Snd
2142       0x0400  BTV Digital
2143       0x0401  Intel Music Coder
2144       0x0450  QDesign Music
2145       0x0680  VME VMPCM
2146       0x0681  AT&T Labs TPC
2147       0x08AE  ClearJump LiteWave
2148       0x1000  Olivetti GSM
2149       0x1001  Olivetti ADPCM
2150       0x1002  Olivetti CELP
2151       0x1003  Olivetti SBC
2152       0x1004  Olivetti OPR
2153       0x1100  Lernout & Hauspie Codec (0x1100)
2154       0x1101  Lernout & Hauspie CELP Codec (0x1101)
2155       0x1102  Lernout & Hauspie SBC Codec (0x1102)
2156       0x1103  Lernout & Hauspie SBC Codec (0x1103)
2157       0x1104  Lernout & Hauspie SBC Codec (0x1104)
2158       0x1400  Norris
2159       0x1401  AT&T ISIAudio
2160       0x1500  Soundspace Music Compression
2161       0x181C  VoxWare RT24 Speech
2162       0x1FC4  NCT Soft ALF2CD (www.nctsoft.com)
2163       0x2000  Dolby AC3
2164       0x2001  Dolby DTS
2165       0x2002  WAVE_FORMAT_14_4
2166       0x2003  WAVE_FORMAT_28_8
2167       0x2004  WAVE_FORMAT_COOK
2168       0x2005  WAVE_FORMAT_DNET
2169       0x674F  Ogg Vorbis 1
2170       0x6750  Ogg Vorbis 2
2171       0x6751  Ogg Vorbis 3
2172       0x676F  Ogg Vorbis 1+
2173       0x6770  Ogg Vorbis 2+
2174       0x6771  Ogg Vorbis 3+
2175       0x7A21  GSM-AMR (CBR, no SID)
2176       0x7A22  GSM-AMR (VBR, including SID)
2177       0xFFFE  WAVE_FORMAT_EXTENSIBLE
2178       0xFFFF  WAVE_FORMAT_DEVELOPMENT
2179 
2180     */
2181 
2182     return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag');
2183   }
2184 
2185   public static function fourccLookup($fourcc) {
2186 
2187     $begin = __LINE__;
2188 
2189     /** This is not a comment!
2190 
2191       swot  http://developer.apple.com/qa/snd/snd07.html
2192       ____  No Codec (____)
2193       _BIT  BI_BITFIELDS (Raw RGB)
2194       _JPG  JPEG compressed
2195       _PNG  PNG compressed W3C/ISO/IEC (RFC-2083)
2196       _RAW  Full Frames (Uncompressed)
2197       _RGB  Raw RGB Bitmap
2198       _RL4  RLE 4bpp RGB
2199       _RL8  RLE 8bpp RGB
2200       3IV1  3ivx MPEG-4 v1
2201       3IV2  3ivx MPEG-4 v2
2202       3IVX  3ivx MPEG-4
2203       AASC  Autodesk Animator
2204       ABYR  Kensington ?ABYR?
2205       AEMI  Array Microsystems VideoONE MPEG1-I Capture
2206       AFLC  Autodesk Animator FLC
2207       AFLI  Autodesk Animator FLI
2208       AMPG  Array Microsystems VideoONE MPEG
2209       ANIM  Intel RDX (ANIM)
2210       AP41  AngelPotion Definitive
2211       ASV1  Asus Video v1
2212       ASV2  Asus Video v2
2213       ASVX  Asus Video 2.0 (audio)
2214       AUR2  AuraVision Aura 2 Codec - YUV 4:2:2
2215       AURA  AuraVision Aura 1 Codec - YUV 4:1:1
2216       AVDJ  Independent JPEG Group\'s codec (AVDJ)
2217       AVRN  Independent JPEG Group\'s codec (AVRN)
2218       AYUV  4:4:4 YUV (AYUV)
2219       AZPR  Quicktime Apple Video (AZPR)
2220       BGR   Raw RGB32
2221       BLZ0  Blizzard DivX MPEG-4
2222       BTVC  Conexant Composite Video
2223       BINK  RAD Game Tools Bink Video
2224       BT20  Conexant Prosumer Video
2225       BTCV  Conexant Composite Video Codec
2226       BW10  Data Translation Broadway MPEG Capture
2227       CC12  Intel YUV12
2228       CDVC  Canopus DV
2229       CFCC  Digital Processing Systems DPS Perception
2230       CGDI  Microsoft Office 97 Camcorder Video
2231       CHAM  Winnov Caviara Champagne
2232       CJPG  Creative WebCam JPEG
2233       CLJR  Cirrus Logic YUV 4:1:1
2234       CMYK  Common Data Format in Printing (Colorgraph)
2235       CPLA  Weitek 4:2:0 YUV Planar
2236       CRAM  Microsoft Video 1 (CRAM)
2237       cvid  Radius Cinepak
2238       CVID  Radius Cinepak
2239       CWLT  Microsoft Color WLT DIB
2240       CYUV  Creative Labs YUV
2241       CYUY  ATI YUV
2242       D261  H.261
2243       D263  H.263
2244       DIB   Device Independent Bitmap
2245       DIV1  FFmpeg OpenDivX
2246       DIV2  Microsoft MPEG-4 v1/v2
2247       DIV3  DivX ;-) MPEG-4 v3.x Low-Motion
2248       DIV4  DivX ;-) MPEG-4 v3.x Fast-Motion
2249       DIV5  DivX MPEG-4 v5.x
2250       DIV6  DivX ;-) (MS MPEG-4 v3.x)
2251       DIVX  DivX MPEG-4 v4 (OpenDivX / Project Mayo)
2252       divx  DivX MPEG-4
2253       DMB1  Matrox Rainbow Runner hardware MJPEG
2254       DMB2  Paradigm MJPEG
2255       DSVD  ?DSVD?
2256       DUCK  Duck TrueMotion 1.0
2257       DPS0  DPS/Leitch Reality Motion JPEG
2258       DPSC  DPS/Leitch PAR Motion JPEG
2259       DV25  Matrox DVCPRO codec
2260       DV50  Matrox DVCPRO50 codec
2261       DVC   IEC 61834 and SMPTE 314M (DVC/DV Video)
2262       DVCP  IEC 61834 and SMPTE 314M (DVC/DV Video)
2263       DVHD  IEC Standard DV 1125 lines @ 30fps / 1250 lines @ 25fps
2264       DVMA  Darim Vision DVMPEG (dummy for MPEG compressor) (www.darvision.com)
2265       DVSL  IEC Standard DV compressed in SD (SDL)
2266       DVAN  ?DVAN?
2267       DVE2  InSoft DVE-2 Videoconferencing
2268       dvsd  IEC 61834 and SMPTE 314M DVC/DV Video
2269       DVSD  IEC 61834 and SMPTE 314M DVC/DV Video
2270       DVX1  Lucent DVX1000SP Video Decoder
2271       DVX2  Lucent DVX2000S Video Decoder
2272       DVX3  Lucent DVX3000S Video Decoder
2273       DX50  DivX v5
2274       DXT1  Microsoft DirectX Compressed Texture (DXT1)
2275       DXT2  Microsoft DirectX Compressed Texture (DXT2)
2276       DXT3  Microsoft DirectX Compressed Texture (DXT3)
2277       DXT4  Microsoft DirectX Compressed Texture (DXT4)
2278       DXT5  Microsoft DirectX Compressed Texture (DXT5)
2279       DXTC  Microsoft DirectX Compressed Texture (DXTC)
2280       DXTn  Microsoft DirectX Compressed Texture (DXTn)
2281       EM2V  Etymonix MPEG-2 I-frame (www.etymonix.com)
2282       EKQ0  Elsa ?EKQ0?
2283       ELK0  Elsa ?ELK0?
2284       ESCP  Eidos Escape
2285       ETV1  eTreppid Video ETV1
2286       ETV2  eTreppid Video ETV2
2287       ETVC  eTreppid Video ETVC
2288       FLIC  Autodesk FLI/FLC Animation
2289       FLV1  Sorenson Spark
2290       FLV4  On2 TrueMotion VP6
2291       FRWT  Darim Vision Forward Motion JPEG (www.darvision.com)
2292       FRWU  Darim Vision Forward Uncompressed (www.darvision.com)
2293       FLJP  D-Vision Field Encoded Motion JPEG
2294       FPS1  FRAPS v1
2295       FRWA  SoftLab-Nsk Forward Motion JPEG w/ alpha channel
2296       FRWD  SoftLab-Nsk Forward Motion JPEG
2297       FVF1  Iterated Systems Fractal Video Frame
2298       GLZW  Motion LZW (gabest@freemail.hu)
2299       GPEG  Motion JPEG (gabest@freemail.hu)
2300       GWLT  Microsoft Greyscale WLT DIB
2301       H260  Intel ITU H.260 Videoconferencing
2302       H261  Intel ITU H.261 Videoconferencing
2303       H262  Intel ITU H.262 Videoconferencing
2304       H263  Intel ITU H.263 Videoconferencing
2305       H264  Intel ITU H.264 Videoconferencing
2306       H265  Intel ITU H.265 Videoconferencing
2307       H266  Intel ITU H.266 Videoconferencing
2308       H267  Intel ITU H.267 Videoconferencing
2309       H268  Intel ITU H.268 Videoconferencing
2310       H269  Intel ITU H.269 Videoconferencing
2311       HFYU  Huffman Lossless Codec
2312       HMCR  Rendition Motion Compensation Format (HMCR)
2313       HMRR  Rendition Motion Compensation Format (HMRR)
2314       I263  FFmpeg I263 decoder
2315       IF09  Indeo YVU9 ("YVU9 with additional delta-frame info after the U plane")
2316       IUYV  Interlaced version of UYVY (www.leadtools.com)
2317       IY41  Interlaced version of Y41P (www.leadtools.com)
2318       IYU1  12 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec    IEEE standard
2319       IYU2  24 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec    IEEE standard
2320       IYUV  Planar YUV format (8-bpp Y plane, followed by 8-bpp 2×2 U and V planes)
2321       i263  Intel ITU H.263 Videoconferencing (i263)
2322       I420  Intel Indeo 4
2323       IAN   Intel Indeo 4 (RDX)
2324       ICLB  InSoft CellB Videoconferencing
2325       IGOR  Power DVD
2326       IJPG  Intergraph JPEG
2327       ILVC  Intel Layered Video
2328       ILVR  ITU-T H.263+
2329       IPDV  I-O Data Device Giga AVI DV Codec
2330       IR21  Intel Indeo 2.1
2331       IRAW  Intel YUV Uncompressed
2332       IV30  Intel Indeo 3.0
2333       IV31  Intel Indeo 3.1
2334       IV32  Ligos Indeo 3.2
2335       IV33  Ligos Indeo 3.3
2336       IV34  Ligos Indeo 3.4
2337       IV35  Ligos Indeo 3.5
2338       IV36  Ligos Indeo 3.6
2339       IV37  Ligos Indeo 3.7
2340       IV38  Ligos Indeo 3.8
2341       IV39  Ligos Indeo 3.9
2342       IV40  Ligos Indeo Interactive 4.0
2343       IV41  Ligos Indeo Interactive 4.1
2344       IV42  Ligos Indeo Interactive 4.2
2345       IV43  Ligos Indeo Interactive 4.3
2346       IV44  Ligos Indeo Interactive 4.4
2347       IV45  Ligos Indeo Interactive 4.5
2348       IV46  Ligos Indeo Interactive 4.6
2349       IV47  Ligos Indeo Interactive 4.7
2350       IV48  Ligos Indeo Interactive 4.8
2351       IV49  Ligos Indeo Interactive 4.9
2352       IV50  Ligos Indeo Interactive 5.0
2353       JBYR  Kensington ?JBYR?
2354       JPEG  Still Image JPEG DIB
2355       JPGL  Pegasus Lossless Motion JPEG
2356       KMVC  Team17 Software Karl Morton\'s Video Codec
2357       LSVM  Vianet Lighting Strike Vmail (Streaming) (www.vianet.com)
2358       LEAD  LEAD Video Codec
2359       Ljpg  LEAD MJPEG Codec
2360       MDVD  Alex MicroDVD Video (hacked MS MPEG-4) (www.tiasoft.de)
2361       MJPA  Morgan Motion JPEG (MJPA) (www.morgan-multimedia.com)
2362       MJPB  Morgan Motion JPEG (MJPB) (www.morgan-multimedia.com)
2363       MMES  Matrox MPEG-2 I-frame
2364       MP2v  Microsoft S-Mpeg 4 version 1 (MP2v)
2365       MP42  Microsoft S-Mpeg 4 version 2 (MP42)
2366       MP43  Microsoft S-Mpeg 4 version 3 (MP43)
2367       MP4S  Microsoft S-Mpeg 4 version 3 (MP4S)
2368       MP4V  FFmpeg MPEG-4
2369       MPG1  FFmpeg MPEG 1/2
2370       MPG2  FFmpeg MPEG 1/2
2371       MPG3  FFmpeg DivX ;-) (MS MPEG-4 v3)
2372       MPG4  Microsoft MPEG-4
2373       MPGI  Sigma Designs MPEG
2374       MPNG  PNG images decoder
2375       MSS1  Microsoft Windows Screen Video
2376       MSZH  LCL (Lossless Codec Library) (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
2377       M261  Microsoft H.261
2378       M263  Microsoft H.263
2379       M4S2  Microsoft Fully Compliant MPEG-4 v2 simple profile (M4S2)
2380       m4s2  Microsoft Fully Compliant MPEG-4 v2 simple profile (m4s2)
2381       MC12  ATI Motion Compensation Format (MC12)
2382       MCAM  ATI Motion Compensation Format (MCAM)
2383       MJ2C  Morgan Multimedia Motion JPEG2000
2384       mJPG  IBM Motion JPEG w/ Huffman Tables
2385       MJPG  Microsoft Motion JPEG DIB
2386       MP42  Microsoft MPEG-4 (low-motion)
2387       MP43  Microsoft MPEG-4 (fast-motion)
2388       MP4S  Microsoft MPEG-4 (MP4S)
2389       mp4s  Microsoft MPEG-4 (mp4s)
2390       MPEG  Chromatic Research MPEG-1 Video I-Frame
2391       MPG4  Microsoft MPEG-4 Video High Speed Compressor
2392       MPGI  Sigma Designs MPEG
2393       MRCA  FAST Multimedia Martin Regen Codec
2394       MRLE  Microsoft Run Length Encoding
2395       MSVC  Microsoft Video 1
2396       MTX1  Matrox ?MTX1?
2397       MTX2  Matrox ?MTX2?
2398       MTX3  Matrox ?MTX3?
2399       MTX4  Matrox ?MTX4?
2400       MTX5  Matrox ?MTX5?
2401       MTX6  Matrox ?MTX6?
2402       MTX7  Matrox ?MTX7?
2403       MTX8  Matrox ?MTX8?
2404       MTX9  Matrox ?MTX9?
2405       MV12  Motion Pixels Codec (old)
2406       MWV1  Aware Motion Wavelets
2407       nAVI  SMR Codec (hack of Microsoft MPEG-4) (IRC #shadowrealm)
2408       NT00  NewTek LightWave HDTV YUV w/ Alpha (www.newtek.com)
2409       NUV1  NuppelVideo
2410       NTN1  Nogatech Video Compression 1
2411       NVS0  nVidia GeForce Texture (NVS0)
2412       NVS1  nVidia GeForce Texture (NVS1)
2413       NVS2  nVidia GeForce Texture (NVS2)
2414       NVS3  nVidia GeForce Texture (NVS3)
2415       NVS4  nVidia GeForce Texture (NVS4)
2416       NVS5  nVidia GeForce Texture (NVS5)
2417       NVT0  nVidia GeForce Texture (NVT0)
2418       NVT1  nVidia GeForce Texture (NVT1)
2419       NVT2  nVidia GeForce Texture (NVT2)
2420       NVT3  nVidia GeForce Texture (NVT3)
2421       NVT4  nVidia GeForce Texture (NVT4)
2422       NVT5  nVidia GeForce Texture (NVT5)
2423       PIXL  MiroXL, Pinnacle PCTV
2424       PDVC  I-O Data Device Digital Video Capture DV codec
2425       PGVV  Radius Video Vision
2426       PHMO  IBM Photomotion
2427       PIM1  MPEG Realtime (Pinnacle Cards)
2428       PIM2  Pegasus Imaging ?PIM2?
2429       PIMJ  Pegasus Imaging Lossless JPEG
2430       PVEZ  Horizons Technology PowerEZ
2431       PVMM  PacketVideo Corporation MPEG-4
2432       PVW2  Pegasus Imaging Wavelet Compression
2433       Q1.0  Q-Team\'s QPEG 1.0 (www.q-team.de)
2434       Q1.1  Q-Team\'s QPEG 1.1 (www.q-team.de)
2435       QPEG  Q-Team QPEG 1.0
2436       qpeq  Q-Team QPEG 1.1
2437       RGB   Raw BGR32
2438       RGBA  Raw RGB w/ Alpha
2439       RMP4  REALmagic MPEG-4 (unauthorized XVID copy) (www.sigmadesigns.com)
2440       ROQV  Id RoQ File Video Decoder
2441       RPZA  Quicktime Apple Video (RPZA)
2442       RUD0  Rududu video codec (http://rududu.ifrance.com/rududu/)
2443       RV10  RealVideo 1.0 (aka RealVideo 5.0)
2444       RV13  RealVideo 1.0 (RV13)
2445       RV20  RealVideo G2
2446       RV30  RealVideo 8
2447       RV40  RealVideo 9
2448       RGBT  Raw RGB w/ Transparency
2449       RLE   Microsoft Run Length Encoder
2450       RLE4  Run Length Encoded (4bpp, 16-color)
2451       RLE8  Run Length Encoded (8bpp, 256-color)
2452       RT21  Intel Indeo RealTime Video 2.1
2453       rv20  RealVideo G2
2454       rv30  RealVideo 8
2455       RVX   Intel RDX (RVX )
2456       SMC   Apple Graphics (SMC )
2457       SP54  Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2
2458       SPIG  Radius Spigot
2459       SVQ3  Sorenson Video 3 (Apple Quicktime 5)
2460       s422  Tekram VideoCap C210 YUV 4:2:2
2461       SDCC  Sun Communication Digital Camera Codec
2462       SFMC  CrystalNet Surface Fitting Method
2463       SMSC  Radius SMSC
2464       SMSD  Radius SMSD
2465       smsv  WorldConnect Wavelet Video
2466       SPIG  Radius Spigot
2467       SPLC  Splash Studios ACM Audio Codec (www.splashstudios.net)
2468       SQZ2  Microsoft VXTreme Video Codec V2
2469       STVA  ST Microelectronics CMOS Imager Data (Bayer)
2470       STVB  ST Microelectronics CMOS Imager Data (Nudged Bayer)
2471       STVC  ST Microelectronics CMOS Imager Data (Bunched)
2472       STVX  ST Microelectronics CMOS Imager Data (Extended CODEC Data Format)
2473       STVY  ST Microelectronics CMOS Imager Data (Extended CODEC Data Format with Correction Data)
2474       SV10  Sorenson Video R1
2475       SVQ1  Sorenson Video
2476       T420  Toshiba YUV 4:2:0
2477       TM2A  Duck TrueMotion Archiver 2.0 (www.duck.com)
2478       TVJP  Pinnacle/Truevision Targa 2000 board (TVJP)
2479       TVMJ  Pinnacle/Truevision Targa 2000 board (TVMJ)
2480       TY0N  Tecomac Low-Bit Rate Codec (www.tecomac.com)
2481       TY2C  Trident Decompression Driver
2482       TLMS  TeraLogic Motion Intraframe Codec (TLMS)
2483       TLST  TeraLogic Motion Intraframe Codec (TLST)
2484       TM20  Duck TrueMotion 2.0
2485       TM2X  Duck TrueMotion 2X
2486       TMIC  TeraLogic Motion Intraframe Codec (TMIC)
2487       TMOT  Horizons Technology TrueMotion S
2488       tmot  Horizons TrueMotion Video Compression
2489       TR20  Duck TrueMotion RealTime 2.0
2490       TSCC  TechSmith Screen Capture Codec
2491       TV10  Tecomac Low-Bit Rate Codec
2492       TY2N  Trident ?TY2N?
2493       U263  UB Video H.263/H.263+/H.263++ Decoder
2494       UMP4  UB Video MPEG 4 (www.ubvideo.com)
2495       UYNV  Nvidia UYVY packed 4:2:2
2496       UYVP  Evans & Sutherland YCbCr 4:2:2 extended precision
2497       UCOD  eMajix.com ClearVideo
2498       ULTI  IBM Ultimotion
2499       UYVY  UYVY packed 4:2:2
2500       V261  Lucent VX2000S
2501       VIFP  VFAPI Reader Codec (www.yks.ne.jp/~hori/)
2502       VIV1  FFmpeg H263+ decoder
2503       VIV2  Vivo H.263
2504       VQC2  Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf)
2505       VTLP  Alaris VideoGramPiX
2506       VYU9  ATI YUV (VYU9)
2507       VYUY  ATI YUV (VYUY)
2508       V261  Lucent VX2000S
2509       V422  Vitec Multimedia 24-bit YUV 4:2:2 Format
2510       V655  Vitec Multimedia 16-bit YUV 4:2:2 Format
2511       VCR1  ATI Video Codec 1
2512       VCR2  ATI Video Codec 2
2513       VCR3  ATI VCR 3.0
2514       VCR4  ATI VCR 4.0
2515       VCR5  ATI VCR 5.0
2516       VCR6  ATI VCR 6.0
2517       VCR7  ATI VCR 7.0
2518       VCR8  ATI VCR 8.0
2519       VCR9  ATI VCR 9.0
2520       VDCT  Vitec Multimedia Video Maker Pro DIB
2521       VDOM  VDOnet VDOWave
2522       VDOW  VDOnet VDOLive (H.263)
2523       VDTZ  Darim Vison VideoTizer YUV
2524       VGPX  Alaris VideoGramPiX
2525       VIDS  Vitec Multimedia YUV 4:2:2 CCIR 601 for V422
2526       VIVO  Vivo H.263 v2.00
2527       vivo  Vivo H.263
2528       VIXL  Miro/Pinnacle Video XL
2529       VLV1  VideoLogic/PURE Digital Videologic Capture
2530       VP30  On2 VP3.0
2531       VP31  On2 VP3.1
2532       VP6F  On2 TrueMotion VP6
2533       VX1K  Lucent VX1000S Video Codec
2534       VX2K  Lucent VX2000S Video Codec
2535       VXSP  Lucent VX1000SP Video Codec
2536       WBVC  Winbond W9960
2537       WHAM  Microsoft Video 1 (WHAM)
2538       WINX  Winnov Software Compression
2539       WJPG  AverMedia Winbond JPEG
2540       WMV1  Windows Media Video V7
2541       WMV2  Windows Media Video V8
2542       WMV3  Windows Media Video V9
2543       WNV1  Winnov Hardware Compression
2544       XYZP  Extended PAL format XYZ palette (www.riff.org)
2545       x263  Xirlink H.263
2546       XLV0  NetXL Video Decoder
2547       XMPG  Xing MPEG (I-Frame only)
2548       XVID  XviD MPEG-4 (www.xvid.org)
2549       XXAN  ?XXAN?
2550       YU92  Intel YUV (YU92)
2551       YUNV  Nvidia Uncompressed YUV 4:2:2
2552       YUVP  Extended PAL format YUV palette (www.riff.org)
2553       Y211  YUV 2:1:1 Packed
2554       Y411  YUV 4:1:1 Packed
2555       Y41B  Weitek YUV 4:1:1 Planar
2556       Y41P  Brooktree PC1 YUV 4:1:1 Packed
2557       Y41T  Brooktree PC1 YUV 4:1:1 with transparency
2558       Y42B  Weitek YUV 4:2:2 Planar
2559       Y42T  Brooktree UYUV 4:2:2 with transparency
2560       Y422  ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera
2561       Y800  Simple, single Y plane for monochrome images
2562       Y8    Grayscale video
2563       YC12  Intel YUV 12 codec
2564       YUV8  Winnov Caviar YUV8
2565       YUV9  Intel YUV9
2566       YUY2  Uncompressed YUV 4:2:2
2567       YUYV  Canopus YUV
2568       YV12  YVU12 Planar
2569       YVU9  Intel YVU9 Planar (8-bpp Y plane, followed by 8-bpp 4x4 U and V planes)
2570       YVYU  YVYU 4:2:2 Packed
2571       ZLIB  Lossless Codec Library zlib compression (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
2572       ZPEG  Metheus Video Zipper
2573 
2574     */
2575 
2576     return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
2577   }
2578 
2579   private function EitherEndian2Int($byteword, $signed=false) {
2580     if ($this->container == 'riff') {
2581       return getid3_lib::LittleEndian2Int($byteword, $signed);
2582     }
2583     return getid3_lib::BigEndian2Int($byteword, false, $signed);
2584   }
2585 
2586 }