[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

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

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


Generated : Sun Jun 14 08:20:09 2026 Cross-referenced by PHPXref