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


Generated : Fri Apr 26 08:20:02 2024 Cross-referenced by PHPXref