[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/ID3/ -> module.audio-video.riff.php (source)

   1  <?php
   2  
   3  /////////////////////////////////////////////////////////////////
   4  /// getID3() by James Heinrich <info@getid3.org>               //
   5  //  available at https://github.com/JamesHeinrich/getID3       //
   6  //            or https://www.getid3.org                        //
   7  //            or http://getid3.sourceforge.net                 //
   8  //  see readme.txt for more details                            //
   9  /////////////////////////////////////////////////////////////////
  10  //                                                             //
  11  // module.audio-video.riff.php                                 //
  12  // module for analyzing RIFF files                             //
  13  // multiple formats supported by this module:                  //
  14  //    Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack v3, 8SVX   //
  15  // dependencies: module.audio.mp3.php                          //
  16  //               module.audio.ac3.php                          //
  17  //               module.audio.dts.php                          //
  18  //                                                            ///
  19  /////////////////////////////////////////////////////////////////
  20  
  21  /**
  22  * @todo Parse AC-3/DTS audio inside WAVE correctly
  23  * @todo Rewrite RIFF parser totally
  24  */
  25  
  26  if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
  27      exit;
  28  }
  29  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
  30  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
  31  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
  32  
  33  class getid3_riff extends getid3_handler
  34  {
  35      protected $container = 'riff'; // default
  36  
  37      /**
  38       * @return bool
  39       *
  40       * @throws getid3_exception
  41       */
  42  	public function Analyze() {
  43          $info = &$this->getid3->info;
  44  
  45          // initialize these values to an empty array, otherwise they default to NULL
  46          // and you can't append array values to a NULL value
  47          $info['riff'] = array('raw'=>array());
  48  
  49          // Shortcuts
  50          $thisfile_riff             = &$info['riff'];
  51          $thisfile_riff_raw         = &$thisfile_riff['raw'];
  52          $thisfile_audio            = &$info['audio'];
  53          $thisfile_video            = &$info['video'];
  54          $thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
  55          $thisfile_riff_audio       = &$thisfile_riff['audio'];
  56          $thisfile_riff_video       = &$thisfile_riff['video'];
  57          $thisfile_riff_WAVE        = array();
  58  
  59          $Original                 = array();
  60          $Original['avdataoffset'] = $info['avdataoffset'];
  61          $Original['avdataend']    = $info['avdataend'];
  62  
  63          $this->fseek($info['avdataoffset']);
  64          $RIFFheader = $this->fread(12);
  65          $offset = $this->ftell();
  66          $RIFFtype    = substr($RIFFheader, 0, 4);
  67          $RIFFsize    = substr($RIFFheader, 4, 4);
  68          $RIFFsubtype = substr($RIFFheader, 8, 4);
  69  
  70          switch ($RIFFtype) {
  71  
  72              case 'FORM':  // AIFF, AIFC
  73                  //$info['fileformat']   = 'aiff';
  74                  $this->container = 'aiff';
  75                  $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
  76                  $thisfile_riff[$RIFFsubtype]  = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
  77                  break;
  78  
  79              case 'RIFF':  // AVI, WAV, etc
  80              case 'SDSS':  // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
  81              case 'RMP3':  // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
  82                  //$info['fileformat']   = 'riff';
  83                  $this->container = 'riff';
  84                  $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
  85                  if ($RIFFsubtype == 'RMP3') {
  86                      // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
  87                      $RIFFsubtype = 'WAVE';
  88                  }
  89                  if ($RIFFsubtype != 'AMV ') {
  90                      // 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
  91                      // Handled separately in ParseRIFFAMV()
  92                      $thisfile_riff[$RIFFsubtype]  = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
  93                  }
  94                  if (($info['avdataend'] - $info['filesize']) == 1) {
  95                      // LiteWave appears to incorrectly *not* pad actual output file
  96                      // to nearest WORD boundary so may appear to be short by one
  97                      // byte, in which case - skip warning
  98                      $info['avdataend'] = $info['filesize'];
  99                  }
 100  
 101                  $nextRIFFoffset = $Original['avdataoffset'] + 8 + $thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset
 102                  while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) {
 103                      try {
 104                          $this->fseek($nextRIFFoffset);
 105                      } catch (getid3_exception $e) {
 106                          if ($e->getCode() == 10) {
 107                              //$this->warning('RIFF parser: '.$e->getMessage());
 108                              $this->error('AVI extends beyond '.round(PHP_INT_MAX / 1073741824).'GB and PHP filesystem functions cannot read that far, playtime may be wrong');
 109                              $this->warning('[avdataend] value may be incorrect, multiple AVIX chunks may be present');
 110                              break;
 111                          } else {
 112                              throw $e;
 113                          }
 114                      }
 115                      $nextRIFFheader = $this->fread(12);
 116                      if ($nextRIFFoffset == ($info['avdataend'] - 1)) {
 117                          if (substr($nextRIFFheader, 0, 1) == "\x00") {
 118                              // RIFF padded to WORD boundary, we're actually already at the end
 119                              break;
 120                          }
 121                      }
 122                      $nextRIFFheaderID =                         substr($nextRIFFheader, 0, 4);
 123                      $nextRIFFsize     = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4));
 124                      $nextRIFFtype     =                         substr($nextRIFFheader, 8, 4);
 125                      $chunkdata = array();
 126                      $chunkdata['offset'] = $nextRIFFoffset + 8;
 127                      $chunkdata['size']   = $nextRIFFsize;
 128                      $nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
 129  
 130                      switch ($nextRIFFheaderID) {
 131                          case 'RIFF':
 132                              $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset);
 133                              if (!isset($thisfile_riff[$nextRIFFtype])) {
 134                                  $thisfile_riff[$nextRIFFtype] = array();
 135                              }
 136                              $thisfile_riff[$nextRIFFtype][] = $chunkdata;
 137                              break;
 138  
 139                          case 'AMV ':
 140                              unset($info['riff']);
 141                              $info['amv'] = $this->ParseRIFFAMV($chunkdata['offset'] + 4, $nextRIFFoffset);
 142                              break;
 143  
 144                          case 'JUNK':
 145                              // ignore
 146                              $thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
 147                              break;
 148  
 149                          case 'IDVX':
 150                              $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunkdata['size']));
 151                              break;
 152  
 153                          default:
 154                              if ($info['filesize'] == ($chunkdata['offset'] - 8 + 128)) {
 155                                  $DIVXTAG = $nextRIFFheader.$this->fread(128 - 12);
 156                                  if (substr($DIVXTAG, -7) == 'DIVXTAG') {
 157                                      // 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
 158                                      $this->warning('Found wrongly-structured DIVXTAG at offset '.($this->ftell() - 128).', parsing anyway');
 159                                      $info['divxtag']['comments'] = self::ParseDIVXTAG($DIVXTAG);
 160                                      break 2;
 161                                  }
 162                              }
 163                              $this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file');
 164                              break 2;
 165  
 166                      }
 167  
 168                  }
 169                  if ($RIFFsubtype == 'WAVE') {
 170                      $thisfile_riff_WAVE = &$thisfile_riff['WAVE'];
 171                  }
 172                  break;
 173  
 174              default:
 175                  $this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead');
 176                  //unset($info['fileformat']);
 177                  return false;
 178          }
 179  
 180          $streamindex = 0;
 181          switch ($RIFFsubtype) {
 182  
 183              // http://en.wikipedia.org/wiki/Wav
 184              case 'WAVE':
 185                  $info['fileformat'] = 'wav';
 186  
 187                  if (empty($thisfile_audio['bitrate_mode'])) {
 188                      $thisfile_audio['bitrate_mode'] = 'cbr';
 189                  }
 190                  if (empty($thisfile_audio_dataformat)) {
 191                      $thisfile_audio_dataformat = 'wav';
 192                  }
 193  
 194                  if (isset($thisfile_riff_WAVE['data'][0]['offset'])) {
 195                      $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] + 8;
 196                      $info['avdataend']    = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size'];
 197                  }
 198                  if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
 199  
 200                      $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
 201                      $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
 202                      if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) {
 203                          $this->error('Corrupt RIFF file: bitrate_audio == zero');
 204                          return false;
 205                      }
 206                      $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
 207                      unset($thisfile_riff_audio[$streamindex]['raw']);
 208                      $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
 209  
 210                      $thisfile_audio = (array) getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
 211                      if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
 212                          $this->warning('Audio codec = '.$thisfile_audio['codec']);
 213                      }
 214                      $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
 215  
 216                      if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV)
 217                          $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
 218                      }
 219  
 220                      $thisfile_audio['lossless'] = false;
 221                      if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
 222                          switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
 223  
 224                              case 0x0001:  // PCM
 225                                  $thisfile_audio['lossless'] = true;
 226                                  break;
 227  
 228                              case 0x2000:  // AC-3
 229                                  $thisfile_audio_dataformat = 'ac3';
 230                                  break;
 231  
 232                              default:
 233                                  // do nothing
 234                                  break;
 235  
 236                          }
 237                      }
 238                      $thisfile_audio['streams'][$streamindex]['wformattag']   = $thisfile_audio['wformattag'];
 239                      $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
 240                      $thisfile_audio['streams'][$streamindex]['lossless']     = $thisfile_audio['lossless'];
 241                      $thisfile_audio['streams'][$streamindex]['dataformat']   = $thisfile_audio_dataformat;
 242                  }
 243  
 244                  if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
 245  
 246                      // shortcuts
 247                      $rgadData = &$thisfile_riff_WAVE['rgad'][0]['data'];
 248                      $thisfile_riff_raw['rgad']    = array('track'=>array(), 'album'=>array());
 249                      $thisfile_riff_raw_rgad       = &$thisfile_riff_raw['rgad'];
 250                      $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track'];
 251                      $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album'];
 252  
 253                      $thisfile_riff_raw_rgad['fPeakAmplitude']      = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4));
 254                      $thisfile_riff_raw_rgad['nRadioRgAdjust']      =        $this->EitherEndian2Int(substr($rgadData, 4, 2));
 255                      $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] =        $this->EitherEndian2Int(substr($rgadData, 6, 2));
 256  
 257                      $nRadioRgAdjustBitstring      = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
 258                      $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
 259                      $thisfile_riff_raw_rgad_track['name']       = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
 260                      $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
 261                      $thisfile_riff_raw_rgad_track['signbit']    = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
 262                      $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
 263                      $thisfile_riff_raw_rgad_album['name']       = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
 264                      $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
 265                      $thisfile_riff_raw_rgad_album['signbit']    = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
 266                      $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
 267  
 268                      $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude'];
 269                      if (($thisfile_riff_raw_rgad_track['name'] != 0) && ($thisfile_riff_raw_rgad_track['originator'] != 0)) {
 270                          $thisfile_riff['rgad']['track']['name']            = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']);
 271                          $thisfile_riff['rgad']['track']['originator']      = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']);
 272                          $thisfile_riff['rgad']['track']['adjustment']      = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']);
 273                      }
 274                      if (($thisfile_riff_raw_rgad_album['name'] != 0) && ($thisfile_riff_raw_rgad_album['originator'] != 0)) {
 275                          $thisfile_riff['rgad']['album']['name']       = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']);
 276                          $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']);
 277                          $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']);
 278                      }
 279                  }
 280  
 281                  if (isset($thisfile_riff_WAVE['fact'][0]['data'])) {
 282                      $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4));
 283  
 284                      // This should be a good way of calculating exact playtime,
 285                      // but some sample files have had incorrect number of samples,
 286                      // so cannot use this method
 287  
 288                      // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
 289                      //     $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
 290                      // }
 291                  }
 292                  if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
 293                      $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
 294                  }
 295  
 296                  if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
 297                      // shortcut
 298                      $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
 299  
 300                      $thisfile_riff_WAVE_bext_0['title']          =                              substr($thisfile_riff_WAVE_bext_0['data'],   0, 256);
 301                      $thisfile_riff_WAVE_bext_0['author']         =                              substr($thisfile_riff_WAVE_bext_0['data'], 256,  32);
 302                      $thisfile_riff_WAVE_bext_0['reference']      =                              substr($thisfile_riff_WAVE_bext_0['data'], 288,  32);
 303                      foreach (array('title','author','reference') as $bext_key) {
 304                          // Some software (notably Logic Pro) may not blank existing data before writing a null-terminated string to the offsets
 305                          // assigned for text fields, resulting in a null-terminated string (or possibly just a single null) followed by garbage
 306                          // Keep only string as far as first null byte, discard rest of fixed-width data
 307                          // https://github.com/JamesHeinrich/getID3/issues/263
 308                          $null_terminator_offset = strpos($thisfile_riff_WAVE_bext_0[$bext_key], "\x00");
 309                          $thisfile_riff_WAVE_bext_0[$bext_key] = substr($thisfile_riff_WAVE_bext_0[$bext_key], 0, $null_terminator_offset);
 310                      }
 311  
 312                      $thisfile_riff_WAVE_bext_0['origin_date']    =                              substr($thisfile_riff_WAVE_bext_0['data'], 320,  10);
 313                      $thisfile_riff_WAVE_bext_0['origin_time']    =                              substr($thisfile_riff_WAVE_bext_0['data'], 330,   8);
 314                      $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338,   8));
 315                      $thisfile_riff_WAVE_bext_0['bwf_version']    = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346,   1));
 316                      $thisfile_riff_WAVE_bext_0['reserved']       =                              substr($thisfile_riff_WAVE_bext_0['data'], 347, 254);
 317                      $thisfile_riff_WAVE_bext_0['coding_history'] =         explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
 318                      if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
 319                          if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
 320                              $bext_timestamp = array();
 321                              list($dummy, $bext_timestamp['year'], $bext_timestamp['month'],  $bext_timestamp['day'])    = $matches_bext_date;
 322                              list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
 323                              $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']);
 324                          } else {
 325                              $this->warning('RIFF.WAVE.BEXT.origin_time is invalid');
 326                          }
 327                      } else {
 328                          $this->warning('RIFF.WAVE.BEXT.origin_date is invalid');
 329                      }
 330                      $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
 331                      $thisfile_riff['comments']['title'][]  = $thisfile_riff_WAVE_bext_0['title'];
 332                  }
 333  
 334                  if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
 335                      // shortcut
 336                      $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0];
 337  
 338                      $thisfile_riff_WAVE_MEXT_0['raw']['sound_information']      = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2));
 339                      $thisfile_riff_WAVE_MEXT_0['flags']['homogenous']           = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0001);
 340                      if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) {
 341                          $thisfile_riff_WAVE_MEXT_0['flags']['padding']          = ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0002) ? false : true;
 342                          $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44']         =        (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0004);
 343                          $thisfile_riff_WAVE_MEXT_0['flags']['free_format']      =        (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0008);
 344  
 345                          $thisfile_riff_WAVE_MEXT_0['nominal_frame_size']        = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
 346                      }
 347                      $thisfile_riff_WAVE_MEXT_0['anciliary_data_length']         = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2));
 348                      $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def']     = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2));
 349                      $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left']  = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0001);
 350                      $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free']  = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0002);
 351                      $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0004);
 352                  }
 353  
 354                  if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
 355                      // shortcut
 356                      $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0];
 357  
 358                      $thisfile_riff_WAVE_cart_0['version']              =                              substr($thisfile_riff_WAVE_cart_0['data'],   0,  4);
 359                      $thisfile_riff_WAVE_cart_0['title']                =                         trim(substr($thisfile_riff_WAVE_cart_0['data'],   4, 64));
 360                      $thisfile_riff_WAVE_cart_0['artist']               =                         trim(substr($thisfile_riff_WAVE_cart_0['data'],  68, 64));
 361                      $thisfile_riff_WAVE_cart_0['cut_id']               =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64));
 362                      $thisfile_riff_WAVE_cart_0['client_id']            =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64));
 363                      $thisfile_riff_WAVE_cart_0['category']             =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64));
 364                      $thisfile_riff_WAVE_cart_0['classification']       =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64));
 365                      $thisfile_riff_WAVE_cart_0['out_cue']              =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64));
 366                      $thisfile_riff_WAVE_cart_0['start_date']           =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10));
 367                      $thisfile_riff_WAVE_cart_0['start_time']           =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 462,  8));
 368                      $thisfile_riff_WAVE_cart_0['end_date']             =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10));
 369                      $thisfile_riff_WAVE_cart_0['end_time']             =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 480,  8));
 370                      $thisfile_riff_WAVE_cart_0['producer_app_id']      =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64));
 371                      $thisfile_riff_WAVE_cart_0['producer_app_version'] =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64));
 372                      $thisfile_riff_WAVE_cart_0['user_defined_text']    =                         trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64));
 373                      $thisfile_riff_WAVE_cart_0['zero_db_reference']    = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680,  4), true);
 374                      for ($i = 0; $i < 8; $i++) {
 375                          $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] =                  substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8), 4);
 376                          $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));
 377                      }
 378                      $thisfile_riff_WAVE_cart_0['url']              =                 trim(substr($thisfile_riff_WAVE_cart_0['data'],  748, 1024));
 379                      $thisfile_riff_WAVE_cart_0['tag_text']         = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
 380                      $thisfile_riff['comments']['tag_text'][]       =                      substr($thisfile_riff_WAVE_cart_0['data'], 1772);
 381  
 382                      $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
 383                      $thisfile_riff['comments']['title'][]  = $thisfile_riff_WAVE_cart_0['title'];
 384                  }
 385  
 386                  if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) {
 387                      // SoundMiner metadata
 388  
 389                      // shortcuts
 390                      $thisfile_riff_WAVE_SNDM_0      = &$thisfile_riff_WAVE['SNDM'][0];
 391                      $thisfile_riff_WAVE_SNDM_0_data = &$thisfile_riff_WAVE_SNDM_0['data'];
 392                      $SNDM_startoffset = 0;
 393                      $SNDM_endoffset   = $thisfile_riff_WAVE_SNDM_0['size'];
 394  
 395                      while ($SNDM_startoffset < $SNDM_endoffset) {
 396                          $SNDM_thisTagOffset = 0;
 397                          $SNDM_thisTagSize      = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4));
 398                          $SNDM_thisTagOffset += 4;
 399                          $SNDM_thisTagKey       =                           substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4);
 400                          $SNDM_thisTagOffset += 4;
 401                          $SNDM_thisTagDataSize  = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
 402                          $SNDM_thisTagOffset += 2;
 403                          $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
 404                          $SNDM_thisTagOffset += 2;
 405                          $SNDM_thisTagDataText =                            substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize);
 406                          $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
 407  
 408                          if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) {
 409                              $this->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).')');
 410                              break;
 411                          } elseif ($SNDM_thisTagSize <= 0) {
 412                              $this->warning('RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')');
 413                              break;
 414                          }
 415                          $SNDM_startoffset += $SNDM_thisTagSize;
 416  
 417                          $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText;
 418                          if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) {
 419                              $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
 420                          } else {
 421                              $this->warning('RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')');
 422                          }
 423                      }
 424  
 425                      $tagmapping = array(
 426                          'tracktitle'=>'title',
 427                          'category'  =>'genre',
 428                          'cdtitle'   =>'album',
 429                      );
 430                      foreach ($tagmapping as $fromkey => $tokey) {
 431                          if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
 432                              $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey];
 433                          }
 434                      }
 435                  }
 436  
 437                  if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) {
 438                      // requires functions simplexml_load_string and get_object_vars
 439                      if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) {
 440                          $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML;
 441                          if (isset($parsedXML['SPEED']['MASTER_SPEED'])) {
 442                              @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']);
 443                              $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000);
 444                          }
 445                          if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) {
 446                              @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']);
 447                              $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000);
 448                          }
 449                          if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
 450                              $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
 451                              $timestamp_sample_rate = (is_array($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) ? max($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) : $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']); // XML could possibly contain more than one TIMESTAMP_SAMPLE_RATE tag, returning as array instead of integer [why? does it make sense? perhaps doesn't matter but getID3 needs to deal with it] - see https://github.com/JamesHeinrich/getID3/issues/105
 452                              $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate;
 453                              $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds']       / 3600);
 454                              $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600))      / 60);
 455                              $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60));
 456                              $f =       ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
 457                              $thisfile_riff_WAVE['iXML'][0]['timecode_string']       = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s,       $f);
 458                              $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d',   $h, $m, $s, round($f));
 459                              unset($samples_since_midnight, $timestamp_sample_rate, $h, $m, $s, $f);
 460                          }
 461                          unset($parsedXML);
 462                      }
 463                  }
 464  
 465                  if (isset($thisfile_riff_WAVE['guan'][0]['data'])) {
 466                      // shortcut
 467                      $thisfile_riff_WAVE_guan_0 = &$thisfile_riff_WAVE['guan'][0];
 468                      if (!empty($thisfile_riff_WAVE_guan_0['data']) && (substr($thisfile_riff_WAVE_guan_0['data'], 0, 14) == 'GUANO|Version:')) {
 469                          $thisfile_riff['guano'] = array();
 470                          foreach (explode("\n", $thisfile_riff_WAVE_guan_0['data']) as $line) {
 471                              if ($line) {
 472                                  @list($key, $value) = explode(':', $line, 2);
 473                                  if (substr($value, 0, 3) == '[{"') {
 474                                      if ($decoded = @json_decode($value, true)) {
 475                                          if (!empty($decoded) && (count($decoded) == 1)) {
 476                                              $value = $decoded[0];
 477                                          } else {
 478                                              $value = $decoded;
 479                                          }
 480                                      }
 481                                  }
 482                                  $thisfile_riff['guano'] = array_merge_recursive($thisfile_riff['guano'], getid3_lib::CreateDeepArray($key, '|', $value));
 483                              }
 484                          }
 485  
 486                          // https://www.wildlifeacoustics.com/SCHEMA/GUANO.html
 487                          foreach ($thisfile_riff['guano'] as $key => $value) {
 488                              switch ($key) {
 489                                  case 'Loc Position':
 490                                      if (preg_match('#^([\\+\\-]?[0-9]+\\.[0-9]+) ([\\+\\-]?[0-9]+\\.[0-9]+)$#', $value, $matches)) {
 491                                          list($dummy, $latitude, $longitude) = $matches;
 492                                          $thisfile_riff['comments']['gps_latitude'][0]  = floatval($latitude);
 493                                          $thisfile_riff['comments']['gps_longitude'][0] = floatval($longitude);
 494                                          $thisfile_riff['guano'][$key] = floatval($latitude).' '.floatval($longitude);
 495                                      }
 496                                      break;
 497                                  case 'Loc Elevation': // Elevation/altitude above mean sea level in meters
 498                                      $thisfile_riff['comments']['gps_altitude'][0] = floatval($value);
 499                                      $thisfile_riff['guano'][$key] = (float) $value;
 500                                      break;
 501                                  case 'Filter HP':        // High-pass filter frequency in kHz
 502                                  case 'Filter LP':        // Low-pass filter frequency in kHz
 503                                  case 'Humidity':         // Relative humidity as a percentage
 504                                  case 'Length':           // Recording length in seconds
 505                                  case 'Loc Accuracy':     // Estimated Position Error in meters
 506                                  case 'Temperature Ext':  // External temperature in degrees Celsius outside the recorder's housing
 507                                  case 'Temperature Int':  // Internal temperature in degrees Celsius inside the recorder's housing
 508                                      $thisfile_riff['guano'][$key] = (float) $value;
 509                                      break;
 510                                  case 'Samplerate':       // Recording sample rate, Hz
 511                                  case 'TE':               // Time-expansion factor. If not specified, then 1 (no time-expansion a.k.a. direct-recording) is assumed.
 512                                      $thisfile_riff['guano'][$key] = (int) $value;
 513                                      break;
 514                              }
 515                          }
 516  
 517                      } else {
 518                          $this->warning('RIFF.guan data not in expected format');
 519                      }
 520                  }
 521  
 522                  if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
 523                      $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
 524                      $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
 525                  }
 526  
 527                  if (!empty($info['wavpack'])) {
 528                      $thisfile_audio_dataformat = 'wavpack';
 529                      $thisfile_audio['bitrate_mode'] = 'vbr';
 530                      $thisfile_audio['encoder']      = 'WavPack v'.$info['wavpack']['version'];
 531  
 532                      // Reset to the way it was - RIFF parsing will have messed this up
 533                      $info['avdataend']        = $Original['avdataend'];
 534                      $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
 535  
 536                      $this->fseek($info['avdataoffset'] - 44);
 537                      $RIFFdata = $this->fread(44);
 538                      $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata,  4, 4)) +  8;
 539                      $OrignalRIFFdataSize   = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
 540  
 541                      if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
 542                          $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
 543                          $this->fseek($info['avdataend']);
 544                          $RIFFdata .= $this->fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
 545                      }
 546  
 547                      // move the data chunk after all other chunks (if any)
 548                      // so that the RIFF parser doesn't see EOF when trying
 549                      // to skip over the data chunk
 550                      $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
 551                      $getid3_riff = new getid3_riff($this->getid3);
 552                      $getid3_riff->ParseRIFFdata($RIFFdata);
 553                      unset($getid3_riff);
 554                  }
 555  
 556                  if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
 557                      switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
 558                          case 0x0001: // PCM
 559                              if (!empty($info['ac3'])) {
 560                                  // Dolby Digital WAV files masquerade as PCM-WAV, but they're not
 561                                  $thisfile_audio['wformattag']  = 0x2000;
 562                                  $thisfile_audio['codec']       = self::wFormatTagLookup($thisfile_audio['wformattag']);
 563                                  $thisfile_audio['lossless']    = false;
 564                                  $thisfile_audio['bitrate']     = $info['ac3']['bitrate'];
 565                                  $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate'];
 566                              }
 567                              if (!empty($info['dts'])) {
 568                                  // Dolby DTS files masquerade as PCM-WAV, but they're not
 569                                  $thisfile_audio['wformattag']  = 0x2001;
 570                                  $thisfile_audio['codec']       = self::wFormatTagLookup($thisfile_audio['wformattag']);
 571                                  $thisfile_audio['lossless']    = false;
 572                                  $thisfile_audio['bitrate']     = $info['dts']['bitrate'];
 573                                  $thisfile_audio['sample_rate'] = $info['dts']['sample_rate'];
 574                              }
 575                              break;
 576                          case 0x08AE: // ClearJump LiteWave
 577                              $thisfile_audio['bitrate_mode'] = 'vbr';
 578                              $thisfile_audio_dataformat   = 'litewave';
 579  
 580                              //typedef struct tagSLwFormat {
 581                              //  WORD    m_wCompFormat;     // low byte defines compression method, high byte is compression flags
 582                              //  DWORD   m_dwScale;         // scale factor for lossy compression
 583                              //  DWORD   m_dwBlockSize;     // number of samples in encoded blocks
 584                              //  WORD    m_wQuality;        // alias for the scale factor
 585                              //  WORD    m_wMarkDistance;   // distance between marks in bytes
 586                              //  WORD    m_wReserved;
 587                              //
 588                              //  //following paramters are ignored if CF_FILESRC is not set
 589                              //  DWORD   m_dwOrgSize;       // original file size in bytes
 590                              //  WORD    m_bFactExists;     // indicates if 'fact' chunk exists in the original file
 591                              //  DWORD   m_dwRiffChunkSize; // riff chunk size in the original file
 592                              //
 593                              //  PCMWAVEFORMAT m_OrgWf;     // original wave format
 594                              // }SLwFormat, *PSLwFormat;
 595  
 596                              // shortcut
 597                              $thisfile_riff['litewave']['raw'] = array();
 598                              $riff_litewave     = &$thisfile_riff['litewave'];
 599                              $riff_litewave_raw = &$riff_litewave['raw'];
 600  
 601                              $flags = array(
 602                                  'compression_method' => 1,
 603                                  'compression_flags'  => 1,
 604                                  'm_dwScale'          => 4,
 605                                  'm_dwBlockSize'      => 4,
 606                                  'm_wQuality'         => 2,
 607                                  'm_wMarkDistance'    => 2,
 608                                  'm_wReserved'        => 2,
 609                                  'm_dwOrgSize'        => 4,
 610                                  'm_bFactExists'      => 2,
 611                                  'm_dwRiffChunkSize'  => 4,
 612                              );
 613                              $litewave_offset = 18;
 614                              foreach ($flags as $flag => $length) {
 615                                  $riff_litewave_raw[$flag] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], $litewave_offset, $length));
 616                                  $litewave_offset += $length;
 617                              }
 618  
 619                              //$riff_litewave['quality_factor'] = intval(round((2000 - $riff_litewave_raw['m_dwScale']) / 20));
 620                              $riff_litewave['quality_factor'] = $riff_litewave_raw['m_wQuality'];
 621  
 622                              $riff_litewave['flags']['raw_source']    = ($riff_litewave_raw['compression_flags'] & 0x01) ? false : true;
 623                              $riff_litewave['flags']['vbr_blocksize'] = ($riff_litewave_raw['compression_flags'] & 0x02) ? false : true;
 624                              $riff_litewave['flags']['seekpoints']    =        (bool) ($riff_litewave_raw['compression_flags'] & 0x04);
 625  
 626                              $thisfile_audio['lossless']        = (($riff_litewave_raw['m_wQuality'] == 100) ? true : false);
 627                              $thisfile_audio['encoder_options'] = '-q'.$riff_litewave['quality_factor'];
 628                              break;
 629  
 630                          default:
 631                              break;
 632                      }
 633                  }
 634                  if ($info['avdataend'] > $info['filesize']) {
 635                      switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') {
 636                          case 'wavpack': // WavPack
 637                          case 'lpac':    // LPAC
 638                          case 'ofr':     // OptimFROG
 639                          case 'ofs':     // OptimFROG DualStream
 640                              // lossless compressed audio formats that keep original RIFF headers - skip warning
 641                              break;
 642  
 643                          case 'litewave':
 644                              if (($info['avdataend'] - $info['filesize']) == 1) {
 645                                  // LiteWave appears to incorrectly *not* pad actual output file
 646                                  // to nearest WORD boundary so may appear to be short by one
 647                                  // byte, in which case - skip warning
 648                              } else {
 649                                  // Short by more than one byte, throw warning
 650                                  $this->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)');
 651                                  $info['avdataend'] = $info['filesize'];
 652                              }
 653                              break;
 654  
 655                          default:
 656                              if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) {
 657                                  // output file appears to be incorrectly *not* padded to nearest WORD boundary
 658                                  // Output less severe warning
 659                                  $this->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)');
 660                                  $info['avdataend'] = $info['filesize'];
 661                              } else {
 662                                  // Short by more than one byte, throw warning
 663                                  $this->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)');
 664                                  $info['avdataend'] = $info['filesize'];
 665                              }
 666                              break;
 667                      }
 668                  }
 669                  if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
 670                      if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
 671                          $info['avdataend']--;
 672                          $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
 673                      }
 674                  }
 675                  if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) {
 676                      unset($thisfile_audio['bits_per_sample']);
 677                      if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) {
 678                          $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
 679                      }
 680                  }
 681                  break;
 682  
 683              // http://en.wikipedia.org/wiki/Audio_Video_Interleave
 684              case 'AVI ':
 685                  $info['fileformat'] = 'avi';
 686                  $info['mime_type']  = 'video/avi';
 687  
 688                  $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
 689                  $thisfile_video['dataformat']   = 'avi';
 690  
 691                  $thisfile_riff_video_current = array();
 692  
 693                  if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
 694                      $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
 695                      if (isset($thisfile_riff['AVIX'])) {
 696                          $info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size'];
 697                      } else {
 698                          $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size'];
 699                      }
 700                      if ($info['avdataend'] > $info['filesize']) {
 701                          $this->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)');
 702                          $info['avdataend'] = $info['filesize'];
 703                      }
 704                  }
 705  
 706                  if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) {
 707                      //$bIndexType = array(
 708                      //    0x00 => 'AVI_INDEX_OF_INDEXES',
 709                      //    0x01 => 'AVI_INDEX_OF_CHUNKS',
 710                      //    0x80 => 'AVI_INDEX_IS_DATA',
 711                      //);
 712                      //$bIndexSubtype = array(
 713                      //    0x01 => array(
 714                      //        0x01 => 'AVI_INDEX_2FIELD',
 715                      //    ),
 716                      //);
 717                      foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) {
 718                          $ahsisd = &$thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data'];
 719  
 720                          $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($ahsisd,  0, 2));
 721                          $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']  = $this->EitherEndian2Int(substr($ahsisd,  2, 1));
 722                          $thisfile_riff_raw['indx'][$streamnumber]['bIndexType']     = $this->EitherEndian2Int(substr($ahsisd,  3, 1));
 723                          $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse']  = $this->EitherEndian2Int(substr($ahsisd,  4, 4));
 724                          $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId']      =                         substr($ahsisd,  8, 4);
 725                          $thisfile_riff_raw['indx'][$streamnumber]['dwReserved']     = $this->EitherEndian2Int(substr($ahsisd, 12, 4));
 726  
 727                          //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name']    =    $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']];
 728                          //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']];
 729  
 730                          unset($ahsisd);
 731                      }
 732                  }
 733                  if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
 734                      $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
 735  
 736                      // shortcut
 737                      $thisfile_riff_raw['avih'] = array();
 738                      $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih'];
 739  
 740                      $thisfile_riff_raw_avih['dwMicroSecPerFrame']    = $this->EitherEndian2Int(substr($avihData,  0, 4)); // frame display rate (or 0L)
 741                      if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
 742                          $this->error('Corrupt RIFF file: avih.dwMicroSecPerFrame == zero');
 743                          return false;
 744                      }
 745  
 746                      $flags = array(
 747                          'dwMaxBytesPerSec',       // max. transfer rate
 748                          'dwPaddingGranularity',   // pad to multiples of this size; normally 2K.
 749                          'dwFlags',                // the ever-present flags
 750                          'dwTotalFrames',          // # frames in file
 751                          'dwInitialFrames',        //
 752                          'dwStreams',              //
 753                          'dwSuggestedBufferSize',  //
 754                          'dwWidth',                //
 755                          'dwHeight',               //
 756                          'dwScale',                //
 757                          'dwRate',                 //
 758                          'dwStart',                //
 759                          'dwLength',               //
 760                      );
 761                      $avih_offset = 4;
 762                      foreach ($flags as $flag) {
 763                          $thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4));
 764                          $avih_offset += 4;
 765                      }
 766  
 767                      $flags = array(
 768                          'hasindex'     => 0x00000010,
 769                          'mustuseindex' => 0x00000020,
 770                          'interleaved'  => 0x00000100,
 771                          'trustcktype'  => 0x00000800,
 772                          'capturedfile' => 0x00010000,
 773                          'copyrighted'  => 0x00020010,
 774                      );
 775                      foreach ($flags as $flag => $value) {
 776                          $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
 777                      }
 778  
 779                      // shortcut
 780                      $thisfile_riff_video[$streamindex] = array();
 781                      /** @var array $thisfile_riff_video_current */
 782                      $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
 783  
 784                      if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
 785                          $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
 786                          $thisfile_video['resolution_x']             = $thisfile_riff_video_current['frame_width'];
 787                      }
 788                      if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
 789                          $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
 790                          $thisfile_video['resolution_y']              = $thisfile_riff_video_current['frame_height'];
 791                      }
 792                      if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
 793                          $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
 794                          $thisfile_video['total_frames']              = $thisfile_riff_video_current['total_frames'];
 795                      }
 796  
 797                      $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
 798                      $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate'];
 799                  }
 800                  if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
 801                      if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
 802                          $thisfile_riff_raw_strf_strhfccType_streamindex = null;
 803                          for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
 804                              if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
 805                                  $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
 806                                  $strhfccType = substr($strhData,  0, 4);
 807  
 808                                  if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
 809                                      $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
 810  
 811                                      // shortcut
 812                                      $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
 813  
 814                                      switch ($strhfccType) {
 815                                          case 'auds':
 816                                              $thisfile_audio['bitrate_mode'] = 'cbr';
 817                                              $thisfile_audio_dataformat      = 'wav';
 818                                              if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) {
 819                                                  $streamindex = count($thisfile_riff_audio);
 820                                              }
 821  
 822                                              $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($strfData);
 823                                              $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
 824  
 825                                              // shortcut
 826                                              $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
 827                                              $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex];
 828  
 829                                              if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
 830                                                  unset($thisfile_audio_streams_currentstream['bits_per_sample']);
 831                                              }
 832                                              $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
 833                                              unset($thisfile_audio_streams_currentstream['raw']);
 834  
 835                                              // shortcut
 836                                              $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
 837  
 838                                              unset($thisfile_riff_audio[$streamindex]['raw']);
 839                                              $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
 840  
 841                                              $thisfile_audio['lossless'] = false;
 842                                              switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
 843                                                  case 0x0001:  // PCM
 844                                                      $thisfile_audio_dataformat  = 'wav';
 845                                                      $thisfile_audio['lossless'] = true;
 846                                                      break;
 847  
 848                                                  case 0x0050: // MPEG Layer 2 or Layer 1
 849                                                      $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2
 850                                                      break;
 851  
 852                                                  case 0x0055: // MPEG Layer 3
 853                                                      $thisfile_audio_dataformat = 'mp3';
 854                                                      break;
 855  
 856                                                  case 0x00FF: // AAC
 857                                                      $thisfile_audio_dataformat = 'aac';
 858                                                      break;
 859  
 860                                                  case 0x0161: // Windows Media v7 / v8 / v9
 861                                                  case 0x0162: // Windows Media Professional v9
 862                                                  case 0x0163: // Windows Media Lossess v9
 863                                                      $thisfile_audio_dataformat = 'wma';
 864                                                      break;
 865  
 866                                                  case 0x2000: // AC-3
 867                                                      $thisfile_audio_dataformat = 'ac3';
 868                                                      break;
 869  
 870                                                  case 0x2001: // DTS
 871                                                      $thisfile_audio_dataformat = 'dts';
 872                                                      break;
 873  
 874                                                  default:
 875                                                      $thisfile_audio_dataformat = 'wav';
 876                                                      break;
 877                                              }
 878                                              $thisfile_audio_streams_currentstream['dataformat']   = $thisfile_audio_dataformat;
 879                                              $thisfile_audio_streams_currentstream['lossless']     = $thisfile_audio['lossless'];
 880                                              $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
 881                                              break;
 882  
 883  
 884                                          case 'iavs':
 885                                          case 'vids':
 886                                              // shortcut
 887                                              $thisfile_riff_raw['strh'][$i]                  = array();
 888                                              $thisfile_riff_raw_strh_current                 = &$thisfile_riff_raw['strh'][$i];
 889  
 890                                              $thisfile_riff_raw_strh_current['fccType']               =                         substr($strhData,  0, 4);  // same as $strhfccType;
 891                                              $thisfile_riff_raw_strh_current['fccHandler']            =                         substr($strhData,  4, 4);
 892                                              $thisfile_riff_raw_strh_current['dwFlags']               = $this->EitherEndian2Int(substr($strhData,  8, 4)); // Contains AVITF_* flags
 893                                              $thisfile_riff_raw_strh_current['wPriority']             = $this->EitherEndian2Int(substr($strhData, 12, 2));
 894                                              $thisfile_riff_raw_strh_current['wLanguage']             = $this->EitherEndian2Int(substr($strhData, 14, 2));
 895                                              $thisfile_riff_raw_strh_current['dwInitialFrames']       = $this->EitherEndian2Int(substr($strhData, 16, 4));
 896                                              $thisfile_riff_raw_strh_current['dwScale']               = $this->EitherEndian2Int(substr($strhData, 20, 4));
 897                                              $thisfile_riff_raw_strh_current['dwRate']                = $this->EitherEndian2Int(substr($strhData, 24, 4));
 898                                              $thisfile_riff_raw_strh_current['dwStart']               = $this->EitherEndian2Int(substr($strhData, 28, 4));
 899                                              $thisfile_riff_raw_strh_current['dwLength']              = $this->EitherEndian2Int(substr($strhData, 32, 4));
 900                                              $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4));
 901                                              $thisfile_riff_raw_strh_current['dwQuality']             = $this->EitherEndian2Int(substr($strhData, 40, 4));
 902                                              $thisfile_riff_raw_strh_current['dwSampleSize']          = $this->EitherEndian2Int(substr($strhData, 44, 4));
 903                                              $thisfile_riff_raw_strh_current['rcFrame']               = $this->EitherEndian2Int(substr($strhData, 48, 4));
 904  
 905                                              $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strh_current['fccHandler']);
 906                                              $thisfile_video['fourcc']             = $thisfile_riff_raw_strh_current['fccHandler'];
 907                                              if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
 908                                                  $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
 909                                                  $thisfile_video['fourcc']             = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
 910                                              }
 911                                              $thisfile_video['codec']              = $thisfile_riff_video_current['codec'];
 912                                              $thisfile_video['pixel_aspect_ratio'] = (float) 1;
 913                                              switch ($thisfile_riff_raw_strh_current['fccHandler']) {
 914                                                  case 'HFYU': // Huffman Lossless Codec
 915                                                  case 'IRAW': // Intel YUV Uncompressed
 916                                                  case 'YUY2': // Uncompressed YUV 4:2:2
 917                                                      $thisfile_video['lossless'] = true;
 918                                                      break;
 919  
 920                                                  default:
 921                                                      $thisfile_video['lossless'] = false;
 922                                                      break;
 923                                              }
 924  
 925                                              switch ($strhfccType) {
 926                                                  case 'vids':
 927                                                      $thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($this->container == 'riff'));
 928                                                      $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
 929  
 930                                                      if ($thisfile_riff_video_current['codec'] == 'DV') {
 931                                                          $thisfile_riff_video_current['dv_type'] = 2;
 932                                                      }
 933                                                      break;
 934  
 935                                                  case 'iavs':
 936                                                      $thisfile_riff_video_current['dv_type'] = 1;
 937                                                      break;
 938                                              }
 939                                              break;
 940  
 941                                          default:
 942                                              $this->warning('Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"');
 943                                              break;
 944  
 945                                      }
 946                                  }
 947                              }
 948  
 949                              if (isset($thisfile_riff_raw_strf_strhfccType_streamindex) && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
 950  
 951                                  $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
 952                                  if (self::fourccLookup($thisfile_video['fourcc'])) {
 953                                      $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_video['fourcc']);
 954                                      $thisfile_video['codec']              = $thisfile_riff_video_current['codec'];
 955                                  }
 956  
 957                                  switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) {
 958                                      case 'HFYU': // Huffman Lossless Codec
 959                                      case 'IRAW': // Intel YUV Uncompressed
 960                                      case 'YUY2': // Uncompressed YUV 4:2:2
 961                                          $thisfile_video['lossless']        = true;
 962                                          //$thisfile_video['bits_per_sample'] = 24;
 963                                          break;
 964  
 965                                      default:
 966                                          $thisfile_video['lossless']        = false;
 967                                          //$thisfile_video['bits_per_sample'] = 24;
 968                                          break;
 969                                  }
 970  
 971                              }
 972                          }
 973                      }
 974                  }
 975                  break;
 976  
 977  
 978              case 'AMV ':
 979                  $info['fileformat'] = 'amv';
 980                  $info['mime_type']  = 'video/amv';
 981  
 982                  $thisfile_video['bitrate_mode']    = 'vbr'; // it's MJPEG, presumably contant-quality encoding, thereby VBR
 983                  $thisfile_video['dataformat']      = 'mjpeg';
 984                  $thisfile_video['codec']           = 'mjpeg';
 985                  $thisfile_video['lossless']        = false;
 986                  $thisfile_video['bits_per_sample'] = 24;
 987  
 988                  $thisfile_audio['dataformat']   = 'adpcm';
 989                  $thisfile_audio['lossless']     = false;
 990                  break;
 991  
 992  
 993              // http://en.wikipedia.org/wiki/CD-DA
 994              case 'CDDA':
 995                  $info['fileformat'] = 'cda';
 996                  unset($info['mime_type']);
 997  
 998                  $thisfile_audio_dataformat      = 'cda';
 999  
