[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

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


Generated : Wed Sep 23 08:20:35 2026 Cross-referenced by PHPXref