1000                  $info['avdataoffset'] = 44;
1001  
1002                  if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
1003                      // shortcut
1004                      $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0];
1005  
1006                      $thisfile_riff_CDDA_fmt_0['unknown1']           = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'],  0, 2));
1007                      $thisfile_riff_CDDA_fmt_0['track_num']          = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'],  2, 2));
1008                      $thisfile_riff_CDDA_fmt_0['disc_id']            = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'],  4, 4));
1009                      $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'],  8, 4));
1010                      $thisfile_riff_CDDA_fmt_0['playtime_frames']    = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4));
1011                      $thisfile_riff_CDDA_fmt_0['unknown6']           = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4));
1012                      $thisfile_riff_CDDA_fmt_0['unknown7']           = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4));
1013  
1014                      $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
1015                      $thisfile_riff_CDDA_fmt_0['playtime_seconds']     = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
1016                      $info['comments']['track_number']         = $thisfile_riff_CDDA_fmt_0['track_num'];
1017                      $info['playtime_seconds']                 = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
1018  
1019                      // hardcoded data for CD-audio
1020                      $thisfile_audio['lossless']        = true;
1021                      $thisfile_audio['sample_rate']     = 44100;
1022                      $thisfile_audio['channels']        = 2;
1023                      $thisfile_audio['bits_per_sample'] = 16;
1024                      $thisfile_audio['bitrate']         = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
1025                      $thisfile_audio['bitrate_mode']    = 'cbr';
1026                  }
1027                  break;
1028  
1029              // http://en.wikipedia.org/wiki/AIFF
1030              case 'AIFF':
1031              case 'AIFC':
1032                  $info['fileformat'] = 'aiff';
1033                  $info['mime_type']  = 'audio/x-aiff';
1034  
1035                  $thisfile_audio['bitrate_mode'] = 'cbr';
1036                  $thisfile_audio_dataformat      = 'aiff';
1037                  $thisfile_audio['lossless']     = true;
1038  
1039                  if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
1040                      $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
1041                      $info['avdataend']    = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
1042                      if ($info['avdataend'] > $info['filesize']) {
1043                          if (($info['avdataend'] == ($info['filesize'] + 1)) && (($info['filesize'] % 2) == 1)) {
1044                              // structures rounded to 2-byte boundary, but dumb encoders
1045                              // forget to pad end of file to make this actually work
1046                          } else {
1047                              $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found');
1048                          }
1049                          $info['avdataend'] = $info['filesize'];
1050                      }
1051                  }
1052  
1053                  if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
1054  
1055                      // shortcut
1056                      $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
1057  
1058                      $thisfile_riff_audio['channels']         =         getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data,  0,  2), true);
1059                      $thisfile_riff_audio['total_samples']    =         getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data,  2,  4), false);
1060                      $thisfile_riff_audio['bits_per_sample']  =         getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data,  6,  2), true);
1061                      $thisfile_riff_audio['sample_rate']      = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data,  8, 10));
1062  
1063                      if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) {
1064                          $thisfile_riff_audio['codec_fourcc'] =                                   substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18,  4);
1065                          $CodecNameSize                       =         getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22,  1), false);
1066                          $thisfile_riff_audio['codec_name']   =                                   substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23,  $CodecNameSize);
1067                          switch ($thisfile_riff_audio['codec_name']) {
1068                              case 'NONE':
1069                                  $thisfile_audio['codec']    = 'Pulse Code Modulation (PCM)';
1070                                  $thisfile_audio['lossless'] = true;
1071                                  break;
1072  
1073                              case '':
1074                                  switch ($thisfile_riff_audio['codec_fourcc']) {
1075                                      // http://developer.apple.com/qa/snd/snd07.html
1076                                      case 'sowt':
1077                                          $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
1078                                          $thisfile_audio['lossless'] = true;
1079                                          break;
1080  
1081                                      case 'twos':
1082                                          $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
1083                                          $thisfile_audio['lossless'] = true;
1084                                          break;
1085  
1086                                      default:
1087                                          break;
1088                                  }
1089                                  break;
1090  
1091                              default:
1092                                  $thisfile_audio['codec']    = $thisfile_riff_audio['codec_name'];
1093                                  $thisfile_audio['lossless'] = false;
1094                                  break;
1095                          }
1096                      }
1097  
1098                      $thisfile_audio['channels']        = $thisfile_riff_audio['channels'];
1099                      if ($thisfile_riff_audio['bits_per_sample'] > 0) {
1100                          $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample'];
1101                      }
1102                      $thisfile_audio['sample_rate']     = $thisfile_riff_audio['sample_rate'];
1103                      if ($thisfile_audio['sample_rate'] == 0) {
1104                          $this->error('Corrupted AIFF file: sample_rate == zero');
1105                          return false;
1106                      }
1107                      $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
1108                  }
1109  
1110                  if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
1111                      $offset = 0;
1112                      $CommentCount                                   = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
1113                      $offset += 2;
1114                      for ($i = 0; $i < $CommentCount; $i++) {
1115                          $info['comments_raw'][$i]['timestamp']      = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false);
1116                          $offset += 4;
1117                          $info['comments_raw'][$i]['marker_id']      = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
1118                          $offset += 2;
1119                          $CommentLength                              = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
1120                          $offset += 2;
1121                          $info['comments_raw'][$i]['comment']        =                           substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
1122                          $offset += $CommentLength;
1123  
1124                          $info['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($info['comments_raw'][$i]['timestamp']);
1125                          $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment'];
1126                      }
1127                  }
1128  
1129                  $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
1130                  foreach ($CommentsChunkNames as $key => $value) {
1131                      if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
1132                          $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
1133                      }
1134                  }
1135  /*
1136                  if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
1137                      getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
1138                      $getid3_temp = new getID3();
1139                      $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
1140                      $getid3_id3v2 = new getid3_id3v2($getid3_temp);
1141                      $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
1142                      if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
1143                          $info['id3v2'] = $getid3_temp->info['id3v2'];
1144                      }
1145                      unset($getid3_temp, $getid3_id3v2);
1146                  }
1147  */
1148                  break;
1149  
1150              // http://en.wikipedia.org/wiki/8SVX
1151              case '8SVX':
1152                  $info['fileformat'] = '8svx';
1153                  $info['mime_type']  = 'audio/8svx';
1154  
1155                  $thisfile_audio['bitrate_mode']    = 'cbr';
1156                  $thisfile_audio_dataformat         = '8svx';
1157                  $thisfile_audio['bits_per_sample'] = 8;
1158                  $thisfile_audio['channels']        = 1; // overridden below, if need be
1159                  $ActualBitsPerSample               = 0;
1160  
1161                  if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
1162                      $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
1163                      $info['avdataend']    = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
1164                      if ($info['avdataend'] > $info['filesize']) {
1165                          $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found');
1166                      }
1167                  }
1168  
1169                  if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
1170                      // shortcut
1171                      $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0];
1172  
1173                      $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples']  =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'],  0, 4));
1174                      $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples']   =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'],  4, 4));
1175                      $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'],  8, 4));
1176                      $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec']     =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2));
1177                      $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave']          =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1));
1178                      $thisfile_riff_RIFFsubtype_VHDR_0['sCompression']      =   getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1));
1179                      $thisfile_riff_RIFFsubtype_VHDR_0['Volume']            = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4));
1180  
1181                      $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
1182  
1183                      switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
1184                          case 0:
1185                              $thisfile_audio['codec']    = 'Pulse Code Modulation (PCM)';
1186                              $thisfile_audio['lossless'] = true;
1187                              $ActualBitsPerSample        = 8;
1188                              break;
1189  
1190                          case 1:
1191                              $thisfile_audio['codec']    = 'Fibonacci-delta encoding';
1192                              $thisfile_audio['lossless'] = false;
1193                              $ActualBitsPerSample        = 4;
1194                              break;
1195  
1196                          default:
1197                              $this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.$thisfile_riff_RIFFsubtype_VHDR_0['sCompression'].'"');
1198                              break;
1199                      }
1200                  }
1201  
1202                  if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) {
1203                      $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4));
1204                      switch ($ChannelsIndex) {
1205                          case 6: // Stereo
1206                              $thisfile_audio['channels'] = 2;
1207                              break;
1208  
1209                          case 2: // Left channel only
1210                          case 4: // Right channel only
1211                              $thisfile_audio['channels'] = 1;
1212                              break;
1213  
1214                          default:
1215                              $this->warning('Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"');
1216                              break;
1217                      }
1218  
1219                  }
1220  
1221                  $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
1222                  foreach ($CommentsChunkNames as $key => $value) {
1223                      if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
1224                          $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
1225                      }
1226                  }
1227  
1228                  $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels'];
1229                  if (!empty($thisfile_audio['bitrate'])) {
1230                      $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8);
1231                  }
1232                  break;
1233  
1234              case 'CDXA':
1235                  $info['fileformat'] = 'vcd'; // Asume Video CD
1236                  $info['mime_type']  = 'video/mpeg';
1237  
1238                  if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
1239                      getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
1240  
1241                      $getid3_temp = new getID3();
1242                      $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
1243                      $getid3_mpeg = new getid3_mpeg($getid3_temp);
1244                      $getid3_mpeg->Analyze();
1245                      if (empty($getid3_temp->info['error'])) {
1246                          $info['audio']   = $getid3_temp->info['audio'];
1247                          $info['video']   = $getid3_temp->info['video'];
1248                          $info['mpeg']    = $getid3_temp->info['mpeg'];
1249                          $info['warning'] = $getid3_temp->info['warning'];
1250                      }
1251                      unset($getid3_temp, $getid3_mpeg);
1252                  }
1253                  break;
1254  
1255              case 'WEBP':
1256                  // https://developers.google.com/speed/webp/docs/riff_container
1257                  // https://tools.ietf.org/html/rfc6386
1258                  // https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt
1259                  $info['fileformat'] = 'webp';
1260                  $info['mime_type']  = 'image/webp';
1261  
1262                  if (!empty($thisfile_riff['WEBP']['VP8 '][0]['size'])) {
1263                      $old_offset = $this->ftell();
1264                      $this->fseek($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8); // 4 bytes "VP8 " + 4 bytes chunk size
1265                      $WEBP_VP8_header = $this->fread(10);
1266                      $this->fseek($old_offset);
1267                      if (substr($WEBP_VP8_header, 3, 3) == "\x9D\x01\x2A") {
1268                          $thisfile_riff['WEBP']['VP8 '][0]['keyframe']   = !(getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x800000);
1269                          $thisfile_riff['WEBP']['VP8 '][0]['version']    =  (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x700000) >> 20;
1270                          $thisfile_riff['WEBP']['VP8 '][0]['show_frame'] =  (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x080000);
1271                          $thisfile_riff['WEBP']['VP8 '][0]['data_bytes'] =  (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x07FFFF) >>  0;
1272  
1273                          $thisfile_riff['WEBP']['VP8 '][0]['scale_x']    =  (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0xC000) >> 14;
1274                          $thisfile_riff['WEBP']['VP8 '][0]['width']      =  (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0x3FFF);
1275                          $thisfile_riff['WEBP']['VP8 '][0]['scale_y']    =  (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0xC000) >> 14;
1276                          $thisfile_riff['WEBP']['VP8 '][0]['height']     =  (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0x3FFF);
1277  
1278                          $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8 '][0]['width'];
1279                          $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8 '][0]['height'];
1280                      } else {
1281                          $this->error('Expecting 9D 01 2A at offset '.($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8 + 3).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8_header, 3, 3)).'"');
1282                      }
1283  
1284                  }
1285                  if (!empty($thisfile_riff['WEBP']['VP8L'][0]['size'])) {
1286                      $old_offset = $this->ftell();
1287                      $this->fseek($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8); // 4 bytes "VP8L" + 4 bytes chunk size
1288                      $WEBP_VP8L_header = $this->fread(10);
1289                      $this->fseek($old_offset);
1290                      if (substr($WEBP_VP8L_header, 0, 1) == "\x2F") {
1291                          $width_height_flags = getid3_lib::LittleEndian2Bin(substr($WEBP_VP8L_header, 1, 4));
1292                          $thisfile_riff['WEBP']['VP8L'][0]['width']         =        bindec(substr($width_height_flags, 18, 14)) + 1;
1293                          $thisfile_riff['WEBP']['VP8L'][0]['height']        =        bindec(substr($width_height_flags,  4, 14)) + 1;
1294                          $thisfile_riff['WEBP']['VP8L'][0]['alpha_is_used'] = (bool) bindec(substr($width_height_flags,  3,  1));
1295                          $thisfile_riff['WEBP']['VP8L'][0]['version']       =        bindec(substr($width_height_flags,  0,  3));
1296  
1297                          $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8L'][0]['width'];
1298                          $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8L'][0]['height'];
1299                      } else {
1300                          $this->error('Expecting 2F at offset '.($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8L_header, 0, 1)).'"');
1301                      }
1302  
1303                  }
1304                  break;
1305  
1306              default:
1307                  $this->error('Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA|WEBP), found "'.$RIFFsubtype.'" instead');
1308                  //unset($info['fileformat']);
1309          }
1310  
1311          switch ($RIFFsubtype) {
1312              case 'WAVE':
1313              case 'AIFF':
1314              case 'AIFC':
1315                  $ID3v2_key_good = 'id3 ';
1316                  $ID3v2_keys_bad = array('ID3 ', 'tag ');
1317                  foreach ($ID3v2_keys_bad as $ID3v2_key_bad) {
1318                      if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) {
1319                          $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad];
1320                          $this->warning('mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"');
1321                      }
1322                  }
1323  
1324                  if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) {
1325                      getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
1326  
1327                      $getid3_temp = new getID3();
1328                      $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
1329                      $getid3_id3v2 = new getid3_id3v2($getid3_temp);
1330                      $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
1331                      if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
1332                          $info['id3v2'] = $getid3_temp->info['id3v2'];
1333                      }
1334                      unset($getid3_temp, $getid3_id3v2);
1335                  }
1336                  break;
1337          }
1338  
1339          if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) {
1340              $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4));
1341          }
1342          if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
1343              self::parseComments($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
1344          }
1345          if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) {
1346              self::parseComments($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']);
1347          }
1348  
1349          if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) {
1350              $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version'];
1351          }
1352  
1353          if (!isset($info['playtime_seconds'])) {
1354              $info['playtime_seconds'] = 0;
1355          }
1356          if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
1357              // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
1358              $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
1359          } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
1360              $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
1361          }
1362  
1363          if ($info['playtime_seconds'] > 0) {
1364              if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
1365  
1366                  if (!isset($info['bitrate'])) {
1367                      $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1368                  }
1369  
1370              } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
1371  
1372                  if (!isset($thisfile_audio['bitrate'])) {
1373                      $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1374                  }
1375  
1376              } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
1377  
1378                  if (!isset($thisfile_video['bitrate'])) {
1379                      $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1380                  }
1381  
1382              }
1383          }
1384  
1385  
1386          if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) {
1387  
1388              $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
1389              $thisfile_audio['bitrate'] = 0;
1390              $thisfile_video['bitrate'] = $info['bitrate'];
1391              foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) {
1392                  $thisfile_video['bitrate'] -= $audioinfoarray['bitrate'];
1393                  $thisfile_audio['bitrate'] += $audioinfoarray['bitrate'];
1394              }
1395              if ($thisfile_video['bitrate'] <= 0) {
1396                  unset($thisfile_video['bitrate']);
1397              }
1398              if ($thisfile_audio['bitrate'] <= 0) {
1399                  unset($thisfile_audio['bitrate']);
1400              }
1401          }
1402  
1403          if (isset($info['mpeg']['audio'])) {
1404              $thisfile_audio_dataformat      = 'mp'.$info['mpeg']['audio']['layer'];
1405              $thisfile_audio['sample_rate']  = $info['mpeg']['audio']['sample_rate'];
1406              $thisfile_audio['channels']     = $info['mpeg']['audio']['channels'];
1407              $thisfile_audio['bitrate']      = $info['mpeg']['audio']['bitrate'];
1408              $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1409              if (!empty($info['mpeg']['audio']['codec'])) {
1410                  $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'].' '.$thisfile_audio['codec'];
1411              }
1412              if (!empty($thisfile_audio['streams'])) {
1413                  foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) {
1414                      if ($streamdata['dataformat'] == $thisfile_audio_dataformat) {
1415                          $thisfile_audio['streams'][$streamnumber]['sample_rate']  = $thisfile_audio['sample_rate'];
1416                          $thisfile_audio['streams'][$streamnumber]['channels']     = $thisfile_audio['channels'];
1417                          $thisfile_audio['streams'][$streamnumber]['bitrate']      = $thisfile_audio['bitrate'];
1418                          $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
1419                          $thisfile_audio['streams'][$streamnumber]['codec']        = $thisfile_audio['codec'];
1420                      }
1421                  }
1422              }
1423              $getid3_mp3 = new getid3_mp3($this->getid3);
1424              $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions();
1425              unset($getid3_mp3);
1426          }
1427  
1428  
1429          if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) {
1430              switch ($thisfile_audio_dataformat) {
1431                  case 'ac3':
1432                      // ignore bits_per_sample
1433                      break;
1434  
1435                  default:
1436                      $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
1437                      break;
1438              }
1439          }
1440  
1441  
1442          if (empty($thisfile_riff_raw)) {
1443              unset($thisfile_riff['raw']);
1444          }
1445          if (empty($thisfile_riff_audio)) {
1446              unset($thisfile_riff['audio']);
1447          }
1448          if (empty($thisfile_riff_video)) {
1449              unset($thisfile_riff['video']);
1450          }
1451  
1452          return true;
1453      }
1454  
1455      /**
1456       * @param int $startoffset
1457       * @param int $maxoffset
1458       *
1459       * @return array|false
1460       *
1461       * @throws Exception
1462       * @throws getid3_exception
1463       */
1464  	public function ParseRIFFAMV($startoffset, $maxoffset) {
1465          // 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
1466  
1467          // https://code.google.com/p/amv-codec-tools/wiki/AmvDocumentation
1468          //typedef struct _amvmainheader {
1469          //FOURCC fcc; // 'amvh'
1470          //DWORD cb;
1471          //DWORD dwMicroSecPerFrame;
1472          //BYTE reserve[28];
1473          //DWORD dwWidth;
1474          //DWORD dwHeight;
1475          //DWORD dwSpeed;
1476          //DWORD reserve0;
1477          //DWORD reserve1;
1478          //BYTE bTimeSec;
1479          //BYTE bTimeMin;
1480          //WORD wTimeHour;
1481          //} AMVMAINHEADER;
1482  
1483          $info = &$this->getid3->info;
1484          $RIFFchunk = false;
1485  
1486          try {
1487  
1488              $this->fseek($startoffset);
1489              $maxoffset = min($maxoffset, $info['avdataend']);
1490              $AMVheader = $this->fread(284);
1491              if (substr($AMVheader,   0,  8) != 'hdrlamvh') {
1492                  throw new Exception('expecting "hdrlamv" at offset '.($startoffset +   0).', found "'.substr($AMVheader,   0, 8).'"');
1493              }
1494              if (substr($AMVheader,   8,  4) != "\x38\x00\x00\x00") { // "amvh" chunk size, hardcoded to 0x38 = 56 bytes
1495                  throw new Exception('expecting "0x38000000" at offset '.($startoffset +   8).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader,   8, 4)).'"');
1496              }
1497              $RIFFchunk = array();
1498              $RIFFchunk['amvh']['us_per_frame']   = getid3_lib::LittleEndian2Int(substr($AMVheader,  12,  4));
1499              $RIFFchunk['amvh']['reserved28']     =                              substr($AMVheader,  16, 28);  // null? reserved?
1500              $RIFFchunk['amvh']['resolution_x']   = getid3_lib::LittleEndian2Int(substr($AMVheader,  44,  4));
1501              $RIFFchunk['amvh']['resolution_y']   = getid3_lib::LittleEndian2Int(substr($AMVheader,  48,  4));
1502              $RIFFchunk['amvh']['frame_rate_int'] = getid3_lib::LittleEndian2Int(substr($AMVheader,  52,  4));
1503              $RIFFchunk['amvh']['reserved0']      = getid3_lib::LittleEndian2Int(substr($AMVheader,  56,  4)); // 1? reserved?
1504              $RIFFchunk['amvh']['reserved1']      = getid3_lib::LittleEndian2Int(substr($AMVheader,  60,  4)); // 0? reserved?
1505              $RIFFchunk['amvh']['runtime_sec']    = getid3_lib::LittleEndian2Int(substr($AMVheader,  64,  1));
1506              $RIFFchunk['amvh']['runtime_min']    = getid3_lib::LittleEndian2Int(substr($AMVheader,  65,  1));
1507              $RIFFchunk['amvh']['runtime_hrs']    = getid3_lib::LittleEndian2Int(substr($AMVheader,  66,  2));
1508  
1509              $info['video']['frame_rate']   = 1000000 / $RIFFchunk['amvh']['us_per_frame'];
1510              $info['video']['resolution_x'] = $RIFFchunk['amvh']['resolution_x'];
1511              $info['video']['resolution_y'] = $RIFFchunk['amvh']['resolution_y'];
1512              $info['playtime_seconds']      = ($RIFFchunk['amvh']['runtime_hrs'] * 3600) + ($RIFFchunk['amvh']['runtime_min'] * 60) + $RIFFchunk['amvh']['runtime_sec'];
1513  
1514              // 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
1515  
1516              if (substr($AMVheader,  68, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x38\x00\x00\x00") {
1517                  throw new Exception('expecting "LIST<0x00000000>strlstrh<0x38000000>" at offset '.($startoffset +  68).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader,  68, 20)).'"');
1518              }
1519              // followed by 56 bytes of null: substr($AMVheader,  88, 56) -> 144
1520              if (substr($AMVheader, 144,  8) != 'strf'."\x24\x00\x00\x00") {
1521                  throw new Exception('expecting "strf<0x24000000>" at offset '.($startoffset + 144).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 144,  8)).'"');
1522              }
1523              // followed by 36 bytes of null: substr($AMVheader, 144, 36) -> 180
1524  
1525              if (substr($AMVheader, 188, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x30\x00\x00\x00") {
1526                  throw new Exception('expecting "LIST<0x00000000>strlstrh<0x30000000>" at offset '.($startoffset + 188).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 188, 20)).'"');
1527              }
1528              // followed by 48 bytes of null: substr($AMVheader, 208, 48) -> 256
1529              if (substr($AMVheader, 256,  8) != 'strf'."\x14\x00\x00\x00") {
1530                  throw new Exception('expecting "strf<0x14000000>" at offset '.($startoffset + 256).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 256,  8)).'"');
1531              }
1532              // followed by 20 bytes of a modified WAVEFORMATEX:
1533              // typedef struct {
1534              // WORD wFormatTag;       //(Fixme: this is equal to PCM's 0x01 format code)
1535              // WORD nChannels;        //(Fixme: this is always 1)
1536              // DWORD nSamplesPerSec;  //(Fixme: for all known sample files this is equal to 22050)
1537              // DWORD nAvgBytesPerSec; //(Fixme: for all known sample files this is equal to 44100)
1538              // WORD nBlockAlign;      //(Fixme: this seems to be 2 in AMV files, is this correct ?)
1539              // WORD wBitsPerSample;   //(Fixme: this seems to be 16 in AMV files instead of the expected 4)
1540              // WORD cbSize;           //(Fixme: this seems to be 0 in AMV files)
1541              // WORD reserved;
1542              // } WAVEFORMATEX;
1543              $RIFFchunk['strf']['wformattag']      = getid3_lib::LittleEndian2Int(substr($AMVheader,  264,  2));
1544              $RIFFchunk['strf']['nchannels']       = getid3_lib::LittleEndian2Int(substr($AMVheader,  266,  2));
1545              $RIFFchunk['strf']['nsamplespersec']  = getid3_lib::LittleEndian2Int(substr($AMVheader,  268,  4));
1546              $RIFFchunk['strf']['navgbytespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader,  272,  4));
1547              $RIFFchunk['strf']['nblockalign']     = getid3_lib::LittleEndian2Int(substr($AMVheader,  276,  2));
1548              $RIFFchunk['strf']['wbitspersample']  = getid3_lib::LittleEndian2Int(substr($AMVheader,  278,  2));
1549              $RIFFchunk['strf']['cbsize']          = getid3_lib::LittleEndian2Int(substr($AMVheader,  280,  2));
1550              $RIFFchunk['strf']['reserved']        = getid3_lib::LittleEndian2Int(substr($AMVheader,  282,  2));
1551  
1552  
1553              $info['audio']['lossless']        = false;
1554              $info['audio']['sample_rate']     = $RIFFchunk['strf']['nsamplespersec'];
1555              $info['audio']['channels']        = $RIFFchunk['strf']['nchannels'];
1556              $info['audio']['bits_per_sample'] = $RIFFchunk['strf']['wbitspersample'];
1557              $info['audio']['bitrate']         = $info['audio']['sample_rate'] * $info['audio']['channels'] * $info['audio']['bits_per_sample'];
1558              $info['audio']['bitrate_mode']    = 'cbr';
1559  
1560  
1561          } catch (getid3_exception $e) {
1562              if ($e->getCode() == 10) {
1563                  $this->warning('RIFFAMV parser: '.$e->getMessage());
1564              } else {
1565                  throw $e;
1566              }
1567          }
1568  
1569          return $RIFFchunk;
1570      }
1571  
1572      /**
1573       * @param int $startoffset
1574       * @param int $maxoffset
1575       *
1576       * @return array|false
1577       * @throws getid3_exception
1578       */
1579  	public function ParseRIFF($startoffset, $maxoffset) {
1580          $info = &$this->getid3->info;
1581  
1582          $RIFFchunk = false;
1583          $FoundAllChunksWeNeed = false;
1584          $LISTchunkParent = null;
1585          $LISTchunkMaxOffset = null;
1586          $AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77"
1587  
1588          try {
1589              $this->fseek($startoffset);
1590              $maxoffset = min($maxoffset, $info['avdataend']);
1591              while ($this->ftell() < $maxoffset) {
1592                  $chunknamesize = $this->fread(8);
1593                  //$chunkname =                          substr($chunknamesize, 0, 4);
1594                  $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
1595                  $chunksize =  $this->EitherEndian2Int(substr($chunknamesize, 4, 4));
1596                  //if (strlen(trim($chunkname, "\x00")) < 4) {
1597                  if (strlen($chunkname) < 4) {
1598                      $this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.');
1599                      break;
1600                  }
1601                  if (($chunksize == 0) && ($chunkname != 'JUNK')) {
1602                      $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.');
1603                      break;
1604                  }
1605                  if (($chunksize % 2) != 0) {
1606                      // all structures are packed on word boundaries
1607                      $chunksize++;
1608                  }
1609  
1610                  switch ($chunkname) {
1611                      case 'LIST':
1612                          $listname = $this->fread(4);
1613                          if (preg_match('#^(movi|rec )$#i', $listname)) {
1614                              $RIFFchunk[$listname]['offset'] = $this->ftell() - 4;
1615                              $RIFFchunk[$listname]['size']   = $chunksize;
1616  
1617                              if (!$FoundAllChunksWeNeed) {
1618                                  $WhereWeWere      = $this->ftell();
1619                                  $AudioChunkHeader = $this->fread(12);
1620                                  $AudioChunkStreamNum  =                              substr($AudioChunkHeader, 0, 2);
1621                                  $AudioChunkStreamType =                              substr($AudioChunkHeader, 2, 2);
1622                                  $AudioChunkSize       = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4));
1623  
1624                                  if ($AudioChunkStreamType == 'wb') {
1625                                      $FirstFourBytes = substr($AudioChunkHeader, 8, 4);
1626                                      if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) {
1627                                          // MP3
1628                                          if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
1629                                              $getid3_temp = new getID3();
1630                                              $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
1631                                              $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
1632                                              $getid3_temp->info['avdataend']    = $this->ftell() + $AudioChunkSize;
1633                                              $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
1634                                              $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
1635                                              if (isset($getid3_temp->info['mpeg']['audio'])) {
1636                                                  $info['mpeg']['audio']         = $getid3_temp->info['mpeg']['audio'];
1637                                                  $info['audio']                 = $getid3_temp->info['audio'];
1638                                                  $info['audio']['dataformat']   = 'mp'.$info['mpeg']['audio']['layer'];
1639                                                  $info['audio']['sample_rate']  = $info['mpeg']['audio']['sample_rate'];
1640                                                  $info['audio']['channels']     = $info['mpeg']['audio']['channels'];
1641                                                  $info['audio']['bitrate']      = $info['mpeg']['audio']['bitrate'];
1642                                                  $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1643                                                  //$info['bitrate']               = $info['audio']['bitrate'];
1644                                              }
1645                                              unset($getid3_temp, $getid3_mp3);
1646                                          }
1647  
1648                                      } elseif (strpos($FirstFourBytes, $AC3syncwordBytes) === 0) {
1649                                          // AC3
1650                                          $getid3_temp = new getID3();
1651                                          $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
1652                                          $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
1653                                          $getid3_temp->info['avdataend']    = $this->ftell() + $AudioChunkSize;
1654                                          $getid3_ac3 = new getid3_ac3($getid3_temp);
1655                                          $getid3_ac3->Analyze();
1656                                          if (empty($getid3_temp->info['error'])) {
1657                                              $info['audio']   = $getid3_temp->info['audio'];
1658                                              $info['ac3']     = $getid3_temp->info['ac3'];
1659                                              if (!empty($getid3_temp->info['warning'])) {
1660                                                  foreach ($getid3_temp->info['warning'] as $key => $value) {
1661                                                      $this->warning($value);
1662                                                  }
1663                                              }
1664                                          }
1665                                          unset($getid3_temp, $getid3_ac3);
1666                                      }
1667                                  }
1668                                  $FoundAllChunksWeNeed = true;
1669                                  $this->fseek($WhereWeWere);
1670                              }
1671                              $this->fseek($chunksize - 4, SEEK_CUR);
1672  
1673                          } else {
1674  
1675                              if (!isset($RIFFchunk[$listname])) {
1676                                  $RIFFchunk[$listname] = array();
1677                              }
1678                              $LISTchunkParent    = $listname;
1679                              $LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize;
1680                              if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) {
1681                                  $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk);
1682                              }
1683  
1684                          }
1685                          break;
1686  
1687                      default:
1688                          if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) {
1689                              $this->fseek($chunksize, SEEK_CUR);
1690                              break;
1691                          }
1692                          $thisindex = 0;
1693                          if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) {
1694                              $thisindex = count($RIFFchunk[$chunkname]);
1695                          }
1696                          $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8;
1697                          $RIFFchunk[$chunkname][$thisindex]['size']   = $chunksize;
1698                          switch ($chunkname) {
1699                              case 'data':
1700                                  $info['avdataoffset'] = $this->ftell();
1701                                  $info['avdataend']    = $info['avdataoffset'] + $chunksize;
1702  
1703                                  $testData = $this->fread(36);
1704                                  if ($testData === '') {
1705                                      break;
1706                                  }
1707                                  if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) {
1708  
1709                                      // Probably is MP3 data
1710                                      if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
1711                                          $getid3_temp = new getID3();
1712                                          $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
1713                                          $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1714                                          $getid3_temp->info['avdataend']    = $info['avdataend'];
1715                                          $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
1716                                          $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
1717                                          if (empty($getid3_temp->info['error'])) {
1718                                              $info['audio'] = $getid3_temp->info['audio'];
1719                                              $info['mpeg']  = $getid3_temp->info['mpeg'];
1720                                          }
1721                                          unset($getid3_temp, $getid3_mp3);
1722                                      }
1723  
1724                                  } elseif (($isRegularAC3 = (substr($testData, 0, 2) == $AC3syncwordBytes)) || substr($testData, 8, 2) == strrev($AC3syncwordBytes)) {
1725  
1726                                      // This is probably AC-3 data
1727                                      $getid3_temp = new getID3();
1728                                      if ($isRegularAC3) {
1729                                          $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
1730                                          $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1731                                          $getid3_temp->info['avdataend']    = $info['avdataend'];
1732                                      }
1733                                      $getid3_ac3 = new getid3_ac3($getid3_temp);
1734                                      if ($isRegularAC3) {
1735                                          $getid3_ac3->Analyze();
1736                                      } else {
1737                                          // Dolby Digital WAV
1738                                          // AC-3 content, but not encoded in same format as normal AC-3 file
1739                                          // For one thing, byte order is swapped
1740                                          $ac3_data = '';
1741                                          for ($i = 0; $i < 28; $i += 2) {
1742                                              $ac3_data .= substr($testData, 8 + $i + 1, 1);
1743                                              $ac3_data .= substr($testData, 8 + $i + 0, 1);
1744                                          }
1745                                          $getid3_ac3->getid3->info['avdataoffset'] = 0;
1746                                          $getid3_ac3->getid3->info['avdataend']    = strlen($ac3_data);
1747                                          $getid3_ac3->AnalyzeString($ac3_data);
1748                                      }
1749  
1750                                      if (empty($getid3_temp->info['error'])) {
1751                                          $info['audio'] = $getid3_temp->info['audio'];
1752                                          $info['ac3']   = $getid3_temp->info['ac3'];
1753                                          if (!empty($getid3_temp->info['warning'])) {
1754                                              foreach ($getid3_temp->info['warning'] as $newerror) {
1755                                                  $this->warning('getid3_ac3() says: ['.$newerror.']');
1756                                              }
1757                                          }
1758                                      }
1759                                      unset($getid3_temp, $getid3_ac3);
1760  
1761                                  } elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts::$syncwords)).')/', $testData)) {
1762  
1763                                      // This is probably DTS data
1764                                      $getid3_temp = new getID3();
1765                                      $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
1766                                      $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1767                                      $getid3_dts = new getid3_dts($getid3_temp);
1768                                      $getid3_dts->Analyze();
1769                                      if (empty($getid3_temp->info['error'])) {
1770                                          $info['audio']            = $getid3_temp->info['audio'];
1771                                          $info['dts']              = $getid3_temp->info['dts'];
1772                                          $info['playtime_seconds'] = $getid3_temp->info['playtime_seconds']; // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing
1773                                          if (!empty($getid3_temp->info['warning'])) {
1774                                              foreach ($getid3_temp->info['warning'] as $newerror) {
1775                                                  $this->warning('getid3_dts() says: ['.$newerror.']');
1776                                              }
1777                                          }
1778                                      }
1779  
1780                                      unset($getid3_temp, $getid3_dts);
1781  
1782                                  } elseif (substr($testData, 0, 4) == 'wvpk') {
1783  
1784                                      // This is WavPack data
1785                                      $info['wavpack']['offset'] = $info['avdataoffset'];
1786                                      $info['wavpack']['size']   = getid3_lib::LittleEndian2Int(substr($testData, 4, 4));
1787                                      $this->parseWavPackHeader(substr($testData, 8, 28));
1788  
1789                                  } else {
1790                                      // This is some other kind of data (quite possibly just PCM)
1791                                      // do nothing special, just skip it
1792                                  }
1793                                  $nextoffset = $info['avdataend'];
1794                                  $this->fseek($nextoffset);
1795                                  break;
1796  
1797                              case 'iXML':
1798                              case 'bext':
1799                              case 'cart':
1800                              case 'fmt ':
1801                              case 'strh':
1802                              case 'strf':
1803                              case 'indx':
1804                              case 'MEXT':
1805                              case 'DISP':
1806                              case 'wamd':
1807                              case 'guan':
1808                                  // always read data in
1809                              case 'JUNK':
1810                                  // should be: never read data in
1811                                  // but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc)
1812                                  if ($chunksize < 1048576) {
1813                                      if ($chunksize > 0) {
1814                                          $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
1815                                          if ($chunkname == 'JUNK') {
1816                                              if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) {
1817                                                  // only keep text characters [chr(32)-chr(127)]
1818                                                  $info['riff']['comments']['junk'][] = trim($matches[1]);
1819                                              }
1820                                              // but if nothing there, ignore
1821                                              // remove the key in either case
1822                                              unset($RIFFchunk[$chunkname][$thisindex]['data']);
1823                                          }
1824                                      }
1825                                  } else {
1826                                      $this->warning('Chunk "'.$chunkname.'" at offset '.$this->ftell().' is unexpectedly larger than 1MB (claims to be '.number_format($chunksize).' bytes), skipping data');
1827                                      $this->fseek($chunksize, SEEK_CUR);
1828                                  }
1829                                  break;
1830  
1831                              //case 'IDVX':
1832                              //    $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
1833                              //    break;
1834  
1835                              case 'scot':
1836                                  // https://cmsdk.com/node-js/adding-scot-chunk-to-wav-file.html
1837                                  $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
1838                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['alter']           =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],   0,   1);
1839                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['attrib']          =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],   1,   1);
1840                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['artnum']          = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'],   2,   2));
1841                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['title']           =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],   4,  43);  // "name" in other documentation
1842                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['copy']            =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  47,   4);
1843                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['padd']            =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  51,   1);
1844                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['asclen']          =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  52,   5);
1845                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['startseconds']    = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'],  57,   2));
1846                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['starthundredths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'],  59,   2));
1847                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['endseconds']      = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'],  61,   2));
1848                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['endhundreths']    = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'],  63,   2));
1849                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['sdate']           =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  65,   6);
1850                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['kdate']           =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  71,   6);
1851                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['start_hr']        =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  77,   1);
1852                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['kill_hr']         =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  78,   1);
1853                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['digital']         =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  79,   1);
1854                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['sample_rate']     = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'],  80,   2));
1855                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['stereo']          =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  82,   1);
1856                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['compress']        =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  83,   1);
1857                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['eomstrt']         = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'],  84,   4));
1858                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['eomlen']          = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'],  88,   2));
1859                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['attrib2']         = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'],  90,   4));
1860                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['future1']         =                              substr($RIFFchunk[$chunkname][$thisindex]['data'],  94,  12);
1861                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['catfontcolor']    = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 106,   4));
1862                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['catcolor']        = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 110,   4));
1863                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['segeompos']       = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 114,   4));
1864                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['vt_startsecs']    = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 118,   2));
1865                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['vt_starthunds']   = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 120,   2));
1866                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['priorcat']        =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 122,   3);
1867                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['priorcopy']       =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 125,   4);
1868                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['priorpadd']       =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 129,   1);
1869                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['postcat']         =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 130,   3);
1870                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['postcopy']        =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 133,   4);
1871                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['postpadd']        =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 137,   1);
1872                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['hrcanplay']       =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 138,  21);
1873                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['future2']         =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 159, 108);
1874                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['artist']          =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 267,  34);
1875                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['comment']         =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 301,  34); // "trivia" in other documentation
1876                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['intro']           =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 335,   2);
1877                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['end']             =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 337,   1);
1878                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['year']            =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 338,   4);
1879                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['obsolete2']       =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 342,   1);
1880                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['rec_hr']          =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 343,   1);
1881                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['rdate']           =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 344,   6);
1882                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['mpeg_bitrate']    = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 350,   2));
1883                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['pitch']           = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 352,   2));
1884                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['playlevel']       = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 354,   2));
1885                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['lenvalid']        =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 356,   1);
1886                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['filelength']      = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 357,   4));
1887                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['newplaylevel']    = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 361,   2));
1888                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['chopsize']        = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 363,   4));
1889                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['vteomovr']        = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 367,   4));
1890                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['desiredlen']      = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 371,   4));
1891                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['triggers']        = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 375,   4));
1892                                  $RIFFchunk[$chunkname][$thisindex]['parsed']['fillout']         =                              substr($RIFFchunk[$chunkname][$thisindex]['data'], 379,   33);
1893  
1894                                  foreach (array('title', 'artist', 'comment') as $key) {
1895                                      if (trim($RIFFchunk[$chunkname][$thisindex]['parsed'][$key])) {
1896                                          $info['riff']['comments'][$key] = array($RIFFchunk[$chunkname][$thisindex]['parsed'][$key]);
1897                                      }
1898                                  }
1899                                  if ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] && !empty($info['filesize']) && ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] != $info['filesize'])) {
1900                                      $this->warning('RIFF.WAVE.scot.filelength ('.$RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'].') different from actual filesize ('.$info['filesize'].')');
1901                                  }
1902                                  break;
1903  
1904                              default:
1905                                  if (!empty($LISTchunkParent) && isset($LISTchunkMaxOffset) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
1906                                      $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
1907                                      $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size']   = $RIFFchunk[$chunkname][$thisindex]['size'];
1908                                      unset($RIFFchunk[$chunkname][$thisindex]['offset']);
1909                                      unset($RIFFchunk[$chunkname][$thisindex]['size']);
1910                                      if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
1911                                          unset($RIFFchunk[$chunkname][$thisindex]);
1912                                      }
1913                                      if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) {
1914                                          unset($RIFFchunk[$chunkname]);
1915                                      }
1916                                      $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize);
1917                                  } elseif ($chunksize < 2048) {
1918                                      // only read data in if smaller than 2kB
1919                                      $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
1920                                  } else {
1921                                      $this->fseek($chunksize, SEEK_CUR);
1922                                  }
1923                                  break;
1924                          }
1925                          break;
1926                  }
1927              }
1928  
1929          } catch (getid3_exception $e) {
1930              if ($e->getCode() == 10) {
1931                  $this->warning('RIFF parser: '.$e->getMessage());
1932              } else {
1933                  throw $e;
1934              }
1935          }
1936  
1937          return $RIFFchunk;
1938      }
1939  
1940      /**
1941       * @param string $RIFFdata
1942       *
1943       * @return bool
1944       */
1945  	public function ParseRIFFdata(&$RIFFdata) {
1946          $info = &$this->getid3->info;
1947          if ($RIFFdata) {
1948              $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3');
1949              $fp_temp  = fopen($tempfile, 'wb');
1950              $RIFFdataLength = strlen($RIFFdata);
1951              $NewLengthString = getid3_lib::LittleEndian2String($RIFFdataLength, 4);
1952              for ($i = 0; $i < 4; $i++) {
1953                  $RIFFdata[($i + 4)] = $NewLengthString[$i];
1954              }
1955              fwrite($fp_temp, $RIFFdata);
1956              fclose($fp_temp);
1957  
1958              $getid3_temp = new getID3();
1959              $getid3_temp->openfile($tempfile);
1960              $getid3_temp->info['filesize']     = $RIFFdataLength;
1961              $getid3_temp->info['filenamepath'] = $info['filenamepath'];
1962              $getid3_temp->info['tags']         = $info['tags'];
1963              $getid3_temp->info['warning']      = $info['warning'];
1964              $getid3_temp->info['error']        = $info['error'];
1965              $getid3_temp->info['comments']     = $info['comments'];
1966              $getid3_temp->info['audio']        = (isset($info['audio']) ? $info['audio'] : array());
1967              $getid3_temp->info['video']        = (isset($info['video']) ? $info['video'] : array());
1968              $getid3_riff = new getid3_riff($getid3_temp);
1969              $getid3_riff->Analyze();
1970  
1971              $info['riff']     = $getid3_temp->info['riff'];
1972              $info['warning']  = $getid3_temp->info['warning'];
1973              $info['error']    = $getid3_temp->info['error'];
1974              $info['tags']     = $getid3_temp->info['tags'];
1975              $info['comments'] = $getid3_temp->info['comments'];
1976              unset($getid3_riff, $getid3_temp);
1977              unlink($tempfile);
1978          }
1979          return false;
1980      }
1981  
1982      /**
1983       * @param array $RIFFinfoArray
1984       * @param array $CommentsTargetArray
1985       *
1986       * @return bool
1987       */
1988  	public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
1989          $RIFFinfoKeyLookup = array(
1990              'IARL'=>'archivallocation',
1991              'IART'=>'artist',
1992              'ICDS'=>'costumedesigner',
1993              'ICMS'=>'commissionedby',
1994              'ICMT'=>'comment',
1995              'ICNT'=>'country',
1996              'ICOP'=>'copyright',
1997              'ICRD'=>'creationdate',
1998              'IDIM'=>'dimensions',
1999              'IDIT'=>'digitizationdate',
2000              'IDPI'=>'resolution',
2001              'IDST'=>'distributor',
2002              'IEDT'=>'editor',
2003              'IENG'=>'engineers',
2004              'IFRM'=>'accountofparts',
2005              'IGNR'=>'genre',
2006              'IKEY'=>'keywords',
2007              'ILGT'=>'lightness',
2008              'ILNG'=>'language',
2009              'IMED'=>'orignalmedium',
2010              'IMUS'=>'composer',
2011              'INAM'=>'title',
2012              'IPDS'=>'productiondesigner',
2013              'IPLT'=>'palette',
2014              'IPRD'=>'product',
2015              'IPRO'=>'producer',
2016              'IPRT'=>'part',
2017              'IRTD'=>'rating',
2018              'ISBJ'=>'subject',
2019              'ISFT'=>'software',
2020              'ISGN'=>'secondarygenre',
2021              'ISHP'=>'sharpness',
2022              'ISRC'=>'sourcesupplier',
2023              'ISRF'=>'digitizationsource',
2024              'ISTD'=>'productionstudio',
2025              'ISTR'=>'starring',
2026              'ITCH'=>'encoded_by',
2027              'IWEB'=>'url',
2028              'IWRI'=>'writer',
2029              '____'=>'comment',
2030          );
2031          foreach ($RIFFinfoKeyLookup as $key => $value) {
2032              if (isset($RIFFinfoArray[$key])) {
2033                  foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) {
2034                      if (trim($commentdata['data']) != '') {
2035                          if (isset($CommentsTargetArray[$value])) {
2036                              $CommentsTargetArray[$value][] =     trim($commentdata['data']);
2037                          } else {
2038                              $CommentsTargetArray[$value] = array(trim($commentdata['data']));
2039                          }
2040                      }
2041                  }
2042              }
2043          }
2044          return true;
2045      }
2046  
2047      /**
2048       * @param string $WaveFormatExData
2049       *
2050       * @return array
2051       */
2052  	public static function parseWAVEFORMATex($WaveFormatExData) {
2053          // shortcut
2054          $WaveFormatEx        = array();
2055          $WaveFormatEx['raw'] = array();
2056          $WaveFormatEx_raw    = &$WaveFormatEx['raw'];
2057  
2058          $WaveFormatEx_raw['wFormatTag']      = substr($WaveFormatExData,  0, 2);
2059          $WaveFormatEx_raw['nChannels']       = substr($WaveFormatExData,  2, 2);
2060          $WaveFormatEx_raw['nSamplesPerSec']  = substr($WaveFormatExData,  4, 4);
2061          $WaveFormatEx_raw['nAvgBytesPerSec'] = substr($WaveFormatExData,  8, 4);
2062          $WaveFormatEx_raw['nBlockAlign']     = substr($WaveFormatExData, 12, 2);
2063          $WaveFormatEx_raw['wBitsPerSample']  = substr($WaveFormatExData, 14, 2);
2064          if (strlen($WaveFormatExData) > 16) {
2065              $WaveFormatEx_raw['cbSize']      = substr($WaveFormatExData, 16, 2);
2066          }
2067          $WaveFormatEx_raw = array_map('getid3_lib::LittleEndian2Int', $WaveFormatEx_raw);
2068  
2069          $WaveFormatEx['codec']           = self::wFormatTagLookup($WaveFormatEx_raw['wFormatTag']);
2070          $WaveFormatEx['channels']        = $WaveFormatEx_raw['nChannels'];
2071          $WaveFormatEx['sample_rate']     = $WaveFormatEx_raw['nSamplesPerSec'];
2072          $WaveFormatEx['bitrate']         = $WaveFormatEx_raw['nAvgBytesPerSec'] * 8;
2073          $WaveFormatEx['bits_per_sample'] = $WaveFormatEx_raw['wBitsPerSample'];
2074  
2075          return $WaveFormatEx;
2076      }
2077  
2078      /**
2079       * @param string $WavPackChunkData
2080       *
2081       * @return bool
2082       */
2083  	public function parseWavPackHeader($WavPackChunkData) {
2084          // typedef struct {
2085          //     char ckID [4];
2086          //     long ckSize;
2087          //     short version;
2088          //     short bits;                // added for version 2.00
2089          //     short flags, shift;        // added for version 3.00
2090          //     long total_samples, crc, crc2;
2091          //     char extension [4], extra_bc, extras [3];
2092          // } WavpackHeader;
2093  
2094          // shortcut
2095          $info = &$this->getid3->info;
2096          $info['wavpack']  = array();
2097          $thisfile_wavpack = &$info['wavpack'];
2098  
2099          $thisfile_wavpack['version']           = getid3_lib::LittleEndian2Int(substr($WavPackChunkData,  0, 2));
2100          if ($thisfile_wavpack['version'] >= 2) {
2101              $thisfile_wavpack['bits']          = getid3_lib::LittleEndian2Int(substr($WavPackChunkData,  2, 2));
2102          }
2103          if ($thisfile_wavpack['version'] >= 3) {
2104              $thisfile_wavpack['flags_raw']     = getid3_lib::LittleEndian2Int(substr($WavPackChunkData,  4, 2));
2105              $thisfile_wavpack['shift']         = getid3_lib::LittleEndian2Int(substr($WavPackChunkData,  6, 2));
2106              $thisfile_wavpack['total_samples'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData,  8, 4));
2107              $thisfile_wavpack['crc1']          = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 12, 4));
2108              $thisfile_wavpack['crc2']          = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 16, 4));
2109              $thisfile_wavpack['extension']     =                              substr($WavPackChunkData, 20, 4);
2110              $thisfile_wavpack['extra_bc']      = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 24, 1));
2111              for ($i = 0; $i <= 2; $i++) {
2112                  $thisfile_wavpack['extras'][]  = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 25 + $i, 1));
2113              }
2114  
2115              // shortcut
2116              $thisfile_wavpack['flags'] = array();
2117              $thisfile_wavpack_flags = &$thisfile_wavpack['flags'];
2118  
2119              $thisfile_wavpack_flags['mono']                 = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001);
2120              $thisfile_wavpack_flags['fast_mode']            = (bool) ($thisfile_wavpack['flags_raw'] & 0x000002);
2121              $thisfile_wavpack_flags['raw_mode']             = (bool) ($thisfile_wavpack['flags_raw'] & 0x000004);
2122              $thisfile_wavpack_flags['calc_noise']           = (bool) ($thisfile_wavpack['flags_raw'] & 0x000008);
2123              $thisfile_wavpack_flags['high_quality']         = (bool) ($thisfile_wavpack['flags_raw'] & 0x000010);
2124              $thisfile_wavpack_flags['3_byte_samples']       = (bool) ($thisfile_wavpack['flags_raw'] & 0x000020);
2125              $thisfile_wavpack_flags['over_20_bits']         = (bool) ($thisfile_wavpack['flags_raw'] & 0x000040);
2126              $thisfile_wavpack_flags['use_wvc']              = (bool) ($thisfile_wavpack['flags_raw'] & 0x000080);
2127              $thisfile_wavpack_flags['noiseshaping']         = (bool) ($thisfile_wavpack['flags_raw'] & 0x000100);
2128              $thisfile_wavpack_flags['very_fast_mode']       = (bool) ($thisfile_wavpack['flags_raw'] & 0x000200);
2129              $thisfile_wavpack_flags['new_high_quality']     = (bool) ($thisfile_wavpack['flags_raw'] & 0x000400);
2130              $thisfile_wavpack_flags['cancel_extreme']       = (bool) ($thisfile_wavpack['flags_raw'] & 0x000800);
2131              $thisfile_wavpack_flags['cross_decorrelation']  = (bool) ($thisfile_wavpack['flags_raw'] & 0x001000);
2132              $thisfile_wavpack_flags['new_decorrelation']    = (bool) ($thisfile_wavpack['flags_raw'] & 0x002000);
2133              $thisfile_wavpack_flags['joint_stereo']         = (bool) ($thisfile_wavpack['flags_raw'] & 0x004000);
2134              $thisfile_wavpack_flags['extra_decorrelation']  = (bool) ($thisfile_wavpack['flags_raw'] & 0x008000);
2135              $thisfile_wavpack_flags['override_noiseshape']  = (bool) ($thisfile_wavpack['flags_raw'] & 0x010000);
2136              $thisfile_wavpack_flags['override_jointstereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x020000);
2137              $thisfile_wavpack_flags['copy_source_filetime'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x040000);
2138              $thisfile_wavpack_flags['create_exe']           = (bool) ($thisfile_wavpack['flags_raw'] & 0x080000);
2139          }
2140  
2141          return true;
2142      }
2143  
2144      /**
2145       * @param string $BITMAPINFOHEADER
2146       * @param bool   $littleEndian
2147       *
2148       * @return array
2149       */
2150  	public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
2151  
2152          $parsed                    = array();
2153          $parsed['biSize']          = substr($BITMAPINFOHEADER,  0, 4); // number of bytes required by the BITMAPINFOHEADER structure
2154          $parsed['biWidth']         = substr($BITMAPINFOHEADER,  4, 4); // width of the bitmap in pixels
2155          $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
2156          $parsed['biPlanes']        = substr($BITMAPINFOHEADER, 12, 2); // number of color planes on the target device. In most cases this value must be set to 1
2157          $parsed['biBitCount']      = substr($BITMAPINFOHEADER, 14, 2); // Specifies the number of bits per pixels
2158          $parsed['biSizeImage']     = substr($BITMAPINFOHEADER, 20, 4); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
2159          $parsed['biXPelsPerMeter'] = substr($BITMAPINFOHEADER, 24, 4); // horizontal resolution, in pixels per metre, of the target device
2160          $parsed['biYPelsPerMeter'] = substr($BITMAPINFOHEADER, 28, 4); // vertical resolution, in pixels per metre, of the target device
2161          $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
2162          $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
2163          $parsed = array_map('getid3_lib::'.($littleEndian ? 'Little' : 'Big').'Endian2Int', $parsed);
2164  
2165          $parsed['fourcc']          = substr($BITMAPINFOHEADER, 16, 4);  // compression identifier
2166  
2167          return $parsed;
2168      }
2169  
2170      /**
2171       * @param string $DIVXTAG
2172       * @param bool   $raw
2173       *
2174       * @return array
2175       */
2176  	public static function ParseDIVXTAG($DIVXTAG, $raw=false) {
2177          // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/
2178          // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip
2179          // 'Byte Layout:                   '1111111111111111
2180          // '32 for Movie - 1               '1111111111111111
2181          // '28 for Author - 6              '6666666666666666
2182          // '4  for year - 2                '6666666666662222
2183          // '3  for genre - 3               '7777777777777777
2184          // '48 for Comments - 7            '7777777777777777
2185          // '1  for Rating - 4              '7777777777777777
2186          // '5  for Future Additions - 0    '333400000DIVXTAG
2187          // '128 bytes total
2188  
2189          static $DIVXTAGgenre  = array(
2190               0 => 'Action',
2191               1 => 'Action/Adventure',
2192               2 => 'Adventure',
2193               3 => 'Adult',
2194               4 => 'Anime',
2195               5 => 'Cartoon',
2196               6 => 'Claymation',
2197               7 => 'Comedy',
2198               8 => 'Commercial',
2199               9 => 'Documentary',
2200              10 => 'Drama',
2201              11 => 'Home Video',
2202              12 => 'Horror',
2203              13 => 'Infomercial',
2204              14 => 'Interactive',
2205              15 => 'Mystery',
2206              16 => 'Music Video',
2207              17 => 'Other',
2208              18 => 'Religion',
2209              19 => 'Sci Fi',
2210              20 => 'Thriller',
2211              21 => 'Western',
2212          ),
2213          $DIVXTAGrating = array(
2214               0 => 'Unrated',
2215               1 => 'G',
2216               2 => 'PG',
2217               3 => 'PG-13',
2218               4 => 'R',
2219               5 => 'NC-17',
2220          );
2221  
2222          $parsed              = array();
2223          $parsed['title']     =        trim(substr($DIVXTAG,   0, 32));
2224          $parsed['artist']    =        trim(substr($DIVXTAG,  32, 28));
2225          $parsed['year']      = intval(trim(substr($DIVXTAG,  60,  4)));
2226          $parsed['comment']   =        trim(substr($DIVXTAG,  64, 48));
2227          $parsed['genre_id']  = intval(trim(substr($DIVXTAG, 112,  3)));
2228          $parsed['rating_id'] =         ord(substr($DIVXTAG, 115,  1));
2229          //$parsed['padding'] =             substr($DIVXTAG, 116,  5);  // 5-byte null
2230          //$parsed['magic']   =             substr($DIVXTAG, 121,  7);  // "DIVXTAG"
2231  
2232          $parsed['genre']  = (isset($DIVXTAGgenre[$parsed['genre_id']])   ? $DIVXTAGgenre[$parsed['genre_id']]   : $parsed['genre_id']);
2233          $parsed['rating'] = (isset($DIVXTAGrating[$parsed['rating_id']]) ? $DIVXTAGrating[$parsed['rating_id']] : $parsed['rating_id']);
2234  
2235          if (!$raw) {
2236              unset($parsed['genre_id'], $parsed['rating_id']);
2237              foreach ($parsed as $key => $value) {
2238                  if (empty($value)) {
2239                      unset($parsed[$key]);
2240                  }
2241              }
2242          }
2243  
2244          foreach ($parsed as $tag => $value) {
2245              $parsed[$tag] = array($value);
2246          }
2247  
2248          return $parsed;
2249      }
2250  
2251      /**
2252       * @param string $tagshortname
2253       *
2254       * @return string
2255       */
2256  	public static function waveSNDMtagLookup($tagshortname) {
2257          $begin = __LINE__;
2258  
2259          /** This is not a comment!
2260  
2261              ©kwd    keywords
2262              ©BPM    bpm
2263              ©trt    tracktitle
2264              ©des    description
2265              ©gen    category
2266              ©fin    featuredinstrument
2267              ©LID    longid
2268              ©bex    bwdescription
2269              ©pub    publisher
2270              ©cdt    cdtitle
2271              ©alb    library
2272              ©com    composer
2273  
2274          */
2275  
2276          return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm');
2277      }
2278  
2279      /**
2280       * @param int $wFormatTag
2281       *
2282       * @return string
2283       */
2284  	public static function wFormatTagLookup($wFormatTag) {
2285  
2286          $begin = __LINE__;
2287  
2288          /** This is not a comment!
2289  
2290              0x0000    Microsoft Unknown Wave Format
2291              0x0001    Pulse Code Modulation (PCM)
2292              0x0002    Microsoft ADPCM
2293              0x0003    IEEE Float
2294              0x0004    Compaq Computer VSELP
2295              0x0005    IBM CVSD
2296              0x0006    Microsoft A-Law
2297              0x0007    Microsoft mu-Law
2298              0x0008    Microsoft DTS
2299              0x0010    OKI ADPCM
2300              0x0011    Intel DVI/IMA ADPCM
2301              0x0012    Videologic MediaSpace ADPCM
2302              0x0013    Sierra Semiconductor ADPCM
2303              0x0014    Antex Electronics G.723 ADPCM
2304              0x0015    DSP Solutions DigiSTD
2305              0x0016    DSP Solutions DigiFIX
2306              0x0017    Dialogic OKI ADPCM
2307              0x0018    MediaVision ADPCM
2308              0x0019    Hewlett-Packard CU
2309              0x0020    Yamaha ADPCM
2310              0x0021    Speech Compression Sonarc
2311              0x0022    DSP Group TrueSpeech
2312              0x0023    Echo Speech EchoSC1
2313              0x0024    Audiofile AF36
2314              0x0025    Audio Processing Technology APTX
2315              0x0026    AudioFile AF10
2316              0x0027    Prosody 1612
2317              0x0028    LRC
2318              0x0030    Dolby AC2
2319              0x0031    Microsoft GSM 6.10
2320              0x0032    MSNAudio
2321              0x0033    Antex Electronics ADPCME
2322              0x0034    Control Resources VQLPC
2323              0x0035    DSP Solutions DigiREAL
2324              0x0036    DSP Solutions DigiADPCM
2325              0x0037    Control Resources CR10
2326              0x0038    Natural MicroSystems VBXADPCM
2327              0x0039    Crystal Semiconductor IMA ADPCM
2328              0x003A    EchoSC3
2329              0x003B    Rockwell ADPCM
2330              0x003C    Rockwell Digit LK
2331              0x003D    Xebec
2332              0x0040    Antex Electronics G.721 ADPCM
2333              0x0041    G.728 CELP
2334              0x0042    MSG723
2335              0x0050    MPEG Layer-2 or Layer-1
2336              0x0052    RT24
2337              0x0053    PAC
2338              0x0055    MPEG Layer-3
2339              0x0059    Lucent G.723
2340              0x0060    Cirrus
2341              0x0061    ESPCM
2342              0x0062    Voxware
2343              0x0063    Canopus Atrac
2344              0x0064    G.726 ADPCM
2345              0x0065    G.722 ADPCM
2346              0x0066    DSAT
2347              0x0067    DSAT Display
2348              0x0069    Voxware Byte Aligned
2349              0x0070    Voxware AC8
2350              0x0071    Voxware AC10
2351              0x0072    Voxware AC16
2352              0x0073    Voxware AC20
2353              0x0074    Voxware MetaVoice
2354              0x0075    Voxware MetaSound
2355              0x0076    Voxware RT29HW
2356              0x0077    Voxware VR12
2357              0x0078    Voxware VR18
2358              0x0079    Voxware TQ40
2359              0x0080    Softsound
2360              0x0081    Voxware TQ60
2361              0x0082    MSRT24
2362              0x0083    G.729A
2363              0x0084    MVI MV12
2364              0x0085    DF G.726
2365              0x0086    DF GSM610
2366              0x0088    ISIAudio
2367              0x0089    Onlive
2368              0x0091    SBC24
2369              0x0092    Dolby AC3 SPDIF
2370              0x0093    MediaSonic G.723
2371              0x0094    Aculab PLC    Prosody 8kbps
2372              0x0097    ZyXEL ADPCM
2373              0x0098    Philips LPCBB
2374              0x0099    Packed
2375              0x00FF    AAC
2376              0x0100    Rhetorex ADPCM
2377              0x0101    IBM mu-law
2378              0x0102    IBM A-law
2379              0x0103    IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM)
2380              0x0111    Vivo G.723
2381              0x0112    Vivo Siren
2382              0x0123    Digital G.723
2383              0x0125    Sanyo LD ADPCM
2384              0x0130    Sipro Lab Telecom ACELP NET
2385              0x0131    Sipro Lab Telecom ACELP 4800
2386              0x0132    Sipro Lab Telecom ACELP 8V3
2387              0x0133    Sipro Lab Telecom G.729
2388              0x0134    Sipro Lab Telecom G.729A
2389              0x0135    Sipro Lab Telecom Kelvin
2390              0x0140    Windows Media Video V8
2391              0x0150    Qualcomm PureVoice
2392              0x0151    Qualcomm HalfRate
2393              0x0155    Ring Zero Systems TUB GSM
2394              0x0160    Microsoft Audio 1
2395              0x0161    Windows Media Audio V7 / V8 / V9
2396              0x0162    Windows Media Audio Professional V9
2397              0x0163    Windows Media Audio Lossless V9
2398              0x0200    Creative Labs ADPCM
2399              0x0202    Creative Labs Fastspeech8
2400              0x0203    Creative Labs Fastspeech10
2401              0x0210    UHER Informatic GmbH ADPCM
2402              0x0220    Quarterdeck
2403              0x0230    I-link Worldwide VC
2404              0x0240    Aureal RAW Sport
2405              0x0250    Interactive Products HSX
2406              0x0251    Interactive Products RPELP
2407              0x0260    Consistent Software CS2
2408              0x0270    Sony SCX
2409              0x0300    Fujitsu FM Towns Snd
2410              0x0400    BTV Digital
2411              0x0401    Intel Music Coder
2412              0x0450    QDesign Music
2413              0x0680    VME VMPCM
2414              0x0681    AT&T Labs TPC
2415              0x08AE    ClearJump LiteWave
2416              0x1000    Olivetti GSM
2417              0x1001    Olivetti ADPCM
2418              0x1002    Olivetti CELP
2419              0x1003    Olivetti SBC
2420              0x1004    Olivetti OPR
2421              0x1100    Lernout & Hauspie Codec (0x1100)
2422              0x1101    Lernout & Hauspie CELP Codec (0x1101)
2423              0x1102    Lernout & Hauspie SBC Codec (0x1102)
2424              0x1103    Lernout & Hauspie SBC Codec (0x1103)
2425              0x1104    Lernout & Hauspie SBC Codec (0x1104)
2426              0x1400    Norris
2427              0x1401    AT&T ISIAudio
2428              0x1500    Soundspace Music Compression
2429              0x181C    VoxWare RT24 Speech
2430              0x1FC4    NCT Soft ALF2CD (www.nctsoft.com)
2431              0x2000    Dolby AC3
2432              0x2001    Dolby DTS
2433              0x2002    WAVE_FORMAT_14_4
2434              0x2003    WAVE_FORMAT_28_8
2435              0x2004    WAVE_FORMAT_COOK
2436              0x2005    WAVE_FORMAT_DNET
2437              0x674F    Ogg Vorbis 1
2438              0x6750    Ogg Vorbis 2
2439              0x6751    Ogg Vorbis 3
2440              0x676F    Ogg Vorbis 1+
2441              0x6770    Ogg Vorbis 2+
2442              0x6771    Ogg Vorbis 3+
2443              0x7A21    GSM-AMR (CBR, no SID)
2444              0x7A22    GSM-AMR (VBR, including SID)
2445              0xFFFE    WAVE_FORMAT_EXTENSIBLE
2446              0xFFFF    WAVE_FORMAT_DEVELOPMENT
2447  
2448          */
2449  
2450          return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag');
2451      }
2452  
2453      /**
2454       * @param string $fourcc
2455       *
2456       * @return string
2457       */
2458  	public static function fourccLookup($fourcc) {
2459  
2460          $begin = __LINE__;
2461  
2462          /** This is not a comment!
2463  
2464              swot    http://developer.apple.com/qa/snd/snd07.html
2465              ____    No Codec (____)
2466              _BIT    BI_BITFIELDS (Raw RGB)
2467              _JPG    JPEG compressed
2468              _PNG    PNG compressed W3C/ISO/IEC (RFC-2083)
2469              _RAW    Full Frames (Uncompressed)
2470              _RGB    Raw RGB Bitmap
2471              _RL4    RLE 4bpp RGB
2472              _RL8    RLE 8bpp RGB
2473              3IV1    3ivx MPEG-4 v1
2474              3IV2    3ivx MPEG-4 v2
2475              3IVX    3ivx MPEG-4
2476              AASC    Autodesk Animator
2477              ABYR    Kensington ?ABYR?
2478              AEMI    Array Microsystems VideoONE MPEG1-I Capture
2479              AFLC    Autodesk Animator FLC
2480              AFLI    Autodesk Animator FLI
2481              AMPG    Array Microsystems VideoONE MPEG
2482              ANIM    Intel RDX (ANIM)
2483              AP41    AngelPotion Definitive
2484              ASV1    Asus Video v1
2485              ASV2    Asus Video v2
2486              ASVX    Asus Video 2.0 (audio)
2487              AUR2    AuraVision Aura 2 Codec - YUV 4:2:2
2488              AURA    AuraVision Aura 1 Codec - YUV 4:1:1
2489              AVDJ    Independent JPEG Group\'s codec (AVDJ)
2490              AVRN    Independent JPEG Group\'s codec (AVRN)
2491              AYUV    4:4:4 YUV (AYUV)
2492              AZPR    Quicktime Apple Video (AZPR)
2493              BGR     Raw RGB32
2494              BLZ0    Blizzard DivX MPEG-4
2495              BTVC    Conexant Composite Video
2496              BINK    RAD Game Tools Bink Video
2497              BT20    Conexant Prosumer Video
2498              BTCV    Conexant Composite Video Codec
2499              BW10    Data Translation Broadway MPEG Capture
2500              CC12    Intel YUV12
2501              CDVC    Canopus DV
2502              CFCC    Digital Processing Systems DPS Perception
2503              CGDI    Microsoft Office 97 Camcorder Video
2504              CHAM    Winnov Caviara Champagne
2505              CJPG    Creative WebCam JPEG
2506              CLJR    Cirrus Logic YUV 4:1:1
2507              CMYK    Common Data Format in Printing (Colorgraph)
2508              CPLA    Weitek 4:2:0 YUV Planar
2509              CRAM    Microsoft Video 1 (CRAM)
2510              cvid    Radius Cinepak
2511              CVID    Radius Cinepak
2512              CWLT    Microsoft Color WLT DIB
2513              CYUV    Creative Labs YUV
2514              CYUY    ATI YUV
2515              D261    H.261
2516              D263    H.263
2517              DIB     Device Independent Bitmap
2518              DIV1    FFmpeg OpenDivX
2519              DIV2    Microsoft MPEG-4 v1/v2
2520              DIV3    DivX ;-) MPEG-4 v3.x Low-Motion
2521              DIV4    DivX ;-) MPEG-4 v3.x Fast-Motion
2522              DIV5    DivX MPEG-4 v5.x
2523              DIV6    DivX ;-) (MS MPEG-4 v3.x)
2524              DIVX    DivX MPEG-4 v4 (OpenDivX / Project Mayo)
2525              divx    DivX MPEG-4
2526              DMB1    Matrox Rainbow Runner hardware MJPEG
2527              DMB2    Paradigm MJPEG
2528              DSVD    ?DSVD?
2529              DUCK    Duck TrueMotion 1.0
2530              DPS0    DPS/Leitch Reality Motion JPEG
2531              DPSC    DPS/Leitch PAR Motion JPEG
2532              DV25    Matrox DVCPRO codec
2533              DV50    Matrox DVCPRO50 codec
2534              DVC     IEC 61834 and SMPTE 314M (DVC/DV Video)
2535              DVCP    IEC 61834 and SMPTE 314M (DVC/DV Video)
2536              DVHD    IEC Standard DV 1125 lines @ 30fps / 1250 lines @ 25fps
2537              DVMA    Darim Vision DVMPEG (dummy for MPEG compressor) (www.darvision.com)
2538              DVSL    IEC Standard DV compressed in SD (SDL)
2539              DVAN    ?DVAN?
2540              DVE2    InSoft DVE-2 Videoconferencing
2541              dvsd    IEC 61834 and SMPTE 314M DVC/DV Video
2542              DVSD    IEC 61834 and SMPTE 314M DVC/DV Video
2543              DVX1    Lucent DVX1000SP Video Decoder
2544              DVX2    Lucent DVX2000S Video Decoder
2545              DVX3    Lucent DVX3000S Video Decoder
2546              DX50    DivX v5
2547              DXT1    Microsoft DirectX Compressed Texture (DXT1)
2548              DXT2    Microsoft DirectX Compressed Texture (DXT2)
2549              DXT3    Microsoft DirectX Compressed Texture (DXT3)
2550              DXT4    Microsoft DirectX Compressed Texture (DXT4)
2551              DXT5    Microsoft DirectX Compressed Texture (DXT5)
2552              DXTC    Microsoft DirectX Compressed Texture (DXTC)
2553              DXTn    Microsoft DirectX Compressed Texture (DXTn)
2554              EM2V    Etymonix MPEG-2 I-frame (www.etymonix.com)
2555              EKQ0    Elsa ?EKQ0?
2556              ELK0    Elsa ?ELK0?
2557              ESCP    Eidos Escape
2558              ETV1    eTreppid Video ETV1
2559              ETV2    eTreppid Video ETV2
2560              ETVC    eTreppid Video ETVC
2561              FLIC    Autodesk FLI/FLC Animation
2562              FLV1    Sorenson Spark
2563              FLV4    On2 TrueMotion VP6
2564              FRWT    Darim Vision Forward Motion JPEG (www.darvision.com)
2565              FRWU    Darim Vision Forward Uncompressed (www.darvision.com)
2566              FLJP    D-Vision Field Encoded Motion JPEG
2567              FPS1    FRAPS v1
2568              FRWA    SoftLab-Nsk Forward Motion JPEG w/ alpha channel
2569              FRWD    SoftLab-Nsk Forward Motion JPEG
2570              FVF1    Iterated Systems Fractal Video Frame
2571              GLZW    Motion LZW (gabest@freemail.hu)
2572              GPEG    Motion JPEG (gabest@freemail.hu)
2573              GWLT    Microsoft Greyscale WLT DIB
2574              H260    Intel ITU H.260 Videoconferencing
2575              H261    Intel ITU H.261 Videoconferencing
2576              H262    Intel ITU H.262 Videoconferencing
2577              H263    Intel ITU H.263 Videoconferencing
2578              H264    Intel ITU H.264 Videoconferencing
2579              H265    Intel ITU H.265 Videoconferencing
2580              H266    Intel ITU H.266 Videoconferencing
2581              H267    Intel ITU H.267 Videoconferencing
2582              H268    Intel ITU H.268 Videoconferencing
2583              H269    Intel ITU H.269 Videoconferencing
2584              HFYU    Huffman Lossless Codec
2585              HMCR    Rendition Motion Compensation Format (HMCR)
2586              HMRR    Rendition Motion Compensation Format (HMRR)
2587              I263    FFmpeg I263 decoder
2588              IF09    Indeo YVU9 ("YVU9 with additional delta-frame info after the U plane")
2589              IUYV    Interlaced version of UYVY (www.leadtools.com)
2590              IY41    Interlaced version of Y41P (www.leadtools.com)
2591              IYU1    12 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec    IEEE standard
2592              IYU2    24 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec    IEEE standard
2593              IYUV    Planar YUV format (8-bpp Y plane, followed by 8-bpp 2×2 U and V planes)
2594              i263    Intel ITU H.263 Videoconferencing (i263)
2595              I420    Intel Indeo 4
2596              IAN     Intel Indeo 4 (RDX)
2597              ICLB    InSoft CellB Videoconferencing
2598              IGOR    Power DVD
2599              IJPG    Intergraph JPEG
2600              ILVC    Intel Layered Video
2601              ILVR    ITU-T H.263+
2602              IPDV    I-O Data Device Giga AVI DV Codec
2603              IR21    Intel Indeo 2.1
2604              IRAW    Intel YUV Uncompressed
2605              IV30    Intel Indeo 3.0
2606              IV31    Intel Indeo 3.1
2607              IV32    Ligos Indeo 3.2
2608              IV33    Ligos Indeo 3.3
2609              IV34    Ligos Indeo 3.4
2610              IV35    Ligos Indeo 3.5
2611              IV36    Ligos Indeo 3.6
2612              IV37    Ligos Indeo 3.7
2613              IV38    Ligos Indeo 3.8
2614              IV39    Ligos Indeo 3.9
2615              IV40    Ligos Indeo Interactive 4.0
2616              IV41    Ligos Indeo Interactive 4.1
2617              IV42    Ligos Indeo Interactive 4.2
2618              IV43    Ligos Indeo Interactive 4.3
2619              IV44    Ligos Indeo Interactive 4.4
2620              IV45    Ligos Indeo Interactive 4.5
2621              IV46    Ligos Indeo Interactive 4.6
2622              IV47    Ligos Indeo Interactive 4.7
2623              IV48    Ligos Indeo Interactive 4.8
2624              IV49    Ligos Indeo Interactive 4.9
2625              IV50    Ligos Indeo Interactive 5.0
2626              JBYR    Kensington ?JBYR?
2627              JPEG    Still Image JPEG DIB
2628              JPGL    Pegasus Lossless Motion JPEG
2629              KMVC    Team17 Software Karl Morton\'s Video Codec
2630              LSVM    Vianet Lighting Strike Vmail (Streaming) (www.vianet.com)
2631              LEAD    LEAD Video Codec
2632              Ljpg    LEAD MJPEG Codec
2633              MDVD    Alex MicroDVD Video (hacked MS MPEG-4) (www.tiasoft.de)
2634              MJPA    Morgan Motion JPEG (MJPA) (www.morgan-multimedia.com)
2635              MJPB    Morgan Motion JPEG (MJPB) (www.morgan-multimedia.com)
2636              MMES    Matrox MPEG-2 I-frame
2637              MP2v    Microsoft S-Mpeg 4 version 1 (MP2v)
2638              MP42    Microsoft S-Mpeg 4 version 2 (MP42)
2639              MP43    Microsoft S-Mpeg 4 version 3 (MP43)
2640              MP4S    Microsoft S-Mpeg 4 version 3 (MP4S)
2641              MP4V    FFmpeg MPEG-4
2642              MPG1    FFmpeg MPEG 1/2
2643              MPG2    FFmpeg MPEG 1/2
2644              MPG3    FFmpeg DivX ;-) (MS MPEG-4 v3)
2645              MPG4    Microsoft MPEG-4
2646              MPGI    Sigma Designs MPEG
2647              MPNG    PNG images decoder
2648              MSS1    Microsoft Windows Screen Video
2649              MSZH    LCL (Lossless Codec Library) (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
2650              M261    Microsoft H.261
2651              M263    Microsoft H.263
2652              M4S2    Microsoft Fully Compliant MPEG-4 v2 simple profile (M4S2)
2653              m4s2    Microsoft Fully Compliant MPEG-4 v2 simple profile (m4s2)
2654              MC12    ATI Motion Compensation Format (MC12)
2655              MCAM    ATI Motion Compensation Format (MCAM)
2656              MJ2C    Morgan Multimedia Motion JPEG2000
2657              mJPG    IBM Motion JPEG w/ Huffman Tables
2658              MJPG    Microsoft Motion JPEG DIB
2659              MP42    Microsoft MPEG-4 (low-motion)
2660              MP43    Microsoft MPEG-4 (fast-motion)
2661              MP4S    Microsoft MPEG-4 (MP4S)
2662              mp4s    Microsoft MPEG-4 (mp4s)
2663              MPEG    Chromatic Research MPEG-1 Video I-Frame
2664              MPG4    Microsoft MPEG-4 Video High Speed Compressor
2665              MPGI    Sigma Designs MPEG
2666              MRCA    FAST Multimedia Martin Regen Codec
2667              MRLE    Microsoft Run Length Encoding
2668              MSVC    Microsoft Video 1
2669              MTX1    Matrox ?MTX1?
2670              MTX2    Matrox ?MTX2?
2671              MTX3    Matrox ?MTX3?
2672              MTX4    Matrox ?MTX4?
2673              MTX5    Matrox ?MTX5?
2674              MTX6    Matrox ?MTX6?
2675              MTX7    Matrox ?MTX7?
2676              MTX8    Matrox ?MTX8?
2677              MTX9    Matrox ?MTX9?
2678              MV12    Motion Pixels Codec (old)
2679              MWV1    Aware Motion Wavelets
2680              nAVI    SMR Codec (hack of Microsoft MPEG-4) (IRC #shadowrealm)
2681              NT00    NewTek LightWave HDTV YUV w/ Alpha (www.newtek.com)
2682              NUV1    NuppelVideo
2683              NTN1    Nogatech Video Compression 1
2684              NVS0    nVidia GeForce Texture (NVS0)
2685              NVS1    nVidia GeForce Texture (NVS1)
2686              NVS2    nVidia GeForce Texture (NVS2)
2687              NVS3    nVidia GeForce Texture (NVS3)
2688              NVS4    nVidia GeForce Texture (NVS4)
2689              NVS5    nVidia GeForce Texture (NVS5)
2690              NVT0    nVidia GeForce Texture (NVT0)
2691              NVT1    nVidia GeForce Texture (NVT1)
2692              NVT2    nVidia GeForce Texture (NVT2)
2693              NVT3    nVidia GeForce Texture (NVT3)
2694              NVT4    nVidia GeForce Texture (NVT4)
2695              NVT5    nVidia GeForce Texture (NVT5)
2696              PIXL    MiroXL, Pinnacle PCTV
2697              PDVC    I-O Data Device Digital Video Capture DV codec
2698              PGVV    Radius Video Vision
2699              PHMO    IBM Photomotion
2700              PIM1    MPEG Realtime (Pinnacle Cards)
2701              PIM2    Pegasus Imaging ?PIM2?
2702              PIMJ    Pegasus Imaging Lossless JPEG
2703              PVEZ    Horizons Technology PowerEZ
2704              PVMM    PacketVideo Corporation MPEG-4
2705              PVW2    Pegasus Imaging Wavelet Compression
2706              Q1.0    Q-Team\'s QPEG 1.0 (www.q-team.de)
2707              Q1.1    Q-Team\'s QPEG 1.1 (www.q-team.de)
2708              QPEG    Q-Team QPEG 1.0
2709              qpeq    Q-Team QPEG 1.1
2710              RGB     Raw BGR32
2711              RGBA    Raw RGB w/ Alpha
2712              RMP4    REALmagic MPEG-4 (unauthorized XVID copy) (www.sigmadesigns.com)
2713              ROQV    Id RoQ File Video Decoder
2714              RPZA    Quicktime Apple Video (RPZA)
2715              RUD0    Rududu video codec (http://rududu.ifrance.com/rududu/)
2716              RV10    RealVideo 1.0 (aka RealVideo 5.0)
2717              RV13    RealVideo 1.0 (RV13)
2718              RV20    RealVideo G2
2719              RV30    RealVideo 8
2720              RV40    RealVideo 9
2721              RGBT    Raw RGB w/ Transparency
2722              RLE     Microsoft Run Length Encoder
2723              RLE4    Run Length Encoded (4bpp, 16-color)
2724              RLE8    Run Length Encoded (8bpp, 256-color)
2725              RT21    Intel Indeo RealTime Video 2.1
2726              rv20    RealVideo G2
2727              rv30    RealVideo 8
2728              RVX     Intel RDX (RVX )
2729              SMC     Apple Graphics (SMC )
2730              SP54    Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2
2731              SPIG    Radius Spigot
2732              SVQ3    Sorenson Video 3 (Apple Quicktime 5)
2733              s422    Tekram VideoCap C210 YUV 4:2:2
2734              SDCC    Sun Communication Digital Camera Codec
2735              SFMC    CrystalNet Surface Fitting Method
2736              SMSC    Radius SMSC
2737              SMSD    Radius SMSD
2738              smsv    WorldConnect Wavelet Video
2739              SPIG    Radius Spigot
2740              SPLC    Splash Studios ACM Audio Codec (www.splashstudios.net)
2741              SQZ2    Microsoft VXTreme Video Codec V2
2742              STVA    ST Microelectronics CMOS Imager Data (Bayer)
2743              STVB    ST Microelectronics CMOS Imager Data (Nudged Bayer)
2744              STVC    ST Microelectronics CMOS Imager Data (Bunched)
2745              STVX    ST Microelectronics CMOS Imager Data (Extended CODEC Data Format)
2746              STVY    ST Microelectronics CMOS Imager Data (Extended CODEC Data Format with Correction Data)
2747              SV10    Sorenson Video R1
2748              SVQ1    Sorenson Video
2749              T420    Toshiba YUV 4:2:0
2750              TM2A    Duck TrueMotion Archiver 2.0 (www.duck.com)
2751              TVJP    Pinnacle/Truevision Targa 2000 board (TVJP)
2752              TVMJ    Pinnacle/Truevision Targa 2000 board (TVMJ)
2753              TY0N    Tecomac Low-Bit Rate Codec (www.tecomac.com)
2754              TY2C    Trident Decompression Driver
2755              TLMS    TeraLogic Motion Intraframe Codec (TLMS)
2756              TLST    TeraLogic Motion Intraframe Codec (TLST)
2757              TM20    Duck TrueMotion 2.0
2758              TM2X    Duck TrueMotion 2X
2759              TMIC    TeraLogic Motion Intraframe Codec (TMIC)
2760              TMOT    Horizons Technology TrueMotion S
2761              tmot    Horizons TrueMotion Video Compression
2762              TR20    Duck TrueMotion RealTime 2.0
2763              TSCC    TechSmith Screen Capture Codec
2764              TV10    Tecomac Low-Bit Rate Codec
2765              TY2N    Trident ?TY2N?
2766              U263    UB Video H.263/H.263+/H.263++ Decoder
2767              UMP4    UB Video MPEG 4 (www.ubvideo.com)
2768              UYNV    Nvidia UYVY packed 4:2:2
2769              UYVP    Evans & Sutherland YCbCr 4:2:2 extended precision
2770              UCOD    eMajix.com ClearVideo
2771              ULTI    IBM Ultimotion
2772              UYVY    UYVY packed 4:2:2
2773              V261    Lucent VX2000S
2774              VIFP    VFAPI Reader Codec (www.yks.ne.jp/~hori/)
2775              VIV1    FFmpeg H263+ decoder
2776              VIV2    Vivo H.263
2777              VQC2    Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf)
2778              VTLP    Alaris VideoGramPiX
2779              VYU9    ATI YUV (VYU9)
2780              VYUY    ATI YUV (VYUY)
2781              V261    Lucent VX2000S
2782              V422    Vitec Multimedia 24-bit YUV 4:2:2 Format
2783              V655    Vitec Multimedia 16-bit YUV 4:2:2 Format
2784              VCR1    ATI Video Codec 1
2785              VCR2    ATI Video Codec 2
2786              VCR3    ATI VCR 3.0
2787              VCR4    ATI VCR 4.0
2788              VCR5    ATI VCR 5.0
2789              VCR6    ATI VCR 6.0
2790              VCR7    ATI VCR 7.0
2791              VCR8    ATI VCR 8.0
2792              VCR9    ATI VCR 9.0
2793              VDCT    Vitec Multimedia Video Maker Pro DIB
2794              VDOM    VDOnet VDOWave
2795              VDOW    VDOnet VDOLive (H.263)
2796              VDTZ    Darim Vison VideoTizer YUV
2797              VGPX    Alaris VideoGramPiX
2798              VIDS    Vitec Multimedia YUV 4:2:2 CCIR 601 for V422
2799              VIVO    Vivo H.263 v2.00
2800              vivo    Vivo H.263
2801              VIXL    Miro/Pinnacle Video XL
2802              VLV1    VideoLogic/PURE Digital Videologic Capture
2803              VP30    On2 VP3.0
2804              VP31    On2 VP3.1
2805              VP6F    On2 TrueMotion VP6
2806              VX1K    Lucent VX1000S Video Codec
2807              VX2K    Lucent VX2000S Video Codec
2808              VXSP    Lucent VX1000SP Video Codec
2809              WBVC    Winbond W9960
2810              WHAM    Microsoft Video 1 (WHAM)
2811              WINX    Winnov Software Compression
2812              WJPG    AverMedia Winbond JPEG
2813              WMV1    Windows Media Video V7
2814              WMV2    Windows Media Video V8
2815              WMV3    Windows Media Video V9
2816              WNV1    Winnov Hardware Compression
2817              XYZP    Extended PAL format XYZ palette (www.riff.org)
2818              x263    Xirlink H.263
2819              XLV0    NetXL Video Decoder
2820              XMPG    Xing MPEG (I-Frame only)
2821              XVID    XviD MPEG-4 (www.xvid.org)
2822              XXAN    ?XXAN?
2823              YU92    Intel YUV (YU92)
2824              YUNV    Nvidia Uncompressed YUV 4:2:2
2825              YUVP    Extended PAL format YUV palette (www.riff.org)
2826              Y211    YUV 2:1:1 Packed
2827              Y411    YUV 4:1:1 Packed
2828              Y41B    Weitek YUV 4:1:1 Planar
2829              Y41P    Brooktree PC1 YUV 4:1:1 Packed
2830              Y41T    Brooktree PC1 YUV 4:1:1 with transparency
2831              Y42B    Weitek YUV 4:2:2 Planar
2832              Y42T    Brooktree UYUV 4:2:2 with transparency
2833              Y422    ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera
2834              Y800    Simple, single Y plane for monochrome images
2835              Y8      Grayscale video
2836              YC12    Intel YUV 12 codec
2837              YUV8    Winnov Caviar YUV8
2838              YUV9    Intel YUV9
2839              YUY2    Uncompressed YUV 4:2:2
2840              YUYV    Canopus YUV
2841              YV12    YVU12 Planar
2842              YVU9    Intel YVU9 Planar (8-bpp Y plane, followed by 8-bpp 4x4 U and V planes)
2843              YVYU    YVYU 4:2:2 Packed
2844              ZLIB    Lossless Codec Library zlib compression (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
2845              ZPEG    Metheus Video Zipper
2846  
2847          */
2848  
2849          return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
2850      }
2851  
2852      /**
2853       * @param string $byteword
2854       * @param bool   $signed
2855       *
2856       * @return int|float|false
2857       */
2858  	private function EitherEndian2Int($byteword, $signed=false) {
2859          if ($this->container == 'riff') {
2860              return getid3_lib::LittleEndian2Int($byteword, $signed);
2861          }
2862          return getid3_lib::BigEndian2Int($byteword, false, $signed);
2863      }
2864  
2865  }


Generated: Sat May 21 01:00:03 2022 Cross-referenced by PHPXref 0.7.1