public function Analyze()
 {
     $info =& $this->getid3->info;
     // parse container
     try {
         $this->parseEBML($info);
     } catch (Exception $e) {
         $info['error'][] = 'EBML parser: ' . $e->getMessage();
     }
     // calculate playtime
     if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
         foreach ($info['matroska']['info'] as $key => $infoarray) {
             if (isset($infoarray['Duration'])) {
                 // TimecodeScale is how many nanoseconds each Duration unit is
                 $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000);
                 break;
             }
         }
     }
     // extract tags
     if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) {
         foreach ($info['matroska']['tags'] as $key => $infoarray) {
             $this->ExtractCommentsSimpleTag($infoarray);
         }
     }
     // process tracks
     if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
         foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) {
             $track_info = array();
             $track_info['dataformat'] = self::CodecIDtoCommonName($trackarray['CodecID']);
             $track_info['default'] = isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true;
             if (isset($trackarray['Name'])) {
                 $track_info['name'] = $trackarray['Name'];
             }
             switch ($trackarray['TrackType']) {
                 case 1:
                     // Video
                     $track_info['resolution_x'] = $trackarray['PixelWidth'];
                     $track_info['resolution_y'] = $trackarray['PixelHeight'];
                     $track_info['display_unit'] = self::displayUnit(isset($trackarray['DisplayUnit']) ? $trackarray['DisplayUnit'] : 0);
                     $track_info['display_x'] = isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth'];
                     $track_info['display_y'] = isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight'];
                     if (isset($trackarray['PixelCropBottom'])) {
                         $track_info['crop_bottom'] = $trackarray['PixelCropBottom'];
                     }
                     if (isset($trackarray['PixelCropTop'])) {
                         $track_info['crop_top'] = $trackarray['PixelCropTop'];
                     }
                     if (isset($trackarray['PixelCropLeft'])) {
                         $track_info['crop_left'] = $trackarray['PixelCropLeft'];
                     }
                     if (isset($trackarray['PixelCropRight'])) {
                         $track_info['crop_right'] = $trackarray['PixelCropRight'];
                     }
                     if (isset($trackarray['DefaultDuration'])) {
                         $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3);
                     }
                     if (isset($trackarray['CodecName'])) {
                         $track_info['codec'] = $trackarray['CodecName'];
                     }
                     switch ($trackarray['CodecID']) {
                         case 'V_MS/VFW/FOURCC':
                             getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio-video.riff.php', __FILE__, true);
                             $parsed = getid3_riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']);
                             $track_info['codec'] = getid3_riff::fourccLookup($parsed['fourcc']);
                             $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
                             break;
                             /*case 'V_MPEG4/ISO/AVC':
                             		$h264['profile']    = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 1, 1));
                             		$h264['level']      = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 3, 1));
                             		$rn                 = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 4, 1));
                             		$h264['NALUlength'] = ($rn & 3) + 1;
                             		$rn                 = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 5, 1));
                             		$nsps               = ($rn & 31);
                             		$offset             = 6;
                             		for ($i = 0; $i < $nsps; $i ++) {
                             			$length        = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2));
                             			$h264['SPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length);
                             			$offset       += 2 + $length;
                             		}
                             		$npps               = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 1));
                             		$offset            += 1;
                             		for ($i = 0; $i < $npps; $i ++) {
                             			$length        = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2));
                             			$h264['PPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length);
                             			$offset       += 2 + $length;
                             		}
                             		$info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $h264;
                             		break;*/
                     }
                     $info['video']['streams'][] = $track_info;
                     break;
                 case 2:
                     // Audio
                     $track_info['sample_rate'] = isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0;
                     $track_info['channels'] = isset($trackarray['Channels']) ? $trackarray['Channels'] : 1;
                     $track_info['language'] = isset($trackarray['Language']) ? $trackarray['Language'] : 'eng';
                     if (isset($trackarray['BitDepth'])) {
                         $track_info['bits_per_sample'] = $trackarray['BitDepth'];
                     }
                     if (isset($trackarray['CodecName'])) {
                         $track_info['codec'] = $trackarray['CodecName'];
                     }
                     switch ($trackarray['CodecID']) {
                         case 'A_PCM/INT/LIT':
                         case 'A_PCM/INT/BIG':
                             $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
                             break;
                         case 'A_AC3':
                         case 'A_DTS':
                         case 'A_MPEG/L3':
                         case 'A_MPEG/L2':
                         case 'A_FLAC':
                             getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio.' . ($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']) . '.php', __FILE__, true);
                             if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
                                 $this->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because $info[matroska][track_data_offsets][' . $trackarray['TrackNumber'] . '] not set');
                                 break;
                             }
                             // create temp instance
                             $getid3_temp = new getID3();
                             if ($track_info['dataformat'] != 'flac') {
                                 $getid3_temp->openfile($this->getid3->filename);
                             }
                             $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
                             if ($track_info['dataformat'][0] == 'm' || $track_info['dataformat'] == 'flac') {
                                 $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length'];
                             }
                             // analyze
                             $class = 'getid3_' . ($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']);
                             $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat'];
                             $getid3_audio = new $class($getid3_temp, __CLASS__);
                             if ($track_info['dataformat'] == 'flac') {
                                 $getid3_audio->AnalyzeString($trackarray['CodecPrivate']);
                             } else {
                                 $getid3_audio->Analyze();
                             }
                             if (!empty($getid3_temp->info[$header_data_key])) {
                                 $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
                                 if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
                                     foreach ($getid3_temp->info['audio'] as $key => $value) {
                                         $track_info[$key] = $value;
                                     }
                                 }
                             } else {
                                 $this->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because ' . $class . '::Analyze() failed at offset ' . $getid3_temp->info['avdataoffset']);
                             }
                             // copy errors and warnings
                             if (!empty($getid3_temp->info['error'])) {
                                 foreach ($getid3_temp->info['error'] as $newerror) {
                                     $this->warning($class . '() says: [' . $newerror . ']');
                                 }
                             }
                             if (!empty($getid3_temp->info['warning'])) {
                                 foreach ($getid3_temp->info['warning'] as $newerror) {
                                     $this->warning($class . '() says: [' . $newerror . ']');
                                 }
                             }
                             unset($getid3_temp, $getid3_audio);
                             break;
                         case 'A_AAC':
                         case 'A_AAC/MPEG2/LC':
                         case 'A_AAC/MPEG2/LC/SBR':
                         case 'A_AAC/MPEG4/LC':
                         case 'A_AAC/MPEG4/LC/SBR':
                             $this->warning($trackarray['CodecID'] . ' audio data contains no header, audio/video bitrates can\'t be calculated');
                             break;
                         case 'A_VORBIS':
                             if (!isset($trackarray['CodecPrivate'])) {
                                 $this->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because CodecPrivate data not set');
                                 break;
                             }
                             $vorbis_offset = strpos($trackarray['CodecPrivate'], 'vorbis', 1);
                             if ($vorbis_offset === false) {
                                 $this->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because CodecPrivate data does not contain "vorbis" keyword');
                                 break;
                             }
                             $vorbis_offset -= 1;
                             getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio.ogg.php', __FILE__, true);
                             // create temp instance
                             $getid3_temp = new getID3();
                             // analyze
                             $getid3_ogg = new getid3_ogg($getid3_temp);
                             $oggpageinfo['page_seqno'] = 0;
                             $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo);
                             if (!empty($getid3_temp->info['ogg'])) {
                                 $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
                                 if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
                                     foreach ($getid3_temp->info['audio'] as $key => $value) {
                                         $track_info[$key] = $value;
                                     }
                                 }
                             }
                             // copy errors and warnings
                             if (!empty($getid3_temp->info['error'])) {
                                 foreach ($getid3_temp->info['error'] as $newerror) {
                                     $this->warning('getid3_ogg() says: [' . $newerror . ']');
                                 }
                             }
                             if (!empty($getid3_temp->info['warning'])) {
                                 foreach ($getid3_temp->info['warning'] as $newerror) {
                                     $this->warning('getid3_ogg() says: [' . $newerror . ']');
                                 }
                             }
                             if (!empty($getid3_temp->info['ogg']['bitrate_nominal'])) {
                                 $track_info['bitrate'] = $getid3_temp->info['ogg']['bitrate_nominal'];
                             }
                             unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset);
                             break;
                         case 'A_MS/ACM':
                             getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio-video.riff.php', __FILE__, true);
                             $parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']);
                             foreach ($parsed as $key => $value) {
                                 if ($key != 'raw') {
                                     $track_info[$key] = $value;
                                 }
                             }
                             $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
                             break;
                         default:
                             $this->warning('Unhandled audio type "' . (isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '') . '"');
                             break;
                     }
                     $info['audio']['streams'][] = $track_info;
                     break;
             }
         }
         if (!empty($info['video']['streams'])) {
             $info['video'] = self::getDefaultStreamInfo($info['video']['streams']);
         }
         if (!empty($info['audio']['streams'])) {
             $info['audio'] = self::getDefaultStreamInfo($info['audio']['streams']);
         }
     }
     // process attachments
     if (isset($info['matroska']['attachments']) && $this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE) {
         foreach ($info['matroska']['attachments'] as $i => $entry) {
             if (strpos($entry['FileMimeType'], 'image/') === 0 && !empty($entry['FileData'])) {
                 $info['matroska']['comments']['picture'][] = array('data' => $entry['FileData'], 'image_mime' => $entry['FileMimeType'], 'filename' => $entry['FileName']);
             }
         }
     }
     // determine mime type
     if (!empty($info['video']['streams'])) {
         $info['mime_type'] = $info['matroska']['doctype'] == 'webm' ? 'video/webm' : 'video/x-matroska';
     } elseif (!empty($info['audio']['streams'])) {
         $info['mime_type'] = $info['matroska']['doctype'] == 'webm' ? 'audio/webm' : 'audio/x-matroska';
     } elseif (isset($info['mime_type'])) {
         unset($info['mime_type']);
     }
     return true;
 }
 function getid3_riff(&$fd, &$ThisFileInfo)
 {
     // initialize these values to an empty array, otherwise they default to NULL
     // and you can't append array values to a NULL value
     $ThisFileInfo['riff'] = array('raw' => array());
     // Shortcuts
     $thisfile_riff =& $ThisFileInfo['riff'];
     $thisfile_riff_raw =& $thisfile_riff['raw'];
     $thisfile_audio =& $ThisFileInfo['audio'];
     $thisfile_video =& $ThisFileInfo['video'];
     $thisfile_avdataoffset =& $ThisFileInfo['avdataoffset'];
     $thisfile_avdataend =& $ThisFileInfo['avdataend'];
     $thisfile_audio_dataformat =& $thisfile_audio['dataformat'];
     $thisfile_riff_audio =& $thisfile_riff['audio'];
     $thisfile_riff_video =& $thisfile_riff['video'];
     $Original['avdataoffset'] = $thisfile_avdataoffset;
     $Original['avdataend'] = $thisfile_avdataend;
     fseek($fd, $thisfile_avdataoffset, SEEK_SET);
     $RIFFheader = fread($fd, 12);
     $RIFFsubtype = substr($RIFFheader, 8, 4);
     switch (substr($RIFFheader, 0, 4)) {
         case 'FORM':
             $ThisFileInfo['fileformat'] = 'aiff';
             $RIFFheaderSize = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($RIFFheader, 4, 4));
             $thisfile_riff[$RIFFsubtype] = getid3_riff::ParseRIFF($fd, $thisfile_avdataoffset + 12, $thisfile_avdataoffset + $RIFFheaderSize, $ThisFileInfo);
             $thisfile_riff['header_size'] = $RIFFheaderSize;
             break;
         case 'RIFF':
         case 'SDSS':
             // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
         // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
         case 'RMP3':
             // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
             if ($RIFFsubtype == 'RMP3') {
                 // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
                 $RIFFsubtype = 'WAVE';
             }
             $ThisFileInfo['fileformat'] = 'riff';
             $RIFFheaderSize = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($RIFFheader, 4, 4));
             $thisfile_riff['header_size'] = $RIFFheaderSize;
             $thisfile_riff[$RIFFsubtype] = getid3_riff::ParseRIFF($fd, $thisfile_avdataoffset + 12, $thisfile_avdataoffset + $RIFFheaderSize, $ThisFileInfo);
             fseek($fd, $thisfile_avdataoffset + $RIFFheaderSize);
             $nextRIFFheader = fread($fd, 20);
             if (substr($nextRIFFheader, 8, 4) == 'RIFF') {
                 $nextRIFFsize = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($nextRIFFheader, 12, 4));
                 $nextRIFFtype = substr($nextRIFFheader, 16, 4) . '<br>';
                 $thisfile_riff[$nextRIFFtype]['offset'] = ftell($fd) - 4;
                 $thisfile_riff[$nextRIFFtype]['size'] = $nextRIFFsize;
                 $ThisFileInfo['avdataend'] = $thisfile_riff[$nextRIFFtype]['offset'] + $thisfile_riff[$nextRIFFtype]['size'];
                 $ThisFileInfo['error'][] = 'AVI extends beyond 2GB and PHP filesystem functions cannot read that far, playtime is probably wrong';
                 $ThisFileInfo['warning'][] = '[avdataend] value may be incorrect, multiple AVIX chunks may be present';
                 $thisfile_riff[$nextRIFFtype] = getid3_riff::ParseRIFF($fd, $thisfile_riff[$nextRIFFtype]['offset'] + 4, $thisfile_riff[$nextRIFFtype]['offset'] + $thisfile_riff[$nextRIFFtype]['size'], $ThisFileInfo);
             }
             if ($RIFFsubtype == 'WAVE') {
                 $thisfile_riff_WAVE =& $thisfile_riff['WAVE'];
             }
             break;
         default:
             $ThisFileInfo['error'][] = 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "' . $RIFFsubtype . '" instead';
             unset($ThisFileInfo['fileformat']);
             return false;
             break;
     }
     $streamindex = 0;
     switch ($RIFFsubtype) {
         case 'WAVE':
             if (empty($thisfile_audio['bitrate_mode'])) {
                 $thisfile_audio['bitrate_mode'] = 'cbr';
             }
             if (empty($thisfile_audio_dataformat)) {
                 $thisfile_audio_dataformat = 'wav';
             }
             if (isset($thisfile_riff_WAVE['data'][0]['offset'])) {
                 $thisfile_avdataoffset = $thisfile_riff_WAVE['data'][0]['offset'] + 8;
                 $thisfile_avdataend = $thisfile_avdataoffset + $thisfile_riff_WAVE['data'][0]['size'];
             }
             if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
                 $thisfile_riff_audio[$streamindex] = getid3_riff::RIFFparseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
                 $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
                 if (@$thisfile_riff_audio[$streamindex]['bitrate'] == 0) {
                     $ThisFileInfo['error'][] = 'Corrupt RIFF file: bitrate_audio == zero';
                     return false;
                 }
                 $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
                 unset($thisfile_riff_audio[$streamindex]['raw']);
                 $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
                 $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
                 if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
                     $ThisFileInfo['warning'][] = 'Audio codec = ' . $thisfile_audio['codec'];
                 }
                 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
                 $ThisFileInfo['playtime_seconds'] = (double) (($thisfile_avdataend - $thisfile_avdataoffset) * 8 / $thisfile_audio['bitrate']);
                 $thisfile_audio['lossless'] = false;
                 if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
                     switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
                         case 0x1:
                             // PCM
                             $thisfile_audio['lossless'] = true;
                             break;
                         case 0x2000:
                             // AC-3
                             $thisfile_audio_dataformat = 'ac3';
                             break;
                         default:
                             // do nothing
                             break;
                     }
                 }
                 $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag'];
                 $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
                 $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless'];
                 $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat;
             }
             if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
                 // shortcuts
                 $rgadData =& $thisfile_riff_WAVE['rgad'][0]['data'];
                 $thisfile_riff_raw['rgad'] = array('track' => array(), 'album' => array());
                 $thisfile_riff_raw_rgad =& $thisfile_riff_raw['rgad'];
                 $thisfile_riff_raw_rgad_track =& $thisfile_riff_raw_rgad['track'];
                 $thisfile_riff_raw_rgad_album =& $thisfile_riff_raw_rgad['album'];
                 $thisfile_riff_raw_rgad['fPeakAmplitude'] = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4));
                 $thisfile_riff_raw_rgad['nRadioRgAdjust'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($rgadData, 4, 2));
                 $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($rgadData, 6, 2));
                 $nRadioRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
                 $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
                 $thisfile_riff_raw_rgad_track['name'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
                 $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
                 $thisfile_riff_raw_rgad_track['signbit'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
                 $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
                 $thisfile_riff_raw_rgad_album['name'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
                 $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
                 $thisfile_riff_raw_rgad_album['signbit'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
                 $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
                 $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude'];
                 if ($thisfile_riff_raw_rgad_track['name'] != 0 && $thisfile_riff_raw_rgad_track['originator'] != 0) {
                     $thisfile_riff['rgad']['track']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']);
                     $thisfile_riff['rgad']['track']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']);
                     $thisfile_riff['rgad']['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']);
                 }
                 if ($thisfile_riff_raw_rgad_album['name'] != 0 && $thisfile_riff_raw_rgad_album['originator'] != 0) {
                     $thisfile_riff['rgad']['album']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']);
                     $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']);
                     $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']);
                 }
             }
             if (isset($thisfile_riff_WAVE['fact'][0]['data'])) {
                 $thisfile_riff_raw['fact']['NumberOfSamples'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4));
                 // This should be a good way of calculating exact playtime,
                 // but some sample files have had incorrect number of samples,
                 // so cannot use this method
                 // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
                 //     $ThisFileInfo['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
                 // }
             }
             if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
                 $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
             }
             if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_WAVE_bext_0 =& $thisfile_riff_WAVE['bext'][0];
                 $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256));
                 $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32));
                 $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32));
                 $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10);
                 $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8);
                 $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8));
                 $thisfile_riff_WAVE_bext_0['bwf_version'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1));
                 $thisfile_riff_WAVE_bext_0['reserved'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 347, 254));
                 $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
                 $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime((int) substr($thisfile_riff_WAVE_bext_0['origin_time'], 0, 2), (int) substr($thisfile_riff_WAVE_bext_0['origin_time'], 3, 2), (int) substr($thisfile_riff_WAVE_bext_0['origin_time'], 6, 2), (int) substr($thisfile_riff_WAVE_bext_0['origin_date'], 5, 2), (int) substr($thisfile_riff_WAVE_bext_0['origin_date'], 8, 2), (int) substr($thisfile_riff_WAVE_bext_0['origin_date'], 0, 4));
                 $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
                 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
             }
             if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_WAVE_MEXT_0 =& $thisfile_riff_WAVE['MEXT'][0];
                 $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2));
                 $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x1);
                 if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) {
                     $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x2 ? false : true;
                     $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x4);
                     $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x8);
                     $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
                 }
                 $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2));
                 $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2));
                 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x1);
                 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x2);
                 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x4);
             }
             if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_WAVE_cart_0 =& $thisfile_riff_WAVE['cart'][0];
                 $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4);
                 $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64));
                 $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64));
                 $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64));
                 $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64));
                 $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64));
                 $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64));
                 $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64));
                 $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10));
                 $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8));
                 $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10));
                 $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8));
                 $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64));
                 $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64));
                 $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64));
                 $thisfile_riff_WAVE_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true);
                 for ($i = 0; $i < 8; $i++) {
                     $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 + $i * 8, 4);
                     $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));
                 }
                 $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
                 $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
                 $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
                 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
             }
             if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
                 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
                 $ThisFileInfo['playtime_seconds'] = (double) (($thisfile_avdataend - $thisfile_avdataoffset) * 8 / $thisfile_audio['bitrate']);
             }
             if (!empty($ThisFileInfo['wavpack'])) {
                 $thisfile_audio_dataformat = 'wavpack';
                 $thisfile_audio['bitrate_mode'] = 'vbr';
                 $thisfile_audio['encoder'] = 'WavPack v' . $ThisFileInfo['wavpack']['version'];
                 // Reset to the way it was - RIFF parsing will have messed this up
                 $thisfile_avdataend = $Original['avdataend'];
                 $thisfile_audio['bitrate'] = ($thisfile_avdataend - $thisfile_avdataoffset) * 8 / $ThisFileInfo['playtime_seconds'];
                 fseek($fd, $thisfile_avdataoffset - 44, SEEK_SET);
                 $RIFFdata = fread($fd, 44);
                 $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
                 $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
                 if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
                     $thisfile_avdataend -= $OrignalRIFFheaderSize - $OrignalRIFFdataSize;
                     fseek($fd, $thisfile_avdataend, SEEK_SET);
                     $RIFFdata .= fread($fd, $OrignalRIFFheaderSize - $OrignalRIFFdataSize);
                 }
                 // move the data chunk after all other chunks (if any)
                 // so that the RIFF parser doesn't see EOF when trying
                 // to skip over the data chunk
                 $RIFFdata = substr($RIFFdata, 0, 36) . substr($RIFFdata, 44) . substr($RIFFdata, 36, 8);
                 getid3_riff::ParseRIFFdata($RIFFdata, $ThisFileInfo);
             }
             if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
                 switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
                     case 0x8ae:
                         // ClearJump LiteWave
                         $thisfile_audio['bitrate_mode'] = 'vbr';
                         $thisfile_audio_dataformat = 'litewave';
                         //typedef struct tagSLwFormat {
                         //  WORD    m_wCompFormat;     // low byte defines compression method, high byte is compression flags
                         //  DWORD   m_dwScale;         // scale factor for lossy compression
                         //  DWORD   m_dwBlockSize;     // number of samples in encoded blocks
                         //  WORD    m_wQuality;        // alias for the scale factor
                         //  WORD    m_wMarkDistance;   // distance between marks in bytes
                         //  WORD    m_wReserved;
                         //
                         //  //following paramters are ignored if CF_FILESRC is not set
                         //  DWORD   m_dwOrgSize;       // original file size in bytes
                         //  WORD    m_bFactExists;     // indicates if 'fact' chunk exists in the original file
                         //  DWORD   m_dwRiffChunkSize; // riff chunk size in the original file
                         //
                         //  PCMWAVEFORMAT m_OrgWf;     // original wave format
                         // }SLwFormat, *PSLwFormat;
                         // shortcut
                         $thisfile_riff['litewave']['raw'] = array();
                         $thisfile_riff_litewave =& $thisfile_riff['litewave'];
                         $thisfile_riff_litewave_raw =& $thisfile_riff_litewave['raw'];
                         $thisfile_riff_litewave_raw['compression_method'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 18, 1));
                         $thisfile_riff_litewave_raw['compression_flags'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 19, 1));
                         $thisfile_riff_litewave_raw['m_dwScale'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 20, 4));
                         $thisfile_riff_litewave_raw['m_dwBlockSize'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 24, 4));
                         $thisfile_riff_litewave_raw['m_wQuality'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 28, 2));
                         $thisfile_riff_litewave_raw['m_wMarkDistance'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 30, 2));
                         $thisfile_riff_litewave_raw['m_wReserved'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 32, 2));
                         $thisfile_riff_litewave_raw['m_dwOrgSize'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 34, 4));
                         $thisfile_riff_litewave_raw['m_bFactExists'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 38, 2));
                         $thisfile_riff_litewave_raw['m_dwRiffChunkSize'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 40, 4));
                         //$thisfile_riff_litewave['quality_factor'] = intval(round((2000 - $thisfile_riff_litewave_raw['m_dwScale']) / 20));
                         $thisfile_riff_litewave['quality_factor'] = $thisfile_riff_litewave_raw['m_wQuality'];
                         $thisfile_riff_litewave['flags']['raw_source'] = $thisfile_riff_litewave_raw['compression_flags'] & 0x1 ? false : true;
                         $thisfile_riff_litewave['flags']['vbr_blocksize'] = $thisfile_riff_litewave_raw['compression_flags'] & 0x2 ? false : true;
                         $thisfile_riff_litewave['flags']['seekpoints'] = (bool) ($thisfile_riff_litewave_raw['compression_flags'] & 0x4);
                         $thisfile_audio['lossless'] = $thisfile_riff_litewave_raw['m_wQuality'] == 100 ? true : false;
                         $thisfile_audio['encoder_options'] = '-q' . $thisfile_riff_litewave['quality_factor'];
                         break;
                     default:
                         break;
                 }
             }
             if ($thisfile_avdataend > $ThisFileInfo['filesize']) {
                 switch (@$thisfile_audio_dataformat) {
                     case 'wavpack':
                         // WavPack
                     // WavPack
                     case 'lpac':
                         // LPAC
                     // LPAC
                     case 'ofr':
                         // OptimFROG
                     // OptimFROG
                     case 'ofs':
                         // OptimFROG DualStream
                         // lossless compressed audio formats that keep original RIFF headers - skip warning
                         break;
                     case 'litewave':
                         if ($thisfile_avdataend - $ThisFileInfo['filesize'] == 1) {
                             // LiteWave appears to incorrectly *not* pad actual output file
                             // to nearest WORD boundary so may appear to be short by one
                             // byte, in which case - skip warning
                         } else {
                             // Short by more than one byte, throw warning
                             $ThisFileInfo['warning'][] = 'Probably truncated file - expecting ' . $thisfile_riff[$RIFFsubtype]['data'][0]['size'] . ' bytes of data, only found ' . ($ThisFileInfo['filesize'] - $thisfile_avdataoffset) . ' (short by ' . ($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($ThisFileInfo['filesize'] - $thisfile_avdataoffset)) . ' bytes)';
                             $thisfile_avdataend = $ThisFileInfo['filesize'];
                         }
                         break;
                     default:
                         if ($thisfile_avdataend - $ThisFileInfo['filesize'] == 1 && $thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2 == 0 && ($ThisFileInfo['filesize'] - $thisfile_avdataoffset) % 2 == 1) {
                             // output file appears to be incorrectly *not* padded to nearest WORD boundary
                             // Output less severe warning
                             $ThisFileInfo['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 ' . ($ThisFileInfo['filesize'] - $thisfile_avdataoffset) . ' therefore short by ' . ($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($ThisFileInfo['filesize'] - $thisfile_avdataoffset)) . ' bytes)';
                             $thisfile_avdataend = $ThisFileInfo['filesize'];
                             break;
                         }
                         // Short by more than one byte, throw warning
                         $ThisFileInfo['warning'][] = 'Probably truncated file - expecting ' . $thisfile_riff[$RIFFsubtype]['data'][0]['size'] . ' bytes of data, only found ' . ($ThisFileInfo['filesize'] - $thisfile_avdataoffset) . ' (short by ' . ($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($ThisFileInfo['filesize'] - $thisfile_avdataoffset)) . ' bytes)';
                         $thisfile_avdataend = $ThisFileInfo['filesize'];
                         break;
                 }
             }
             if (!empty($ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'])) {
                 if ($thisfile_avdataend - $thisfile_avdataoffset - $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] == 1) {
                     $thisfile_avdataend--;
                     $ThisFileInfo['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
                 }
             }
             if (@$thisfile_audio_dataformat == 'ac3') {
                 unset($thisfile_audio['bits_per_sample']);
                 if (!empty($ThisFileInfo['ac3']['bitrate']) && $ThisFileInfo['ac3']['bitrate'] != $thisfile_audio['bitrate']) {
                     $thisfile_audio['bitrate'] = $ThisFileInfo['ac3']['bitrate'];
                 }
             }
             break;
         case 'AVI ':
             $thisfile_video['bitrate_mode'] = 'vbr';
             // maybe not, but probably
             $thisfile_video['dataformat'] = 'avi';
             $ThisFileInfo['mime_type'] = 'video/avi';
             if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
                 $thisfile_avdataoffset = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
                 $thisfile_avdataend = $thisfile_avdataoffset + $thisfile_riff[$RIFFsubtype]['movi']['size'];
                 if ($thisfile_avdataend > $ThisFileInfo['filesize']) {
                     $ThisFileInfo['warning'][] = 'Probably truncated file - expecting ' . $thisfile_riff[$RIFFsubtype]['movi']['size'] . ' bytes of data, only found ' . ($ThisFileInfo['filesize'] - $thisfile_avdataoffset) . ' (short by ' . ($thisfile_riff[$RIFFsubtype]['movi']['size'] - ($ThisFileInfo['filesize'] - $thisfile_avdataoffset)) . ' bytes)';
                     $thisfile_avdataend = $ThisFileInfo['filesize'];
                 }
             }
             if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) {
                 //$bIndexType = array(
                 //	0x00 => 'AVI_INDEX_OF_INDEXES',
                 //	0x01 => 'AVI_INDEX_OF_CHUNKS',
                 //	0x80 => 'AVI_INDEX_IS_DATA',
                 //);
                 //$bIndexSubtype = array(
                 //	0x01 => array(
                 //		0x01 => 'AVI_INDEX_2FIELD',
                 //	),
                 //);
                 foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) {
                     $thisfile_riff_avi_hdrl_strl_indx_stream_data =& $thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data'];
                     $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 0, 2));
                     $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 2, 1));
                     $thisfile_riff_raw['indx'][$streamnumber]['bIndexType'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 3, 1));
                     $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 4, 4));
                     $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId'] = substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 8, 4);
                     $thisfile_riff_raw['indx'][$streamnumber]['dwReserved'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 12, 4));
                     //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name']    =    @$bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']];
                     //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = @$bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']];
                     unset($thisfile_riff_avi_hdrl_strl_indx_stream_data);
                 }
             }
             if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
                 $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
                 // shortcut
                 $thisfile_riff_raw['avih'] = array();
                 $thisfile_riff_raw_avih =& $thisfile_riff_raw['avih'];
                 $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 0, 4));
                 // frame display rate (or 0L)
                 if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
                     $ThisFileInfo['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
                     return false;
                 }
                 $thisfile_riff_raw_avih['dwMaxBytesPerSec'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 4, 4));
                 // max. transfer rate
                 $thisfile_riff_raw_avih['dwPaddingGranularity'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 8, 4));
                 // pad to multiples of this size; normally 2K.
                 $thisfile_riff_raw_avih['dwFlags'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 12, 4));
                 // the ever-present flags
                 $thisfile_riff_raw_avih['dwTotalFrames'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 16, 4));
                 // # frames in file
                 $thisfile_riff_raw_avih['dwInitialFrames'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 20, 4));
                 $thisfile_riff_raw_avih['dwStreams'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 24, 4));
                 $thisfile_riff_raw_avih['dwSuggestedBufferSize'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 28, 4));
                 $thisfile_riff_raw_avih['dwWidth'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 32, 4));
                 $thisfile_riff_raw_avih['dwHeight'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 36, 4));
                 $thisfile_riff_raw_avih['dwScale'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 40, 4));
                 $thisfile_riff_raw_avih['dwRate'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 44, 4));
                 $thisfile_riff_raw_avih['dwStart'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 48, 4));
                 $thisfile_riff_raw_avih['dwLength'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($avihData, 52, 4));
                 $thisfile_riff_raw_avih['flags']['hasindex'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x10);
                 $thisfile_riff_raw_avih['flags']['mustuseindex'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x20);
                 $thisfile_riff_raw_avih['flags']['interleaved'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x100);
                 $thisfile_riff_raw_avih['flags']['trustcktype'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x800);
                 $thisfile_riff_raw_avih['flags']['capturedfile'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x10000);
                 $thisfile_riff_raw_avih['flags']['copyrighted'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x20010);
                 // shortcut
                 $thisfile_riff_video[$streamindex] = array();
                 $thisfile_riff_video_current =& $thisfile_riff_video[$streamindex];
                 if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
                     $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
                     $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width'];
                 }
                 if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
                     $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
                     $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height'];
                 }
                 if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
                     $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
                     $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames'];
                 }
                 $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
                 $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate'];
             }
             if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
                 if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
                     for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
                         if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
                             $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
                             $strhfccType = substr($strhData, 0, 4);
                             if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
                                 $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
                                 // shortcut
                                 $thisfile_riff_raw_strf_strhfccType_streamindex =& $thisfile_riff_raw['strf'][$strhfccType][$streamindex];
                                 switch ($strhfccType) {
                                     case 'auds':
                                         $thisfile_audio['bitrate_mode'] = 'cbr';
                                         $thisfile_audio_dataformat = 'wav';
                                         if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) {
                                             $streamindex = count($thisfile_riff_audio);
                                         }
                                         $thisfile_riff_audio[$streamindex] = getid3_riff::RIFFparseWAVEFORMATex($strfData);
                                         $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
                                         // shortcut
                                         $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
                                         $thisfile_audio_streams_currentstream =& $thisfile_audio['streams'][$streamindex];
                                         if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
                                             unset($thisfile_audio_streams_currentstream['bits_per_sample']);
                                         }
                                         $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
                                         unset($thisfile_audio_streams_currentstream['raw']);
                                         // shortcut
                                         $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
                                         unset($thisfile_riff_audio[$streamindex]['raw']);
                                         $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
                                         $thisfile_audio['lossless'] = false;
                                         switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
                                             case 0x1:
                                                 // PCM
                                                 $thisfile_audio_dataformat = 'wav';
                                                 $thisfile_audio['lossless'] = true;
                                                 break;
                                             case 0x50:
                                                 // MPEG Layer 2 or Layer 1
                                                 $thisfile_audio_dataformat = 'mp2';
                                                 // Assume Layer-2
                                                 break;
                                             case 0x55:
                                                 // MPEG Layer 3
                                                 $thisfile_audio_dataformat = 'mp3';
                                                 break;
                                             case 0xff:
                                                 // AAC
                                                 $thisfile_audio_dataformat = 'aac';
                                                 break;
                                             case 0x161:
                                                 // Windows Media v7 / v8 / v9
                                             // Windows Media v7 / v8 / v9
                                             case 0x162:
                                                 // Windows Media Professional v9
                                             // Windows Media Professional v9
                                             case 0x163:
                                                 // Windows Media Lossess v9
                                                 $thisfile_audio_dataformat = 'wma';
                                                 break;
                                             case 0x2000:
                                                 // AC-3
                                                 $thisfile_audio_dataformat = 'ac3';
                                                 break;
                                             case 0x2001:
                                                 // DTS
                                                 $thisfile_audio_dataformat = 'dts';
                                                 break;
                                             default:
                                                 $thisfile_audio_dataformat = 'wav';
                                                 break;
                                         }
                                         $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat;
                                         $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless'];
                                         $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
                                         break;
                                     case 'iavs':
                                     case 'vids':
                                         // shortcut
                                         $thisfile_riff_raw['strh'][$i] = array();
                                         $thisfile_riff_raw_strh_current =& $thisfile_riff_raw['strh'][$i];
                                         $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4);
                                         // same as $strhfccType;
                                         $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4);
                                         $thisfile_riff_raw_strh_current['dwFlags'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 8, 4));
                                         // Contains AVITF_* flags
                                         $thisfile_riff_raw_strh_current['wPriority'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 12, 2));
                                         $thisfile_riff_raw_strh_current['wLanguage'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 14, 2));
                                         $thisfile_riff_raw_strh_current['dwInitialFrames'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 16, 4));
                                         $thisfile_riff_raw_strh_current['dwScale'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 20, 4));
                                         $thisfile_riff_raw_strh_current['dwRate'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 24, 4));
                                         $thisfile_riff_raw_strh_current['dwStart'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 28, 4));
                                         $thisfile_riff_raw_strh_current['dwLength'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 32, 4));
                                         $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 36, 4));
                                         $thisfile_riff_raw_strh_current['dwQuality'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 40, 4));
                                         $thisfile_riff_raw_strh_current['dwSampleSize'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 44, 4));
                                         $thisfile_riff_raw_strh_current['rcFrame'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strhData, 48, 4));
                                         $thisfile_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strh_current['fccHandler']);
                                         $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler'];
                                         if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
                                             $thisfile_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
                                             $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
                                         }
                                         $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
                                         $thisfile_video['pixel_aspect_ratio'] = (double) 1;
                                         switch ($thisfile_riff_raw_strh_current['fccHandler']) {
                                             case 'HFYU':
                                                 // Huffman Lossless Codec
                                             // Huffman Lossless Codec
                                             case 'IRAW':
                                                 // Intel YUV Uncompressed
                                             // Intel YUV Uncompressed
                                             case 'YUY2':
                                                 // Uncompressed YUV 4:2:2
                                                 $thisfile_video['lossless'] = true;
                                                 break;
                                             default:
                                                 $thisfile_video['lossless'] = false;
                                                 break;
                                         }
                                         switch ($strhfccType) {
                                             case 'vids':
                                                 $thisfile_riff_raw_strf_strhfccType_streamindex = getid3_riff::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), $ThisFileInfo['fileformat'] == 'riff');
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['biSize']          = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData,  0, 4)); // number of bytes required by the BITMAPINFOHEADER structure
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['biWidth']         = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData,  4, 4)); // width of the bitmap in pixels
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['biHeight']        = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData,  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
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['biPlanes']        = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 12, 2)); // number of color planes on the target device. In most cases this value must be set to 1
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount']      = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 14, 2)); // Specifies the number of bits per pixels
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']          =                                              substr($strfData, 16, 4);  //
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['biSizeImage']     = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 20, 4)); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['biXPelsPerMeter'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 24, 4)); // horizontal resolution, in pixels per metre, of the target device
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['biYPelsPerMeter'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 28, 4)); // vertical resolution, in pixels per metre, of the target device
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['biClrUsed']       = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 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
                                                 //$thisfile_riff_raw_strf_strhfccType_streamindex['biClrImportant']  = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($strfData, 36, 4)); // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
                                                 $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
                                                 if ($thisfile_riff_video_current['codec'] == 'DV') {
                                                     $thisfile_riff_video_current['dv_type'] = 2;
                                                 }
                                                 break;
                                             case 'iavs':
                                                 $thisfile_riff_video_current['dv_type'] = 1;
                                                 break;
                                         }
                                         break;
                                     default:
                                         $ThisFileInfo['warning'][] = 'Unhandled fccType for stream (' . $i . '): "' . $strhfccType . '"';
                                         break;
                                 }
                             }
                         }
                         if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
                             $thisfile_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
                             $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
                             $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
                             switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) {
                                 case 'HFYU':
                                     // Huffman Lossless Codec
                                 // Huffman Lossless Codec
                                 case 'IRAW':
                                     // Intel YUV Uncompressed
                                 // Intel YUV Uncompressed
                                 case 'YUY2':
                                     // Uncompressed YUV 4:2:2
                                     $thisfile_video['lossless'] = true;
                                     $thisfile_video['bits_per_sample'] = 24;
                                     break;
                                 default:
                                     $thisfile_video['lossless'] = false;
                                     $thisfile_video['bits_per_sample'] = 24;
                                     break;
                             }
                         }
                     }
                 }
             }
             break;
         case 'CDDA':
             $thisfile_audio['bitrate_mode'] = 'cbr';
             $thisfile_audio_dataformat = 'cda';
             $thisfile_audio['lossless'] = true;
             unset($ThisFileInfo['mime_type']);
             $thisfile_avdataoffset = 44;
             if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
                 // shortcut
                 $thisfile_riff_CDDA_fmt_0 =& $thisfile_riff['CDDA']['fmt '][0];
                 $thisfile_riff_CDDA_fmt_0['unknown1'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2));
                 $thisfile_riff_CDDA_fmt_0['track_num'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2));
                 $thisfile_riff_CDDA_fmt_0['disc_id'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4));
                 $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4));
                 $thisfile_riff_CDDA_fmt_0['playtime_frames'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4));
                 $thisfile_riff_CDDA_fmt_0['unknown6'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4));
                 $thisfile_riff_CDDA_fmt_0['unknown7'] = getid3_riff::EitherEndian2Int($ThisFileInfo, substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4));
                 $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (double) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
                 $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (double) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
                 $ThisFileInfo['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num'];
                 $ThisFileInfo['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
                 // hardcoded data for CD-audio
                 $thisfile_audio['sample_rate'] = 44100;
                 $thisfile_audio['channels'] = 2;
                 $thisfile_audio['bits_per_sample'] = 16;
                 $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
                 $thisfile_audio['bitrate_mode'] = 'cbr';
             }
             break;
         case 'AIFF':
         case 'AIFC':
             $thisfile_audio['bitrate_mode'] = 'cbr';
             $thisfile_audio_dataformat = 'aiff';
             $thisfile_audio['lossless'] = true;
             $ThisFileInfo['mime_type'] = 'audio/x-aiff';
             if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
                 $thisfile_avdataoffset = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
                 $thisfile_avdataend = $thisfile_avdataoffset + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
                 if ($thisfile_avdataend > $ThisFileInfo['filesize']) {
                     if ($thisfile_avdataend == $ThisFileInfo['filesize'] + 1 && $ThisFileInfo['filesize'] % 2 == 1) {
                         // structures rounded to 2-byte boundary, but dumb encoders
                         // forget to pad end of file to make this actually work
                     } else {
                         $ThisFileInfo['warning'][] = 'Probable truncated AIFF file: expecting ' . $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'] . ' bytes of audio data, only ' . ($ThisFileInfo['filesize'] - $thisfile_avdataoffset) . ' bytes found';
                     }
                     $thisfile_avdataend = $ThisFileInfo['filesize'];
                 }
             }
             if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_RIFFsubtype_COMM_0_data =& $thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
                 $thisfile_riff_audio['channels'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true);
                 $thisfile_riff_audio['total_samples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false);
                 $thisfile_riff_audio['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true);
                 $thisfile_riff_audio['sample_rate'] = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10));
                 if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) {
                     $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4);
                     $CodecNameSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false);
                     $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize);
                     switch ($thisfile_riff_audio['codec_name']) {
                         case 'NONE':
                             $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
                             $thisfile_audio['lossless'] = true;
                             break;
                         case '':
                             switch ($thisfile_riff_audio['codec_fourcc']) {
                                 // http://developer.apple.com/qa/snd/snd07.html
                                 case 'sowt':
                                     $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
                                     $thisfile_audio['lossless'] = true;
                                     break;
                                 case 'twos':
                                     $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
                                     $thisfile_audio['lossless'] = true;
                                     break;
                                 default:
                                     break;
                             }
                             break;
                         default:
                             $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name'];
                             $thisfile_audio['lossless'] = false;
                             break;
                     }
                 }
                 $thisfile_audio['channels'] = $thisfile_riff_audio['channels'];
                 if ($thisfile_riff_audio['bits_per_sample'] > 0) {
                     $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample'];
                 }
                 $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
                 if ($thisfile_audio['sample_rate'] == 0) {
                     $ThisFileInfo['error'][] = 'Corrupted AIFF file: sample_rate == zero';
                     return false;
                 }
                 $ThisFileInfo['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
             }
             if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
                 $offset = 0;
                 $CommentCount = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
                 $offset += 2;
                 for ($i = 0; $i < $CommentCount; $i++) {
                     $ThisFileInfo['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false);
                     $offset += 4;
                     $ThisFileInfo['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
                     $offset += 2;
                     $CommentLength = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
                     $offset += 2;
                     $ThisFileInfo['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
                     $offset += $CommentLength;
                     $ThisFileInfo['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($ThisFileInfo['comments_raw'][$i]['timestamp']);
                     $thisfile_riff['comments']['comment'][] = $ThisFileInfo['comments_raw'][$i]['comment'];
                 }
             }
             $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
             foreach ($CommentsChunkNames as $key => $value) {
                 if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
                     $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
                 }
             }
             break;
         case '8SVX':
             $thisfile_audio['bitrate_mode'] = 'cbr';
             $thisfile_audio_dataformat = '8svx';
             $thisfile_audio['bits_per_sample'] = 8;
             $thisfile_audio['channels'] = 1;
             // overridden below, if need be
             $ThisFileInfo['mime_type'] = 'audio/x-aiff';
             if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
                 $thisfile_avdataoffset = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
                 $thisfile_avdataend = $thisfile_avdataoffset + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
                 if ($thisfile_avdataend > $ThisFileInfo['filesize']) {
                     $ThisFileInfo['warning'][] = 'Probable truncated AIFF file: expecting ' . $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'] . ' bytes of audio data, only ' . ($ThisFileInfo['filesize'] - $thisfile_avdataoffset) . ' bytes found';
                 }
             }
             if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
                 // shortcut
                 $thisfile_riff_RIFFsubtype_VHDR_0 =& $thisfile_riff[$RIFFsubtype]['VHDR'][0];
                 $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4));
                 $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4));
                 $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4));
                 $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2));
                 $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1));
                 $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1));
                 $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4));
                 $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
                 switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
                     case 0:
                         $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
                         $thisfile_audio['lossless'] = true;
                         $ActualBitsPerSample = 8;
                         break;
                     case 1:
                         $thisfile_audio['codec'] = 'Fibonacci-delta encoding';
                         $thisfile_audio['lossless'] = false;
                         $ActualBitsPerSample = 4;
                         break;
                     default:
                         $ThisFileInfo['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "' . sCompression . '"';
                         break;
                 }
             }
             if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) {
                 $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4));
                 switch ($ChannelsIndex) {
                     case 6:
                         // Stereo
                         $thisfile_audio['channels'] = 2;
                         break;
                     case 2:
                         // Left channel only
                     // Left channel only
                     case 4:
                         // Right channel only
                         $thisfile_audio['channels'] = 1;
                         break;
                     default:
                         $ThisFileInfo['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "' . $ChannelsIndex . '"';
                         break;
                 }
             }
             $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
             foreach ($CommentsChunkNames as $key => $value) {
                 if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
                     $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
                 }
             }
             $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels'];
             if (!empty($thisfile_audio['bitrate'])) {
                 $ThisFileInfo['playtime_seconds'] = ($thisfile_avdataend - $thisfile_avdataoffset) / ($thisfile_audio['bitrate'] / 8);
             }
             break;
         case 'CDXA':
             $ThisFileInfo['mime_type'] = 'video/mpeg';
             if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
                 $GETID3_ERRORARRAY =& $ThisFileInfo['warning'];
                 if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio-video.mpeg.php', __FILE__, false)) {
                     $dummy = $ThisFileInfo;
                     $dummy['error'] = array();
                     $mpeg_scanner = new getid3_mpeg($fd, $dummy);
                     if (empty($dummy['error'])) {
                         $ThisFileInfo['audio'] = $dummy['audio'];
                         $ThisFileInfo['video'] = $dummy['video'];
                         $ThisFileInfo['mpeg'] = $dummy['mpeg'];
                         $ThisFileInfo['warning'] = $dummy['warning'];
                     }
                     unset($mpeg_scanner);
                 }
             }
             break;
         default:
             $ThisFileInfo['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "' . $RIFFsubtype . '" instead';
             unset($ThisFileInfo['fileformat']);
             break;
     }
     if (@$thisfile_riff_raw['fmt ']['wFormatTag'] == 1) {
         // http://www.mega-nerd.com/erikd/Blog/Windiots/dts.html
         fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
         $FirstFourBytes = fread($fd, 4);
         if (preg_match('/^\\xFF\\x1F\\x00\\xE8/s', $FirstFourBytes)) {
             // DTSWAV
             $thisfile_audio_dataformat = 'dts';
         } elseif (preg_match('/^\\x7F\\xFF\\x80\\x01/s', $FirstFourBytes)) {
             // DTS, but this probably shouldn't happen
             $thisfile_audio_dataformat = 'dts';
         }
     }
     if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) {
         $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4));
     }
     if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
         $this->RIFFcommentsParse($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
     }
     if (empty($thisfile_audio['encoder']) && !empty($ThisFileInfo['mpeg']['audio']['LAME']['short_version'])) {
         $thisfile_audio['encoder'] = $ThisFileInfo['mpeg']['audio']['LAME']['short_version'];
     }
     if (!isset($ThisFileInfo['playtime_seconds'])) {
         $ThisFileInfo['playtime_seconds'] = 0;
     }
     if (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
         $ThisFileInfo['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
     }
     if ($ThisFileInfo['playtime_seconds'] > 0) {
         if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
             if (!isset($ThisFileInfo['bitrate'])) {
                 $ThisFileInfo['bitrate'] = ($thisfile_avdataend - $thisfile_avdataoffset) / $ThisFileInfo['playtime_seconds'] * 8;
             }
         } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
             if (!isset($thisfile_audio['bitrate'])) {
                 $thisfile_audio['bitrate'] = ($thisfile_avdataend - $thisfile_avdataoffset) / $ThisFileInfo['playtime_seconds'] * 8;
             }
         } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
             if (!isset($thisfile_video['bitrate'])) {
                 $thisfile_video['bitrate'] = ($thisfile_avdataend - $thisfile_avdataoffset) / $ThisFileInfo['playtime_seconds'] * 8;
             }
         }
     }
     if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && $thisfile_audio['bitrate'] > 0 && $ThisFileInfo['playtime_seconds'] > 0) {
         $ThisFileInfo['bitrate'] = ($thisfile_avdataend - $thisfile_avdataoffset) / $ThisFileInfo['playtime_seconds'] * 8;
         $thisfile_audio['bitrate'] = 0;
         $thisfile_video['bitrate'] = $ThisFileInfo['bitrate'];
         foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) {
             $thisfile_video['bitrate'] -= $audioinfoarray['bitrate'];
             $thisfile_audio['bitrate'] += $audioinfoarray['bitrate'];
         }
         if ($thisfile_video['bitrate'] <= 0) {
             unset($thisfile_video['bitrate']);
         }
         if ($thisfile_audio['bitrate'] <= 0) {
             unset($thisfile_audio['bitrate']);
         }
     }
     if (isset($ThisFileInfo['mpeg']['audio'])) {
         $thisfile_audio_dataformat = 'mp' . $ThisFileInfo['mpeg']['audio']['layer'];
         $thisfile_audio['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
         $thisfile_audio['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
         $thisfile_audio['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'];
         $thisfile_audio['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitrate_mode']);
         if (!empty($ThisFileInfo['mpeg']['audio']['codec'])) {
             $thisfile_audio['codec'] = $ThisFileInfo['mpeg']['audio']['codec'] . ' ' . $thisfile_audio['codec'];
         }
         if (!empty($thisfile_audio['streams'])) {
             foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) {
                 if ($streamdata['dataformat'] == $thisfile_audio_dataformat) {
                     $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate'];
                     $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels'];
                     $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate'];
                     $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
                     $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec'];
                 }
             }
         }
         $thisfile_audio['encoder_options'] = getid3_mp3::GuessEncoderOptions($ThisFileInfo);
     }
     if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && $thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0) {
         switch ($thisfile_audio_dataformat) {
             case 'ac3':
                 // ignore bits_per_sample
                 break;
             default:
                 $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
                 break;
         }
     }
     if (empty($thisfile_riff_raw)) {
         unset($thisfile_riff['raw']);
     }
     if (empty($thisfile_riff_audio)) {
         unset($thisfile_riff['audio']);
     }
     if (empty($thisfile_riff_video)) {
         unset($thisfile_riff['video']);
     }
     return true;
 }
 function Analyze()
 {
     $info =& $this->getid3->info;
     // http://www.matroska.org/technical/specs/index.html#EBMLBasics
     $offset = $info['avdataoffset'];
     $EBMLdata = '';
     $EBMLdata_offset = $offset;
     if (!getid3_lib::intValueSupported($info['avdataend'])) {
         $this->warnings[] = 'This version of getID3() [' . $this->getid3->version() . '] may or may not correctly handle Matroska files larger than ' . round(PHP_INT_MAX / 1073741824) . 'GB';
     }
     while ($offset < $info['avdataend']) {
         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
         $top_element_offset = $offset;
         $top_element_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
         $top_element_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
         if ($top_element_length === false) {
             $this->warnings[] = 'invalid chunk length at ' . $top_element_offset;
             $offset = PHP_INT_MAX + 1;
             break;
         }
         $top_element_endoffset = $offset + $top_element_length;
         switch ($top_element_id) {
             case EBML_ID_EBML:
                 $info['fileformat'] = 'matroska';
                 $info['matroska']['header']['offset'] = $top_element_offset;
                 $info['matroska']['header']['length'] = $top_element_length;
                 while ($offset < $top_element_endoffset) {
                     $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                     $element_data = array();
                     $element_data_offset = $offset;
                     $element_data['id'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                     $element_data['id_name'] = $this->EBMLidName($element_data['id']);
                     $element_data['length'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                     $end_offset = $offset + $element_data['length'];
                     switch ($element_data['id']) {
                         case EBML_ID_VOID:
                             // padding, ignore
                             break;
                         case EBML_ID_EBMLVERSION:
                         case EBML_ID_EBMLREADVERSION:
                         case EBML_ID_EBMLMAXIDLENGTH:
                         case EBML_ID_EBMLMAXSIZELENGTH:
                         case EBML_ID_DOCTYPEVERSION:
                         case EBML_ID_DOCTYPEREADVERSION:
                             $element_data['data'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $element_data['length']));
                             break;
                         case EBML_ID_DOCTYPE:
                             $element_data['data'] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $element_data['length']), "");
                             break;
                         case EBML_ID_CRC32:
                             // probably not useful, ignore
                             unset($element_data);
                             break;
                         default:
                             $this->warnings[] = 'Unhandled track.video element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $element_data['id'] . '::' . $element_data['id_name'] . ') at ' . $element_data_offset;
                             break;
                     }
                     $offset = $end_offset;
                     if (!empty($element_data)) {
                         $info['matroska']['header']['elements'][] = $element_data;
                     }
                 }
                 break;
             case EBML_ID_SEGMENT:
                 $info['matroska']['segment'][0]['offset'] = $top_element_offset;
                 $info['matroska']['segment'][0]['length'] = $top_element_length;
                 $segment_key = -1;
                 while ($offset < $info['avdataend']) {
                     $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                     $element_data = array();
                     $element_data['offset'] = $offset;
                     $element_data['id'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                     $element_data['id_name'] = $this->EBMLidName($element_data['id']);
                     $element_data['length'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                     if ($element_data['length'] === false) {
                         $this->warnings[] = 'invalid chunk length at ' . $element_data['offset'];
                         //$offset = PHP_INT_MAX + 1;
                         $offset = $info['avdataend'];
                         break;
                     }
                     $element_end = $offset + $element_data['length'];
                     switch ($element_data['id']) {
                         //case EBML_ID_CLUSTER:
                         //	// too many cluster entries, probably not useful
                         //	break;
                         case false:
                             $this->warnings[] = 'invalid ID at ' . $element_data['offset'];
                             $offset = $element_end;
                             continue 3;
                         default:
                             $info['matroska']['segments'][] = $element_data;
                             break;
                     }
                     $segment_key++;
                     switch ($element_data['id']) {
                         case EBML_ID_SEEKHEAD:
                             // Contains the position of other level 1 elements
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                 $seek_entry = array();
                                 $seek_entry['offset'] = $offset;
                                 $seek_entry['id'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $seek_entry['id_name'] = $this->EBMLidName($seek_entry['id']);
                                 $seek_entry['length'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $seek_end_offset = $offset + $seek_entry['length'];
                                 switch ($seek_entry['id']) {
                                     case EBML_ID_SEEK:
                                         // Contains a single seek entry to an EBML element
                                         while ($offset < $seek_end_offset) {
                                             $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                             $id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $value = substr($EBMLdata, $offset - $EBMLdata_offset, $length);
                                             $offset += $length;
                                             switch ($id) {
                                                 case EBML_ID_SEEKID:
                                                     $dummy = 0;
                                                     $seek_entry['target_id'] = $this->readEBMLint($value, $dummy);
                                                     $seek_entry['target_name'] = $this->EBMLidName($seek_entry['target_id']);
                                                     break;
                                                 case EBML_ID_SEEKPOSITION:
                                                     $seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($value);
                                                     break;
                                                 case EBML_ID_CRC32:
                                                     // probably not useful, ignore
                                                     //$seek_entry['crc32'] = getid3_lib::PrintHexBytes($value, true, false, false);
                                                     unset($seek_entry);
                                                     break;
                                                 default:
                                                     $info['error'][] = 'Unhandled segment [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $id . ') at ' . $offset;
                                                     break;
                                             }
                                         }
                                         if (!empty($seek_entry)) {
                                             $info['matroska']['seek'][] = $seek_entry;
                                         }
                                         //switch ($seek_entry['target_id']) {
                                         //	case EBML_ID_CLUSTER:
                                         //		// too many cluster seek points, probably not useful
                                         //		break;
                                         //	default:
                                         //		$info['matroska']['seek'][] = $seek_entry;
                                         //		break;
                                         //}
                                         break;
                                     case EBML_ID_CRC32:
                                         // probably not useful, ignore
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled seekhead element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $seek_entry['id'] . '::' . $seek_entry['id_name'] . ') at ' . $offset;
                                         break;
                                 }
                                 $offset = $seek_end_offset;
                             }
                             break;
                         case EBML_ID_TRACKS:
                             // information about all tracks in segment
                             $info['matroska']['tracks'] = $element_data;
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                 $track_entry = array();
                                 $track_entry['offset'] = $offset;
                                 $track_entry['id'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $track_entry['id_name'] = $this->EBMLidName($track_entry['id']);
                                 $track_entry['length'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $track_entry_endoffset = $offset + $track_entry['length'];
                                 // $track_entry['offset'] is not the same as $offset, even though they were set equal a few lines up: $offset has been automagically incremented by readEMLint()
                                 switch ($track_entry['id']) {
                                     case EBML_ID_TRACKENTRY:
                                         //subelements: Describes a track with all elements.
                                         while ($offset < $track_entry_endoffset) {
                                             $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                             $subelement_offset = $offset;
                                             $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $subelement_idname = $this->EBMLidName($subelement_id);
                                             $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $subelement_end = $offset + $subelement_length;
                                             switch ($subelement_id) {
                                                 case EBML_ID_TRACKNUMBER:
                                                 case EBML_ID_TRACKUID:
                                                 case EBML_ID_TRACKTYPE:
                                                 case EBML_ID_MINCACHE:
                                                 case EBML_ID_MAXCACHE:
                                                 case EBML_ID_MAXBLOCKADDITIONID:
                                                 case EBML_ID_DEFAULTDURATION:
                                                     // nanoseconds per frame
                                                     $track_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                                     break;
                                                 case EBML_ID_TRACKTIMECODESCALE:
                                                     $track_entry[$subelement_idname] = getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                                     break;
                                                 case EBML_ID_CODECID:
                                                 case EBML_ID_LANGUAGE:
                                                 case EBML_ID_NAME:
                                                 case EBML_ID_CODECNAME:
                                                 case EBML_ID_CODECPRIVATE:
                                                     $track_entry[$subelement_idname] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "");
                                                     break;
                                                     // thought maybe it was a nice wFormatTag entry, but it's not :(
                                                     //case EBML_ID_CODECPRIVATE:
                                                     //$track_entry[$subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "\x00");
                                                     //if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
                                                     //	$track_entry[$subelement_idname.'_decoded'] = getid3_riff::RIFFparseWAVEFORMATex($track_entry[$subelement_idname]);
                                                     //	if (isset($track_entry[$subelement_idname.'_decoded']['raw']['wFormatTag'])) {
                                                     //	}
                                                     //} else {
                                                     //	$this->warnings[] = 'failed to include "module.audio-video.riff.php" for parsing codec private data';
                                                     //}
                                                     //break;
                                                 // thought maybe it was a nice wFormatTag entry, but it's not :(
                                                 //case EBML_ID_CODECPRIVATE:
                                                 //$track_entry[$subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "\x00");
                                                 //if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
                                                 //	$track_entry[$subelement_idname.'_decoded'] = getid3_riff::RIFFparseWAVEFORMATex($track_entry[$subelement_idname]);
                                                 //	if (isset($track_entry[$subelement_idname.'_decoded']['raw']['wFormatTag'])) {
                                                 //	}
                                                 //} else {
                                                 //	$this->warnings[] = 'failed to include "module.audio-video.riff.php" for parsing codec private data';
                                                 //}
                                                 //break;
                                                 case EBML_ID_FLAGENABLED:
                                                 case EBML_ID_FLAGDEFAULT:
                                                 case EBML_ID_FLAGFORCED:
                                                 case EBML_ID_FLAGLACING:
                                                 case EBML_ID_CODECDECODEALL:
                                                     $track_entry[$subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                                     break;
                                                 case EBML_ID_VIDEO:
                                                     while ($offset < $subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_offset = $offset;
                                                         $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                                         $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_end = $offset + $sub_subelement_length;
                                                         switch ($sub_subelement_id) {
                                                             case EBML_ID_PIXELWIDTH:
                                                             case EBML_ID_PIXELHEIGHT:
                                                             case EBML_ID_STEREOMODE:
                                                             case EBML_ID_PIXELCROPBOTTOM:
                                                             case EBML_ID_PIXELCROPTOP:
                                                             case EBML_ID_PIXELCROPLEFT:
                                                             case EBML_ID_PIXELCROPRIGHT:
                                                             case EBML_ID_DISPLAYWIDTH:
                                                             case EBML_ID_DISPLAYHEIGHT:
                                                             case EBML_ID_DISPLAYUNIT:
                                                             case EBML_ID_ASPECTRATIOTYPE:
                                                                 $track_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_FLAGINTERLACED:
                                                                 $track_entry[$sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_GAMMAVALUE:
                                                                 $track_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_COLOURSPACE:
                                                                 $track_entry[$sub_subelement_idname] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length), "");
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled track.video element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_subelement_end;
                                                     }
                                                     if (isset($track_entry[$this->EBMLidName(EBML_ID_CODECID)]) && $track_entry[$this->EBMLidName(EBML_ID_CODECID)] == 'V_MS/VFW/FOURCC' && isset($track_entry[$this->EBMLidName(EBML_ID_CODECPRIVATE)])) {
                                                         if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio-video.riff.php', __FILE__, false)) {
                                                             $track_entry['codec_private_parsed'] = getid3_riff::ParseBITMAPINFOHEADER($track_entry[$this->EBMLidName(EBML_ID_CODECPRIVATE)]);
                                                         } else {
                                                             $this->warnings[] = 'Unable to parse codec private data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio-video.riff.php"';
                                                         }
                                                     }
                                                     break;
                                                 case EBML_ID_AUDIO:
                                                     while ($offset < $subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_offset = $offset;
                                                         $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                                         $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_end = $offset + $sub_subelement_length;
                                                         switch ($sub_subelement_id) {
                                                             case EBML_ID_CHANNELS:
                                                             case EBML_ID_BITDEPTH:
                                                                 $track_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_SAMPLINGFREQUENCY:
                                                             case EBML_ID_OUTPUTSAMPLINGFREQUENCY:
                                                                 $track_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_CHANNELPOSITIONS:
                                                                 $track_entry[$sub_subelement_idname] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length), "");
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled track.audio element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_subelement_end;
                                                     }
                                                     break;
                                                 case EBML_ID_CONTENTENCODINGS:
                                                     while ($offset < $subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_offset = $offset;
                                                         $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                                         $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_end = $offset + $sub_subelement_length;
                                                         switch ($sub_subelement_id) {
                                                             case EBML_ID_CONTENTENCODING:
                                                                 while ($offset < $sub_subelement_end) {
                                                                     $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_subelement_offset = $offset;
                                                                     $sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                                     $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_subelement_end = $offset + $sub_sub_subelement_length;
                                                                     switch ($sub_sub_subelement_id) {
                                                                         case EBML_ID_CONTENTENCODINGORDER:
                                                                         case EBML_ID_CONTENTENCODINGSCOPE:
                                                                         case EBML_ID_CONTENTENCODINGTYPE:
                                                                             $track_entry[$sub_subelement_idname][$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                             break;
                                                                         case EBML_ID_CONTENTCOMPRESSION:
                                                                             while ($offset < $sub_sub_subelement_end) {
                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                                                 $sub_sub_sub_subelement_offset = $offset;
                                                                                 $sub_sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                                 $sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                                                 $sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                                 $sub_sub_sub_subelement_end = $offset + $sub_sub_sub_subelement_length;
                                                                                 switch ($sub_sub_sub_subelement_id) {
                                                                                     case EBML_ID_CONTENTCOMPALGO:
                                                                                         $track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length));
                                                                                         break;
                                                                                     case EBML_ID_CONTENTCOMPSETTINGS:
                                                                                         $track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length);
                                                                                         break;
                                                                                     default:
                                                                                         $this->warnings[] = 'Unhandled track.contentencodings.contentencoding.contentcompression element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                                                                         break;
                                                                                 }
                                                                                 $offset = $sub_sub_sub_subelement_end;
                                                                             }
                                                                             break;
                                                                         case EBML_ID_CONTENTENCRYPTION:
                                                                             while ($offset < $sub_sub_subelement_end) {
                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                                                 $sub_sub_sub_subelement_offset = $offset;
                                                                                 $sub_sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                                 $sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                                                 $sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                                 $sub_sub_sub_subelement_end = $offset + $sub_sub_sub_subelement_length;
                                                                                 switch ($sub_sub_sub_subelement_id) {
                                                                                     case EBML_ID_CONTENTENCALGO:
                                                                                     case EBML_ID_CONTENTSIGALGO:
                                                                                     case EBML_ID_CONTENTSIGHASHALGO:
                                                                                         $track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length));
                                                                                         break;
                                                                                     case EBML_ID_CONTENTENCKEYID:
                                                                                     case EBML_ID_CONTENTSIGNATURE:
                                                                                     case EBML_ID_CONTENTSIGKEYID:
                                                                                         $track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length);
                                                                                         break;
                                                                                     default:
                                                                                         $this->warnings[] = 'Unhandled track.contentencodings.contentencoding.contentcompression element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                                                                         break;
                                                                                 }
                                                                                 $offset = $sub_sub_sub_subelement_end;
                                                                             }
                                                                             break;
                                                                         default:
                                                                             $this->warnings[] = 'Unhandled track.contentencodings.contentencoding element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                                                             break;
                                                                     }
                                                                     $offset = $sub_sub_subelement_end;
                                                                 }
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled track.contentencodings element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_subelement_end;
                                                     }
                                                     break;
                                                 case EBML_ID_CRC32:
                                                     // probably not useful, ignore
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled track element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                                     break;
                                             }
                                             $offset = $subelement_end;
                                         }
                                         break;
                                     case EBML_ID_CRC32:
                                         // probably not useful, ignore
                                         $offset = $track_entry_endoffset;
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled track element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $track_entry['id'] . '::' . $track_entry['id_name'] . ') at ' . $track_entry['offset'];
                                         $offset = $track_entry_endoffset;
                                         break;
                                 }
                                 $info['matroska']['tracks']['tracks'][] = $track_entry;
                             }
                             break;
                         case EBML_ID_INFO:
                             // Contains the position of other level 1 elements
                             $info_entry = array();
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 switch ($subelement_id) {
                                     case EBML_ID_CHAPTERTRANSLATEEDITIONUID:
                                     case EBML_ID_CHAPTERTRANSLATECODEC:
                                     case EBML_ID_TIMECODESCALE:
                                         $info_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                         break;
                                     case EBML_ID_DURATION:
                                         $info_entry[$subelement_idname] = getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                         break;
                                     case EBML_ID_DATEUTC:
                                         $info_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                         $info_entry[$subelement_idname . '_unix'] = $this->EBMLdate2unix($info_entry[$subelement_idname]);
                                         break;
                                     case EBML_ID_SEGMENTUID:
                                     case EBML_ID_PREVUID:
                                     case EBML_ID_NEXTUID:
                                     case EBML_ID_SEGMENTFAMILY:
                                     case EBML_ID_CHAPTERTRANSLATEID:
                                         $info_entry[$subelement_idname] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "");
                                         break;
                                     case EBML_ID_SEGMENTFILENAME:
                                     case EBML_ID_PREVFILENAME:
                                     case EBML_ID_NEXTFILENAME:
                                     case EBML_ID_TITLE:
                                     case EBML_ID_MUXINGAPP:
                                     case EBML_ID_WRITINGAPP:
                                         $info_entry[$subelement_idname] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "");
                                         $info['matroska']['comments'][strtolower($subelement_idname)][] = $info_entry[$subelement_idname];
                                         break;
                                     case EBML_ID_CRC32:
                                         // probably not useful, ignore
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled info element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                         break;
                                 }
                                 $offset = $subelement_end;
                             }
                             $info['matroska']['info'][] = $info_entry;
                             break;
                         case EBML_ID_CUES:
                             $cues_entry = array();
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 switch ($subelement_id) {
                                     case EBML_ID_CUEPOINT:
                                         $cuepoint_entry = array();
                                         while ($offset < $subelement_end) {
                                             $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_offset = $offset;
                                             $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                             $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_end = $offset + $sub_subelement_length;
                                             switch ($sub_subelement_id) {
                                                 case EBML_ID_CUETRACKPOSITIONS:
                                                     while ($offset < $sub_subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_offset = $offset;
                                                         $sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                         $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_end = $offset + $sub_sub_subelement_length;
                                                         switch ($sub_sub_subelement_id) {
                                                             case EBML_ID_CUETRACK:
                                                                 $cuepoint_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled cues.cuepoint.cuetrackpositions element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_sub_subelement_id . '::' . $sub_sub_subelement_idname . ') at ' . $sub_sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_subelement_end;
                                                     }
                                                     break;
                                                 case EBML_ID_CUETIME:
                                                     $cuepoint_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled cues.cuepoint element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                     break;
                                             }
                                             $offset = $sub_subelement_end;
                                         }
                                         $cues_entry[] = $cuepoint_entry;
                                         $offset = $sub_subelement_end;
                                         break;
                                     case EBML_ID_CRC32:
                                         // probably not useful, ignore
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled cues element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                         break;
                                 }
                                 $offset = $subelement_end;
                             }
                             $info['matroska']['cues'] = $cues_entry;
                             break;
                         case EBML_ID_TAGS:
                             $tags_entry = array();
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 $tag_entry = array();
                                 switch ($subelement_id) {
                                     case EBML_ID_WRITINGAPP:
                                         $tag_entry[$subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length);
                                         break;
                                     case EBML_ID_TAG:
                                         while ($offset < $subelement_end) {
                                             $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_offset = $offset;
                                             $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                             $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_end = $offset + $sub_subelement_length;
                                             switch ($sub_subelement_id) {
                                                 case EBML_ID_TARGETS:
                                                     $targets_entry = array();
                                                     while ($offset < $sub_subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_offset = $offset;
                                                         $sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                         $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_end = $offset + $sub_sub_subelement_length;
                                                         switch ($sub_sub_subelement_id) {
                                                             case EBML_ID_TARGETTYPEVALUE:
                                                                 $targets_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                 $targets_entry[strtolower($sub_sub_subelement_idname) . '_long'] = $this->MatroskaTargetTypeValue($targets_entry[$sub_sub_subelement_idname]);
                                                                 break;
                                                             case EBML_ID_EDITIONUID:
                                                             case EBML_ID_CHAPTERUID:
                                                             case EBML_ID_ATTACHMENTUID:
                                                             case EBML_ID_TAGTRACKUID:
                                                             case EBML_ID_TAGCHAPTERUID:
                                                                 $targets_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled tag.targets element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_sub_subelement_id . '::' . $sub_sub_subelement_idname . ') at ' . $sub_sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_sub_subelement_end;
                                                     }
                                                     $tag_entry[$sub_subelement_idname][] = $targets_entry;
                                                     break;
                                                 case EBML_ID_SIMPLETAG:
                                                     //$tag_entry[$sub_subelement_idname][] = $simpletag_entry;
                                                     $tag_entry[$sub_subelement_idname][] = $this->Handle_EMBL_ID_SIMPLETAG($offset, $sub_subelement_end);
                                                     break;
                                                 case EBML_ID_TARGETTYPE:
                                                     $tag_entry[$sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
                                                     break;
                                                 case EBML_ID_TRACKUID:
                                                     $tag_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled tags.tag element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                     break;
                                             }
                                             $offset = $sub_subelement_end;
                                         }
                                         $offset = $sub_subelement_end;
                                         break;
                                     case EBML_ID_CRC32:
                                         // probably not useful, ignore
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled tags element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                         break;
                                 }
                                 $tags_entry['tags'][] = $tag_entry;
                                 $offset = $subelement_end;
                             }
                             $info['matroska']['tags'] = $tags_entry['tags'];
                             break;
                         case EBML_ID_ATTACHMENTS:
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 switch ($subelement_id) {
                                     case EBML_ID_ATTACHEDFILE:
                                         $attachedfile_entry = array();
                                         while ($offset < $subelement_end) {
                                             $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_offset = $offset;
                                             $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                             $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_end = $offset + $sub_subelement_length;
                                             switch ($sub_subelement_id) {
                                                 case EBML_ID_FILEDESCRIPTION:
                                                 case EBML_ID_FILENAME:
                                                 case EBML_ID_FILEMIMETYPE:
                                                     $attachedfile_entry[$sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
                                                     break;
                                                 case EBML_ID_FILEDATA:
                                                     $attachedfile_entry['data_offset'] = $offset;
                                                     $attachedfile_entry['data_length'] = $sub_subelement_length;
                                                     do {
                                                         if ($this->inline_attachments === false) {
                                                             // skip entirely
                                                             break;
                                                         }
                                                         if ($this->inline_attachments === true) {
                                                             // great
                                                         } elseif (is_int($this->inline_attachments)) {
                                                             if ($this->inline_attachments < $sub_subelement_length) {
                                                                 // too big, skip
                                                                 $this->warnings[] = 'attachment at ' . $sub_subelement_offset . ' is too large to process inline (' . number_format($sub_subelement_length) . ' bytes)';
                                                                 break;
                                                             }
                                                         } elseif (is_string($this->inline_attachments)) {
                                                             $this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR);
                                                             if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) {
                                                                 // cannot write, skip
                                                                 $this->warnings[] = 'attachment at ' . $sub_subelement_offset . ' cannot be saved to "' . $this->inline_attachments . '" (not writable)';
                                                                 break;
                                                             }
                                                         }
                                                         // if we get this far, must be OK
                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset, $sub_subelement_length);
                                                         $attachedfile_entry[$sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
                                                         if (is_string($this->inline_attachments)) {
                                                             $destination_filename = $this->inline_attachments . DIRECTORY_SEPARATOR . md5($info['filenamepath']) . '_' . $attachedfile_entry['data_offset'];
                                                             if (!file_exists($destination_filename) || is_writable($destination_filename)) {
                                                                 file_put_contents($destination_filename, $attachedfile_entry[$sub_subelement_idname]);
                                                             } else {
                                                                 $this->warnings[] = 'attachment at ' . $sub_subelement_offset . ' cannot be saved to "' . $destination_filename . '" (not writable)';
                                                             }
                                                             $attachedfile_entry[$sub_subelement_idname . '_filename'] = $destination_filename;
                                                             unset($attachedfile_entry[$sub_subelement_idname]);
                                                         }
                                                     } while (false);
                                                     break;
                                                 case EBML_ID_FILEUID:
                                                     $attachedfile_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled attachment.attachedfile element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                     break;
                                             }
                                             $offset = $sub_subelement_end;
                                         }
                                         if (!empty($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)]) && !empty($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)]) && preg_match('#^image/#i', $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)])) {
                                             if ($this->inline_attachments === true || is_int($this->inline_attachments) && $this->inline_attachments >= strlen($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)])) {
                                                 $attachedfile_entry['data'] = $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)];
                                                 $attachedfile_entry['image_mime'] = $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)];
                                                 $info['matroska']['comments']['picture'][] = array('data' => $attachedfile_entry['data'], 'image_mime' => $attachedfile_entry['image_mime'], 'filename' => !empty($attachedfile_entry[$this->EBMLidName(EBML_ID_FILENAME)]) ? $attachedfile_entry[$this->EBMLidName(EBML_ID_FILENAME)] : '');
                                                 unset($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)], $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)]);
                                             }
                                         }
                                         if (!empty($attachedfile_entry['image_mime']) && preg_match('#^image/#i', $attachedfile_entry['image_mime'])) {
                                             // don't add a second copy of attached images, which are grouped under the standard location [comments][picture]
                                         } else {
                                             $info['matroska']['attachments'][] = $attachedfile_entry;
                                         }
                                         $offset = $sub_subelement_end;
                                         break;
                                     case EBML_ID_CRC32:
                                         // probably not useful, ignore
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled tags element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                         break;
                                 }
                                 $offset = $subelement_end;
                             }
                             break;
                         case EBML_ID_CHAPTERS:
                             // not important to us, contains mostly actual audio/video data, ignore
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 switch ($subelement_id) {
                                     case EBML_ID_EDITIONENTRY:
                                         $editionentry_entry = array();
                                         while ($offset < $subelement_end) {
                                             $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_offset = $offset;
                                             $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                             $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_end = $offset + $sub_subelement_length;
                                             switch ($sub_subelement_id) {
                                                 case EBML_ID_EDITIONUID:
                                                     $editionentry_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 case EBML_ID_EDITIONFLAGHIDDEN:
                                                 case EBML_ID_EDITIONFLAGDEFAULT:
                                                 case EBML_ID_EDITIONFLAGORDERED:
                                                     $editionentry_entry[$sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 case EBML_ID_CHAPTERATOM:
                                                     $chapteratom_entry = array();
                                                     while ($offset < $sub_subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_offset = $offset;
                                                         $sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                         $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_end = $offset + $sub_sub_subelement_length;
                                                         switch ($sub_sub_subelement_id) {
                                                             case EBML_ID_CHAPTERSEGMENTUID:
                                                             case EBML_ID_CHAPTERSEGMENTEDITIONUID:
                                                                 $chapteratom_entry[$sub_sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length);
                                                                 break;
                                                             case EBML_ID_CHAPTERFLAGENABLED:
                                                             case EBML_ID_CHAPTERFLAGHIDDEN:
                                                                 $chapteratom_entry[$sub_sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_CHAPTERUID:
                                                             case EBML_ID_CHAPTERTIMESTART:
                                                             case EBML_ID_CHAPTERTIMEEND:
                                                                 $chapteratom_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_CHAPTERTRACK:
                                                                 $chaptertrack_entry = array();
                                                                 while ($offset < $sub_sub_subelement_end) {
                                                                     $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_offset = $offset;
                                                                     $sub_sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                                     $sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_end = $offset + $sub_sub_sub_subelement_length;
                                                                     switch ($sub_sub_sub_subelement_id) {
                                                                         case EBML_ID_CHAPTERTRACKNUMBER:
                                                                             $chaptertrack_entry[$sub_sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length));
                                                                             break;
                                                                         default:
                                                                             $this->warnings[] = 'Unhandled chapters.editionentry.chapteratom.chaptertrack element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_sub_sub_subelement_id . '::' . $sub_sub_sub_subelement_idname . ') at ' . $sub_sub_sub_subelement_offset;
                                                                             break;
                                                                     }
                                                                     $offset = $sub_sub_sub_subelement_end;
                                                                 }
                                                                 $chapteratom_entry[$sub_sub_subelement_idname][] = $chaptertrack_entry;
                                                                 break;
                                                             case EBML_ID_CHAPTERDISPLAY:
                                                                 $chapterdisplay_entry = array();
                                                                 while ($offset < $sub_sub_subelement_end) {
                                                                     $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_offset = $offset;
                                                                     $sub_sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_sub_subelement_id);
                                                                     $sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_end = $offset + $sub_sub_sub_subelement_length;
                                                                     switch ($sub_sub_sub_subelement_id) {
                                                                         case EBML_ID_CHAPSTRING:
                                                                         case EBML_ID_CHAPLANGUAGE:
                                                                         case EBML_ID_CHAPCOUNTRY:
                                                                             $chapterdisplay_entry[$sub_sub_sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length);
                                                                             break;
                                                                         default:
                                                                             $this->warnings[] = 'Unhandled chapters.editionentry.chapteratom.chapterdisplay element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_sub_sub_subelement_id . '::' . $sub_sub_sub_subelement_idname . ') at ' . $sub_sub_sub_subelement_offset;
                                                                             break;
                                                                     }
                                                                     $offset = $sub_sub_sub_subelement_end;
                                                                 }
                                                                 $chapteratom_entry[$sub_sub_subelement_idname][] = $chapterdisplay_entry;
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled chapters.editionentry.chapteratom element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_sub_subelement_id . '::' . $sub_sub_subelement_idname . ') at ' . $sub_sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_sub_subelement_end;
                                                     }
                                                     $editionentry_entry[$sub_subelement_idname][] = $chapteratom_entry;
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled chapters.editionentry element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                     break;
                                             }
                                             $offset = $sub_subelement_end;
                                         }
                                         $info['matroska']['chapters'][] = $editionentry_entry;
                                         $offset = $sub_subelement_end;
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled chapters element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                         break;
                                 }
                                 $offset = $subelement_end;
                             }
                             break;
                         case EBML_ID_VOID:
                             // padding, ignore
                             $void_entry = array();
                             $void_entry['offset'] = $offset;
                             $info['matroska']['void'][] = $void_entry;
                             break;
                         case EBML_ID_CLUSTER:
                             // not important to us, contains mostly actual audio/video data, ignore
                             $cluster_entry = array();
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 switch ($subelement_id) {
                                     case EBML_ID_CLUSTERTIMECODE:
                                     case EBML_ID_CLUSTERPOSITION:
                                     case EBML_ID_CLUSTERPREVSIZE:
                                         $cluster_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                         break;
                                     case EBML_ID_CLUSTERSILENTTRACKS:
                                         $cluster_silent_tracks = array();
                                         while ($offset < $subelement_end) {
                                             $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_offset = $offset;
                                             $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                             $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_end = $offset + $sub_subelement_length;
                                             switch ($sub_subelement_id) {
                                                 case EBML_ID_CLUSTERSILENTTRACKNUMBER:
                                                     $cluster_silent_tracks[] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled clusters.silenttracks element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                     break;
                                             }
                                             $offset = $sub_subelement_end;
                                         }
                                         $cluster_entry[$subelement_idname][] = $cluster_silent_tracks;
                                         $offset = $sub_subelement_end;
                                         break;
                                     case EBML_ID_CLUSTERBLOCKGROUP:
                                         $cluster_block_group = array('offset' => $offset);
                                         while ($offset < $subelement_end) {
                                             $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_offset = $offset;
                                             $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                             $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_end = $offset + $sub_subelement_length;
                                             switch ($sub_subelement_id) {
                                                 case EBML_ID_CLUSTERBLOCK:
                                                     $cluster_block_data = array();
                                                     $cluster_block_data['tracknumber'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                     $cluster_block_data['timecode'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 2));
                                                     $offset += 2;
                                                     // unsure whether this is 1 octect or 2 octets? (http://matroska.org/technical/specs/index.html#block_structure)
                                                     $cluster_block_data['flags_raw'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
                                                     $offset += 1;
                                                     //$cluster_block_data['flags']['reserved1'] =      (($cluster_block_data['flags_raw'] & 0xF0) >> 4);
                                                     $cluster_block_data['flags']['invisible'] = (bool) (($cluster_block_data['flags_raw'] & 0x8) >> 3);
                                                     $cluster_block_data['flags']['lacing'] = ($cluster_block_data['flags_raw'] & 0x6) >> 1;
                                                     //$cluster_block_data['flags']['reserved2'] =      (($cluster_block_data['flags_raw'] & 0x01) >> 0);
                                                     $cluster_block_data['flags']['lacing_type'] = $this->MatroskaBlockLacingType($cluster_block_data['flags']['lacing']);
                                                     if ($cluster_block_data['flags']['lacing'] != 0) {
                                                         $cluster_block_data['lace_frames'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
                                                         // Number of frames in the lace-1 (uint8)
                                                         $offset += 1;
                                                         if ($cluster_block_data['flags']['lacing'] != 2) {
                                                             $cluster_block_data['lace_frames'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
                                                             // Lace-coded size of each frame of the lace, except for the last one (multiple uint8). *This is not used with Fixed-size lacing as it is calculated automatically from (total size of lace) / (number of frames in lace).
                                                             $offset += 1;
                                                         }
                                                     }
                                                     if (!isset($info['matroska']['track_data_offsets'][$cluster_block_data['tracknumber']])) {
                                                         $info['matroska']['track_data_offsets'][$cluster_block_data['tracknumber']]['offset'] = $offset;
                                                         $info['matroska']['track_data_offsets'][$cluster_block_data['tracknumber']]['length'] = $subelement_length;
                                                     }
                                                     $cluster_block_group[$sub_subelement_idname] = $cluster_block_data;
                                                     break;
                                                 case EBML_ID_CLUSTERREFERENCEPRIORITY:
                                                     // unsigned-int
                                                 // unsigned-int
                                                 case EBML_ID_CLUSTERBLOCKDURATION:
                                                     // unsigned-int
                                                     $cluster_block_group[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 case EBML_ID_CLUSTERREFERENCEBLOCK:
                                                     // signed-int
                                                     $cluster_block_group[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length), false, true);
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled clusters.blockgroup element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                     break;
                                             }
                                             $offset = $sub_subelement_end;
                                         }
                                         $cluster_entry[$subelement_idname][] = $cluster_block_group;
                                         $offset = $sub_subelement_end;
                                         break;
                                     case EBML_ID_CLUSTERSIMPLEBLOCK:
                                         // http://www.matroska.org/technical/specs/index.html#simpleblock_structure
                                         $cluster_block_data = array();
                                         $cluster_block_data['tracknumber'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                         $cluster_block_data['timecode'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 2));
                                         $offset += 2;
                                         $cluster_block_data['flags_raw'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
                                         $offset += 1;
                                         $cluster_block_data['flags']['keyframe'] = ($cluster_block_data['flags_raw'] & 0x80) >> 7;
                                         $cluster_block_data['flags']['reserved1'] = ($cluster_block_data['flags_raw'] & 0x70) >> 4;
                                         $cluster_block_data['flags']['invisible'] = ($cluster_block_data['flags_raw'] & 0x8) >> 3;
                                         $cluster_block_data['flags']['lacing'] = ($cluster_block_data['flags_raw'] & 0x6) >> 1;
                                         // 00=no lacing; 01=Xiph lacing; 11=EBML lacing; 10=fixed-size lacing
                                         $cluster_block_data['flags']['discardable'] = $cluster_block_data['flags_raw'] & 0x1;
                                         if ($cluster_block_data['flags']['lacing'] > 0) {
                                             $cluster_block_data['lace_frames'] = 1 + getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
                                             $offset += 1;
                                             if ($cluster_block_data['flags']['lacing'] != 0x2) {
                                                 // *This is not used with Fixed-size lacing as it is calculated automatically from (total size of lace) / (number of frames in lace).
                                                 $cluster_block_data['lace_frame_size'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
                                                 $offset += 1;
                                             }
                                         }
                                         if (!isset($info['matroska']['track_data_offsets'][$cluster_block_data['tracknumber']])) {
                                             $info['matroska']['track_data_offsets'][$cluster_block_data['tracknumber']]['offset'] = $offset;
                                             $info['matroska']['track_data_offsets'][$cluster_block_data['tracknumber']]['length'] = $subelement_length;
                                         }
                                         $cluster_block_group[$sub_subelement_idname] = $cluster_block_data;
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled cluster element [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ' [' . $subelement_length . ' bytes]) at ' . $subelement_offset;
                                         break;
                                 }
                                 $offset = $subelement_end;
                             }
                             $info['matroska']['cluster'][] = $cluster_entry;
                             // check to see if all the data we need exists already, if so, break out of the loop
                             if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
                                 if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
                                     break 2;
                                 }
                             }
                             break;
                         default:
                             if ($element_data['id_name'] == dechex($element_data['id'])) {
                                 $info['error'][] = 'Unhandled segment [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $element_data['id'] . ') at ' . $element_data_offset;
                             } else {
                                 $this->warnings[] = 'Unhandled segment [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $element_data['id'] . '::' . $element_data['id_name'] . ') at ' . $element_data['offset'];
                             }
                             break;
                     }
                     $offset = $element_end;
                 }
                 break;
             default:
                 $info['error'][] = 'Unhandled chunk [' . basename(__FILE__) . ':' . __LINE__ . '] (' . $top_element_id . ') at ' . $offset;
                 break;
         }
         $offset = $top_element_endoffset;
     }
     if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
         foreach ($info['matroska']['info'] as $key => $infoarray) {
             if (isset($infoarray['Duration'])) {
                 // TimecodeScale is how many nanoseconds each Duration unit is
                 $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000);
                 break;
             }
         }
     }
     if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) {
         foreach ($info['matroska']['tags'] as $key => $infoarray) {
             $this->ExtractCommentsSimpleTag($infoarray);
         }
     }
     if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
         foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) {
             $track_info = array();
             if (isset($trackarray['FlagDefault'])) {
                 $track_info['default'] = $trackarray['FlagDefault'];
             }
             switch (isset($trackarray['TrackType']) ? $trackarray['TrackType'] : '') {
                 case 1:
                     // Video
                     if (!empty($trackarray['PixelWidth'])) {
                         $track_info['resolution_x'] = $trackarray['PixelWidth'];
                     }
                     if (!empty($trackarray['PixelHeight'])) {
                         $track_info['resolution_y'] = $trackarray['PixelHeight'];
                     }
                     if (!empty($trackarray['DisplayWidth'])) {
                         $track_info['display_x'] = $trackarray['DisplayWidth'];
                     }
                     if (!empty($trackarray['DisplayHeight'])) {
                         $track_info['display_y'] = $trackarray['DisplayHeight'];
                     }
                     if (!empty($trackarray['DefaultDuration'])) {
                         $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3);
                     }
                     if (!empty($trackarray['CodecID'])) {
                         $track_info['dataformat'] = $this->MatroskaCodecIDtoCommonName($trackarray['CodecID']);
                     }
                     if (!empty($trackarray['codec_private_parsed']['fourcc'])) {
                         $track_info['fourcc'] = $trackarray['codec_private_parsed']['fourcc'];
                     }
                     $info['video']['streams'][] = $track_info;
                     if (isset($track_info['resolution_x']) && empty($info['video']['resolution_x'])) {
                         foreach ($track_info as $key => $value) {
                             $info['video'][$key] = $value;
                         }
                     }
                     break;
                 case 2:
                     // Audio
                     if (!empty($trackarray['CodecID'])) {
                         $track_info['dataformat'] = $this->MatroskaCodecIDtoCommonName($trackarray['CodecID']);
                     }
                     if (!empty($trackarray['SamplingFrequency'])) {
                         $track_info['sample_rate'] = $trackarray['SamplingFrequency'];
                     }
                     if (!empty($trackarray['Channels'])) {
                         $track_info['channels'] = $trackarray['Channels'];
                     }
                     if (!empty($trackarray['BitDepth'])) {
                         $track_info['bits_per_sample'] = $trackarray['BitDepth'];
                     }
                     if (!empty($trackarray['Language'])) {
                         $track_info['language'] = $trackarray['Language'];
                     }
                     switch (isset($trackarray[$this->EBMLidName(EBML_ID_CODECID)]) ? $trackarray[$this->EBMLidName(EBML_ID_CODECID)] : '') {
                         case 'A_PCM/INT/LIT':
                         case 'A_PCM/INT/BIG':
                             $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
                             break;
                         case 'A_AC3':
                             if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio.ac3.php', __FILE__, false)) {
                                 if (isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'])) {
                                     $getid3_temp = new getID3();
                                     $getid3_temp->openfile($this->getid3->filename);
                                     $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
                                     $getid3_ac3 = new getid3_ac3($getid3_temp);
                                     $getid3_ac3->Analyze();
                                     unset($getid3_temp->info['ac3']['GETID3_VERSION']);
                                     $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ac3'];
                                     if (!empty($getid3_temp->info['error'])) {
                                         foreach ($getid3_temp->info['error'] as $newerror) {
                                             $this->warnings[] = 'getid3_ac3() says: [' . $newerror . ']';
                                         }
                                     }
                                     if (!empty($getid3_temp->info['warning'])) {
                                         foreach ($getid3_temp->info['warning'] as $newerror) {
                                             $this->warnings[] = 'getid3_ac3() says: [' . $newerror . ']';
                                         }
                                     }
                                     if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
                                         foreach ($getid3_temp->info['audio'] as $key => $value) {
                                             $track_info[$key] = $value;
                                         }
                                     }
                                     unset($getid3_temp, $getid3_ac3);
                                 } else {
                                     $this->warnings[] = 'Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because $info[matroska][track_data_offsets][' . $trackarray['TrackNumber'] . '][offset] not set';
                                 }
                             } else {
                                 $this->warnings[] = 'Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio.ac3.php"';
                             }
                             break;
                         case 'A_DTS':
                             $dts_offset = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
                             // this is a NASTY hack, but sometimes audio data is off by a byte or two and not sure why, email info@getid3.org if you can explain better
                             fseek($this->getid3->fp, $dts_offset, SEEK_SET);
                             $magic_test = fread($this->getid3->fp, 8);
                             for ($i = 0; $i < 4; $i++) {
                                 // look to see if DTS "magic" is here, if so adjust offset by that many bytes
                                 if (substr($magic_test, $i, 4) == "þ€") {
                                     $dts_offset += $i;
                                     break;
                                 }
                             }
                             if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio.dts.php', __FILE__, false)) {
                                 $getid3_temp = new getID3();
                                 $getid3_temp->openfile($this->getid3->filename);
                                 $getid3_temp->info['avdataoffset'] = $dts_offset;
                                 $getid3_dts = new getid3_dts($getid3_temp);
                                 $getid3_dts->Analyze();
                                 unset($getid3_temp->info['dts']['GETID3_VERSION']);
                                 $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['dts'];
                                 if (!empty($getid3_temp->info['error'])) {
                                     foreach ($getid3_temp->info['error'] as $newerror) {
                                         $this->warnings[] = 'getid3_dts() says: [' . $newerror . ']';
                                     }
                                 }
                                 if (!empty($getid3_temp->info['warning'])) {
                                     foreach ($getid3_temp->info['warning'] as $newerror) {
                                         $this->warnings[] = 'getid3_dts() says: [' . $newerror . ']';
                                     }
                                 }
                                 if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
                                     foreach ($getid3_temp->info['audio'] as $key => $value) {
                                         $track_info[$key] = $value;
                                     }
                                 }
                                 unset($getid3_temp, $getid3_dts);
                             } else {
                                 $this->warnings[] = 'Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio.dts.php"';
                             }
                             break;
                         case 'A_AAC':
                             $this->warnings[] = 'This version of getID3() [v' . $this->getid3->version() . '] has problems parsing AAC audio in Matroska containers [' . basename(__FILE__) . ':' . __LINE__ . ']';
                             if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio.aac.php', __FILE__, false)) {
                                 $getid3_temp = new getID3();
                                 $getid3_temp->openfile($this->getid3->filename);
                                 $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
                                 $getid3_aac = new getid3_aac($getid3_temp);
                                 $getid3_aac->Analyze();
                                 unset($getid3_temp->info['aac']['GETID3_VERSION']);
                                 if (!empty($getid3_temp->info['audio']['dataformat'])) {
                                     $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['aac'];
                                     if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
                                         foreach ($getid3_temp->info['audio'] as $key => $value) {
                                             $track_info[$key] = $value;
                                         }
                                     }
                                 } else {
                                     $this->warnings[] = 'Failed to parse ' . $trackarray[$this->EBMLidName(EBML_ID_CODECID)] . ' audio data [' . basename(__FILE__) . ':' . __LINE__ . ']';
                                 }
                                 unset($getid3_temp, $getid3_aac);
                             } else {
                                 $this->warnings[] = 'Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio.aac.php"';
                             }
                             break;
                         case 'A_MPEG/L3':
                             if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio.mp3.php', __FILE__, false)) {
                                 $getid3_temp = new getID3();
                                 $getid3_temp->openfile($this->getid3->filename);
                                 $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
                                 $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length'];
                                 $getid3_mp3 = new getid3_mp3($getid3_temp);
                                 $getid3_mp3->allow_bruteforce = true;
                                 $getid3_mp3->Analyze();
                                 if (!empty($getid3_temp->info['mpeg'])) {
                                     unset($getid3_temp->info['mpeg']['GETID3_VERSION']);
                                     $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['mpeg'];
                                     if (!empty($getid3_temp->info['error'])) {
                                         foreach ($getid3_temp->info['error'] as $newerror) {
                                             $this->warnings[] = 'getid3_mp3() says: [' . $newerror . ']';
                                         }
                                     }
                                     if (!empty($getid3_temp->info['warning'])) {
                                         foreach ($getid3_temp->info['warning'] as $newerror) {
                                             $this->warnings[] = 'getid3_mp3() says: [' . $newerror . ']';
                                         }
                                     }
                                     if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
                                         foreach ($getid3_temp->info['audio'] as $key => $value) {
                                             $track_info[$key] = $value;
                                         }
                                     }
                                 } else {
                                     $this->warnings[] = 'Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because getid3_mp3::Analyze failed at offset ' . $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
                                 }
                                 unset($getid3_temp, $getid3_mp3);
                             } else {
                                 $this->warnings[] = 'Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio.mp3.php"';
                             }
                             break;
                         case 'A_VORBIS':
                             if (isset($trackarray['CodecPrivate'])) {
                                 // this is a NASTY hack, email info@getid3.org if you have a better idea how to get this info out
                                 $found_vorbis = false;
                                 for ($vorbis_offset = 1; $vorbis_offset < 16; $vorbis_offset++) {
                                     if (substr($trackarray['CodecPrivate'], $vorbis_offset, 6) == 'vorbis') {
                                         $vorbis_offset--;
                                         $found_vorbis = true;
                                         break;
                                     }
                                 }
                                 if ($found_vorbis) {
                                     if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio.ogg.php', __FILE__, false)) {
                                         $oggpageinfo['page_seqno'] = 0;
                                         $getid3_temp = new getID3();
                                         $getid3_temp->openfile($this->getid3->filename);
                                         $getid3_ogg = new getid3_ogg($getid3_temp);
                                         $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo);
                                         $vorbis_fileinfo = $getid3_temp->info;
                                         unset($getid3_temp, $getid3_ogg);
                                         if (isset($vorbis_fileinfo['audio'])) {
                                             $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']]['audio'] = $vorbis_fileinfo['audio'];
                                         }
                                         if (isset($vorbis_fileinfo['ogg'])) {
                                             $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']]['ogg'] = $vorbis_fileinfo['ogg'];
                                         }
                                         if (!empty($vorbis_fileinfo['error'])) {
                                             foreach ($vorbis_fileinfo['error'] as $newerror) {
                                                 $this->warnings[] = 'getid3_ogg() says: [' . $newerror . ']';
                                             }
                                         }
                                         if (!empty($vorbis_fileinfo['warning'])) {
                                             foreach ($vorbis_fileinfo['warning'] as $newerror) {
                                                 $this->warnings[] = 'getid3_ogg() says: [' . $newerror . ']';
                                             }
                                         }
                                         if (isset($vorbis_fileinfo['audio']) && is_array($vorbis_fileinfo['audio'])) {
                                             foreach ($vorbis_fileinfo['audio'] as $key => $value) {
                                                 $track_info[$key] = $value;
                                             }
                                         }
                                         if (!empty($vorbis_fileinfo['ogg']['bitrate_average'])) {
                                             $track_info['bitrate'] = $vorbis_fileinfo['ogg']['bitrate_average'];
                                         } elseif (!empty($vorbis_fileinfo['ogg']['bitrate_nominal'])) {
                                             $track_info['bitrate'] = $vorbis_fileinfo['ogg']['bitrate_nominal'];
                                         }
                                         unset($vorbis_fileinfo);
                                         unset($oggpageinfo);
                                     } else {
                                         $this->warnings[] = 'Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio.ogg.php"';
                                     }
                                 } else {
                                 }
                             } else {
                             }
                             break;
                         default:
                             $this->warnings[] = 'Unhandled audio type "' . (isset($trackarray[$this->EBMLidName(EBML_ID_CODECID)]) ? $trackarray[$this->EBMLidName(EBML_ID_CODECID)] : '') . '"';
                             break;
                     }
                     $info['audio']['streams'][] = $track_info;
                     if (isset($track_info['dataformat']) && empty($info['audio']['dataformat'])) {
                         foreach ($track_info as $key => $value) {
                             $info['audio'][$key] = $value;
                         }
                     }
                     break;
                 default:
                     // ignore, do nothing
                     break;
             }
         }
     }
     if ($this->hide_clusters) {
         // too much data returned that is usually not useful
         if (isset($info['matroska']['segments']) && is_array($info['matroska']['segments'])) {
             foreach ($info['matroska']['segments'] as $key => $segmentsarray) {
                 if ($segmentsarray['id'] == EBML_ID_CLUSTER) {
                     unset($info['matroska']['segments'][$key]);
                 }
             }
         }
         if (isset($info['matroska']['seek']) && is_array($info['matroska']['seek'])) {
             foreach ($info['matroska']['seek'] as $key => $seekarray) {
                 if ($seekarray['target_id'] == EBML_ID_CLUSTER) {
                     unset($info['matroska']['seek'][$key]);
                 }
             }
         }
         //unset($info['matroska']['cluster']);
         //unset($info['matroska']['track_data_offsets']);
     }
     if (!empty($info['video']['streams'])) {
         $info['mime_type'] = 'video/x-matroska';
     } elseif (!empty($info['audio']['streams'])) {
         $info['mime_type'] = 'audio/x-matroska';
     } elseif (isset($info['mime_type'])) {
         unset($info['mime_type']);
     }
     foreach ($this->warnings as $key => $value) {
         $info['warning'][] = $value;
     }
     return true;
 }
 public function Analyze()
 {
     $info =& $this->getid3->info;
     // parse container
     try {
         $this->parseEBML($info);
     } catch (Exception $e) {
         $info['error'][] = 'EBML parser: ' . $e->getMessage();
     }
     // calculate playtime
     if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
         foreach ($info['matroska']['info'] as $key => $infoarray) {
             if (isset($infoarray['Duration'])) {
                 // TimecodeScale is how many nanoseconds each Duration unit is
                 $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000);
                 break;
             }
         }
     }
     // extract tags
     if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) {
         foreach ($info['matroska']['tags'] as $key => $infoarray) {
             $this->ExtractCommentsSimpleTag($infoarray);
         }
     }
     // process tracks
     if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
         foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) {
             $track_info = array();
             $track_info['dataformat'] = self::MatroskaCodecIDtoCommonName($trackarray['CodecID']);
             $track_info['default'] = isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true;
             if (isset($trackarray['Name'])) {
                 $track_info['name'] = $trackarray['Name'];
             }
             switch ($trackarray['TrackType']) {
                 case 1:
                     // Video
                     $track_info['resolution_x'] = $trackarray['PixelWidth'];
                     $track_info['resolution_y'] = $trackarray['PixelHeight'];
                     if (isset($trackarray['DisplayWidth'])) {
                         $track_info['display_x'] = $trackarray['DisplayWidth'];
                     }
                     if (isset($trackarray['DisplayHeight'])) {
                         $track_info['display_y'] = $trackarray['DisplayHeight'];
                     }
                     if (isset($trackarray['DefaultDuration'])) {
                         $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3);
                     }
                     //if (isset($trackarray['CodecName']))       { $track_info['codec']      = $trackarray['CodecName']; }
                     switch ($trackarray['CodecID']) {
                         case 'V_MS/VFW/FOURCC':
                             if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio-video.riff.php', __FILE__, false)) {
                                 $this->getid3->warning('Unable to parse codec private data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio-video.riff.php"');
                                 break;
                             }
                             $parsed = getid3_riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']);
                             $track_info['codec'] = getid3_riff::RIFFfourccLookup($parsed['fourcc']);
                             $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
                             break;
                     }
                     $info['video']['streams'][] = $track_info;
                     break;
                 case 2:
                     // Audio
                     $track_info['sample_rate'] = isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0;
                     $track_info['channels'] = isset($trackarray['Channels']) ? $trackarray['Channels'] : 1;
                     $track_info['language'] = isset($trackarray['Language']) ? $trackarray['Language'] : 'eng';
                     if (isset($trackarray['BitDepth'])) {
                         $track_info['bits_per_sample'] = $trackarray['BitDepth'];
                     }
                     //if (isset($trackarray['CodecName'])) { $track_info['codec']           = $trackarray['CodecName']; }
                     switch ($trackarray['CodecID']) {
                         case 'A_PCM/INT/LIT':
                         case 'A_PCM/INT/BIG':
                             $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
                             break;
                         case 'A_AC3':
                         case 'A_DTS':
                         case 'A_MPEG/L3':
                             //case 'A_FLAC':
                             if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio.' . $track_info['dataformat'] . '.php', __FILE__, false)) {
                                 $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio.' . $track_info['dataformat'] . '.php"');
                                 break;
                             }
                             if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
                                 $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because $info[matroska][track_data_offsets][' . $trackarray['TrackNumber'] . '] not set');
                                 break;
                             }
                             // create temp instance
                             $getid3_temp = new getID3();
                             $getid3_temp->openfile($this->getid3->filename);
                             $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
                             if ($track_info['dataformat'] == 'mp3' || $track_info['dataformat'] == 'flac') {
                                 $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length'];
                             }
                             // analyze
                             $class = 'getid3_' . $track_info['dataformat'];
                             $header_data_key = $track_info['dataformat'] == 'mp3' ? 'mpeg' : $track_info['dataformat'];
                             $getid3_audio = new $class($getid3_temp);
                             if ($track_info['dataformat'] == 'mp3') {
                                 $getid3_audio->allow_bruteforce = true;
                             }
                             if ($track_info['dataformat'] == 'flac') {
                                 $getid3_audio->AnalyzeString($trackarray['CodecPrivate']);
                             } else {
                                 $getid3_audio->Analyze();
                             }
                             if (!empty($getid3_temp->info[$header_data_key])) {
                                 unset($getid3_temp->info[$header_data_key]['GETID3_VERSION']);
                                 $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
                                 if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
                                     foreach ($getid3_temp->info['audio'] as $key => $value) {
                                         $track_info[$key] = $value;
                                     }
                                 }
                             } else {
                                 $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because ' . $class . '::Analyze() failed at offset ' . $getid3_temp->info['avdataoffset']);
                             }
                             // copy errors and warnings
                             if (!empty($getid3_temp->info['error'])) {
                                 foreach ($getid3_temp->info['error'] as $newerror) {
                                     $this->getid3->warning($class . '() says: [' . $newerror . ']');
                                 }
                             }
                             if (!empty($getid3_temp->info['warning'])) {
                                 foreach ($getid3_temp->info['warning'] as $newerror) {
                                     if ($track_info['dataformat'] == 'mp3' && preg_match('/^Probable truncated file: expecting \\d+ bytes of audio data, only found \\d+ \\(short by \\d+ bytes\\)$/', $newerror)) {
                                         // LAME/Xing header is probably set, but audio data is chunked into Matroska file and near-impossible to verify if audio stream is complete, so ignore useless warning
                                         continue;
                                     }
                                     $this->getid3->warning($class . '() says: [' . $newerror . ']');
                                 }
                             }
                             unset($getid3_temp, $getid3_audio);
                             break;
                         case 'A_AAC':
                         case 'A_AAC/MPEG2/LC':
                         case 'A_AAC/MPEG4/LC':
                         case 'A_AAC/MPEG4/LC/SBR':
                             $this->getid3->warning($trackarray['CodecID'] . ' audio data contains no header, audio/video bitrates can\'t be calculated');
                             break;
                         case 'A_VORBIS':
                             if (!isset($trackarray['CodecPrivate'])) {
                                 $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because CodecPrivate data not set');
                                 break;
                             }
                             $vorbis_offset = strpos($trackarray['CodecPrivate'], 'vorbis', 1);
                             if ($vorbis_offset === false) {
                                 $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because CodecPrivate data does not contain "vorbis" keyword');
                                 break;
                             }
                             $vorbis_offset -= 1;
                             if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio.ogg.php', __FILE__, false)) {
                                 $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio.ogg.php"');
                             }
                             // create temp instance
                             $getid3_temp = new getID3();
                             $getid3_temp->openfile($this->getid3->filename);
                             // analyze
                             $getid3_ogg = new getid3_ogg($getid3_temp);
                             $oggpageinfo['page_seqno'] = 0;
                             $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo);
                             if (!empty($getid3_temp->info['ogg'])) {
                                 $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
                                 if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
                                     foreach ($getid3_temp->info['audio'] as $key => $value) {
                                         $track_info[$key] = $value;
                                     }
                                 }
                             }
                             // copy errors and warnings
                             if (!empty($getid3_temp->info['error'])) {
                                 foreach ($getid3_temp->info['error'] as $newerror) {
                                     $this->getid3->warning('getid3_ogg() says: [' . $newerror . ']');
                                 }
                             }
                             if (!empty($getid3_temp->info['warning'])) {
                                 foreach ($getid3_temp->info['warning'] as $newerror) {
                                     $this->getid3->warning('getid3_ogg() says: [' . $newerror . ']');
                                 }
                             }
                             if (!empty($getid3_temp->info['ogg']['bitrate_nominal'])) {
                                 $track_info['bitrate'] = $getid3_temp->info['ogg']['bitrate_nominal'];
                             }
                             unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset);
                             break;
                         case 'A_MS/ACM':
                             if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio-video.riff.php', __FILE__, false)) {
                                 $this->getid3->warning('Unable to parse audio data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio-video.riff.php"');
                                 break;
                             }
                             $parsed = getid3_riff::RIFFparseWAVEFORMATex($trackarray['CodecPrivate']);
                             foreach ($parsed as $key => $value) {
                                 if ($key != 'raw') {
                                     $track_info[$key] = $value;
                                 }
                             }
                             $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
                             break;
                         default:
                             $this->getid3->warning('Unhandled audio type "' . (isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '') . '"');
                     }
                     $info['audio']['streams'][] = $track_info;
                     break;
             }
         }
         if (!empty($info['video']['streams'])) {
             $info['video'] = self::getDefaultStreamInfo($info['video']['streams']);
         }
         if (!empty($info['audio']['streams'])) {
             $info['audio'] = self::getDefaultStreamInfo($info['audio']['streams']);
         }
     }
     // determine mime type
     if (!empty($info['video']['streams'])) {
         $info['mime_type'] = $info['matroska']['doctype'] == 'webm' ? 'video/webm' : 'video/x-matroska';
     } elseif (!empty($info['audio']['streams'])) {
         $info['mime_type'] = $info['matroska']['doctype'] == 'webm' ? 'audio/webm' : 'audio/x-matroska';
     } elseif (isset($info['mime_type'])) {
         unset($info['mime_type']);
     }
     return true;
 }
 function Analyze()
 {
     $info =& $this->getid3->info;
     // initialize these values to an empty array, otherwise they default to NULL
     // and you can't append array values to a NULL value
     $info['riff'] = array('raw' => array());
     // Shortcuts
     $thisfile_riff =& $info['riff'];
     $thisfile_riff_raw =& $thisfile_riff['raw'];
     $thisfile_audio =& $info['audio'];
     $thisfile_video =& $info['video'];
     $thisfile_audio_dataformat =& $thisfile_audio['dataformat'];
     $thisfile_riff_audio =& $thisfile_riff['audio'];
     $thisfile_riff_video =& $thisfile_riff['video'];
     $Original['avdataoffset'] = $info['avdataoffset'];
     $Original['avdataend'] = $info['avdataend'];
     fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
     $RIFFheader = fread($this->getid3->fp, 12);
     $RIFFsubtype = substr($RIFFheader, 8, 4);
     switch (substr($RIFFheader, 0, 4)) {
         case 'FORM':
             $info['fileformat'] = 'aiff';
             $thisfile_riff['header_size'] = $this->EitherEndian2Int(substr($RIFFheader, 4, 4));
             $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($info['avdataoffset'] + 12, $info['avdataoffset'] + $thisfile_riff['header_size']);
             break;
         case 'RIFF':
             // AVI, WAV, etc
         // AVI, WAV, etc
         case 'SDSS':
             // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
         // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
         case 'RMP3':
             // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
             $info['fileformat'] = 'riff';
             $thisfile_riff['header_size'] = $this->EitherEndian2Int(substr($RIFFheader, 4, 4));
             if ($RIFFsubtype == 'RMP3') {
                 // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
                 $RIFFsubtype = 'WAVE';
             }
             $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($info['avdataoffset'] + 12, $info['avdataoffset'] + $thisfile_riff['header_size']);
             if ($info['avdataend'] - $info['filesize'] == 1) {
                 // LiteWave appears to incorrectly *not* pad actual output file
                 // to nearest WORD boundary so may appear to be short by one
                 // byte, in which case - skip warning
                 $info['avdataend'] = $info['filesize'];
             }
             $nextRIFFoffset = $Original['avdataoffset'] + 8 + $thisfile_riff['header_size'];
             // 8 = "RIFF" + 32-bit offset
             while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) {
                 if (!getid3_lib::intValueSupported($nextRIFFoffset + 1024)) {
                     $info['error'][] = 'AVI extends beyond ' . round(PHP_INT_MAX / 1073741824) . 'GB and PHP filesystem functions cannot read that far, playtime is probably wrong';
                     $info['warning'][] = '[avdataend] value may be incorrect, multiple AVIX chunks may be present';
                     break;
                 } else {
                     fseek($this->getid3->fp, $nextRIFFoffset, SEEK_SET);
                     $nextRIFFheader = fread($this->getid3->fp, 12);
                     if ($nextRIFFoffset == $info['avdataend'] - 1) {
                         if (substr($nextRIFFheader, 0, 1) == "") {
                             // RIFF padded to WORD boundary, we're actually already at the end
                             break;
                         }
                     }
                     $nextRIFFheaderID = substr($nextRIFFheader, 0, 4);
                     $nextRIFFsize = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4));
                     $nextRIFFtype = substr($nextRIFFheader, 8, 4);
                     $chunkdata = array();
                     $chunkdata['offset'] = $nextRIFFoffset + 8;
                     $chunkdata['size'] = $nextRIFFsize;
                     $nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
                     switch ($nextRIFFheaderID) {
                         case 'RIFF':
                             $info['avdataend'] = $nextRIFFoffset;
                             if (!getid3_lib::intValueSupported($info['avdataend'])) {
                                 $info['error'][] = 'AVI extends beyond ' . round(PHP_INT_MAX / 1073741824) . 'GB and PHP filesystem functions cannot read that far, playtime is probably wrong';
                                 $info['warning'][] = '[avdataend] value may be incorrect, multiple AVIX chunks may be present';
                             }
                             $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $chunkdata['offset'] + $chunkdata['size']);
                             if (!isset($thisfile_riff[$nextRIFFtype])) {
                                 $thisfile_riff[$nextRIFFtype] = array();
                             }
                             $thisfile_riff[$nextRIFFtype][] = $chunkdata;
                             break;
                         case 'JUNK':
                             // ignore
                             $thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
                             break;
                         default:
                             if ($info['filesize'] == $chunkdata['offset'] - 8 + 128) {
                                 $DIVXTAG = $nextRIFFheader . fread($this->getid3->fp, 128 - 12);
                                 if (substr($DIVXTAG, -7) == 'DIVXTAG') {
                                     // 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
                                     $info['warning'][] = 'Found wrongly-structured DIVXTAG at offset ' . (ftell($this->getid3->fp) - 128 + 12) . ', parsing anyway';
                                     $thisfile_riff['DIVXTAG'] = $this->ParseDIVXTAG($DIVXTAG);
                                     foreach ($thisfile_riff['DIVXTAG'] as $key => $value) {
                                         if ($value && !preg_match('#_id$#', $key)) {
                                             $thisfile_riff['comments'][$key][] = $value;
                                         }
                                     }
                                     break 2;
                                 }
                             }
                             $info['warning'][] = 'expecting "RIFF" or "JUNK" at ' . $nextRIFFoffset . ', found ' . getid3_lib::PrintHexBytes(substr($nextRIFFheader, 0, 4)) . ' - skipping rest of file';
                             break 2;
                     }
                 }
             }
             if ($RIFFsubtype == 'WAVE') {
                 $thisfile_riff_WAVE =& $thisfile_riff['WAVE'];
             }
             break;
         default:
             $info['error'][] = 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "' . $RIFFsubtype . '" instead';
             unset($info['fileformat']);
             return false;
             break;
     }
     $streamindex = 0;
     switch ($RIFFsubtype) {
         case 'WAVE':
             if (empty($thisfile_audio['bitrate_mode'])) {
                 $thisfile_audio['bitrate_mode'] = 'cbr';
             }
             if (empty($thisfile_audio_dataformat)) {
                 $thisfile_audio_dataformat = 'wav';
             }
             if (isset($thisfile_riff_WAVE['data'][0]['offset'])) {
                 $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] + 8;
                 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size'];
             }
             if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
                 $thisfile_riff_audio[$streamindex] = getid3_riff::RIFFparseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
                 $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
                 if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || $thisfile_riff_audio[$streamindex]['bitrate'] == 0) {
                     $info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero';
                     return false;
                 }
                 $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
                 unset($thisfile_riff_audio[$streamindex]['raw']);
                 $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
                 $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
                 if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
                     $info['warning'][] = 'Audio codec = ' . $thisfile_audio['codec'];
                 }
                 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
                 $info['playtime_seconds'] = (double) (($info['avdataend'] - $info['avdataoffset']) * 8 / $thisfile_audio['bitrate']);
                 $thisfile_audio['lossless'] = false;
                 if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
                     switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
                         case 0x1:
                             // PCM
                             $thisfile_audio['lossless'] = true;
                             break;
                         case 0x2000:
                             // AC-3
                             $thisfile_audio_dataformat = 'ac3';
                             break;
                         default:
                             // do nothing
                             break;
                     }
                 }
                 $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag'];
                 $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
                 $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless'];
                 $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat;
             }
             if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
                 // shortcuts
                 $rgadData =& $thisfile_riff_WAVE['rgad'][0]['data'];
                 $thisfile_riff_raw['rgad'] = array('track' => array(), 'album' => array());
                 $thisfile_riff_raw_rgad =& $thisfile_riff_raw['rgad'];
                 $thisfile_riff_raw_rgad_track =& $thisfile_riff_raw_rgad['track'];
                 $thisfile_riff_raw_rgad_album =& $thisfile_riff_raw_rgad['album'];
                 $thisfile_riff_raw_rgad['fPeakAmplitude'] = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4));
                 $thisfile_riff_raw_rgad['nRadioRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 4, 2));
                 $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 6, 2));
                 $nRadioRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
                 $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
                 $thisfile_riff_raw_rgad_track['name'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
                 $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
                 $thisfile_riff_raw_rgad_track['signbit'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
                 $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
                 $thisfile_riff_raw_rgad_album['name'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
                 $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
                 $thisfile_riff_raw_rgad_album['signbit'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
                 $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
                 $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude'];
                 if ($thisfile_riff_raw_rgad_track['name'] != 0 && $thisfile_riff_raw_rgad_track['originator'] != 0) {
                     $thisfile_riff['rgad']['track']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']);
                     $thisfile_riff['rgad']['track']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']);
                     $thisfile_riff['rgad']['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']);
                 }
                 if ($thisfile_riff_raw_rgad_album['name'] != 0 && $thisfile_riff_raw_rgad_album['originator'] != 0) {
                     $thisfile_riff['rgad']['album']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']);
                     $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']);
                     $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']);
                 }
             }
             if (isset($thisfile_riff_WAVE['fact'][0]['data'])) {
                 $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4));
                 // This should be a good way of calculating exact playtime,
                 // but some sample files have had incorrect number of samples,
                 // so cannot use this method
                 // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
                 //     $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
                 // }
             }
             if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
                 $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
             }
             if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_WAVE_bext_0 =& $thisfile_riff_WAVE['bext'][0];
                 $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256));
                 $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32));
                 $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32));
                 $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10);
                 $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8);
                 $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8));
                 $thisfile_riff_WAVE_bext_0['bwf_version'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1));
                 $thisfile_riff_WAVE_bext_0['reserved'] = substr($thisfile_riff_WAVE_bext_0['data'], 347, 254);
                 $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
                 if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
                     if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
                         list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date;
                         list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
                         $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']);
                     } else {
                         $info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid';
                     }
                 } else {
                     $info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid';
                 }
                 $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
                 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
             }
             if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_WAVE_MEXT_0 =& $thisfile_riff_WAVE['MEXT'][0];
                 $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2));
                 $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x1);
                 if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) {
                     $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x2 ? false : true;
                     $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x4);
                     $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x8);
                     $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
                 }
                 $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2));
                 $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2));
                 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x1);
                 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x2);
                 $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x4);
             }
             if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_WAVE_cart_0 =& $thisfile_riff_WAVE['cart'][0];
                 $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4);
                 $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64));
                 $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64));
                 $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64));
                 $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64));
                 $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64));
                 $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64));
                 $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64));
                 $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10));
                 $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8));
                 $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10));
                 $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8));
                 $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64));
                 $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64));
                 $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64));
                 $thisfile_riff_WAVE_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true);
                 for ($i = 0; $i < 8; $i++) {
                     $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 + $i * 8, 4);
                     $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));
                 }
                 $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
                 $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
                 $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
                 $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
             }
             if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) {
                 // SoundMiner metadata
                 // shortcuts
                 $thisfile_riff_WAVE_SNDM_0 =& $thisfile_riff_WAVE['SNDM'][0];
                 $thisfile_riff_WAVE_SNDM_0_data =& $thisfile_riff_WAVE_SNDM_0['data'];
                 $SNDM_startoffset = 0;
                 $SNDM_endoffset = $thisfile_riff_WAVE_SNDM_0['size'];
                 while ($SNDM_startoffset < $SNDM_endoffset) {
                     $SNDM_thisTagOffset = 0;
                     $SNDM_thisTagSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4));
                     $SNDM_thisTagOffset += 4;
                     $SNDM_thisTagKey = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4);
                     $SNDM_thisTagOffset += 4;
                     $SNDM_thisTagDataSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
                     $SNDM_thisTagOffset += 2;
                     $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
                     $SNDM_thisTagOffset += 2;
                     $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize);
                     $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
                     if ($SNDM_thisTagSize != 4 + 4 + 2 + 2 + $SNDM_thisTagDataSize) {
                         $info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: ' . $SNDM_thisTagSize . ', found: ' . (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize) . ') at offset ' . $SNDM_startoffset . ' (file offset ' . ($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset) . ')';
                         break;
                     } elseif ($SNDM_thisTagSize <= 0) {
                         $info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset ' . $SNDM_startoffset . ' (file offset ' . ($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset) . ')';
                         break;
                     }
                     $SNDM_startoffset += $SNDM_thisTagSize;
                     $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText;
                     if ($parsedkey = $this->RIFFwaveSNDMtagLookup($SNDM_thisTagKey)) {
                         $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
                     } else {
                         $info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "' . $SNDM_thisTagKey . '" at offset ' . $SNDM_startoffset . ' (file offset ' . ($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset) . ')';
                     }
                 }
                 $tagmapping = array('tracktitle' => 'title', 'category' => 'genre', 'cdtitle' => 'album', 'tracktitle' => 'title');
                 foreach ($tagmapping as $fromkey => $tokey) {
                     if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
                         $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey];
                     }
                 }
             }
             if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) {
                 // requires functions simplexml_load_string and get_object_vars
                 if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) {
                     $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML;
                     if (isset($parsedXML['SPEED']['MASTER_SPEED'])) {
                         @(list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']));
                         $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000);
                     }
                     if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) {
                         @(list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']));
                         $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000);
                     }
                     if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
                         $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'] . $parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
                         $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE'];
                         $h = floor($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600);
                         $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - $h * 3600) / 60);
                         $s = floor($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - $h * 3600 - $m * 60);
                         $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - $h * 3600 - $m * 60 - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
                         $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f);
                         $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f));
                     }
                     unset($parsedXML);
                 }
             }
             if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
                 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
                 $info['playtime_seconds'] = (double) (($info['avdataend'] - $info['avdataoffset']) * 8 / $thisfile_audio['bitrate']);
             }
             if (!empty($info['wavpack'])) {
                 $thisfile_audio_dataformat = 'wavpack';
                 $thisfile_audio['bitrate_mode'] = 'vbr';
                 $thisfile_audio['encoder'] = 'WavPack v' . $info['wavpack']['version'];
                 // Reset to the way it was - RIFF parsing will have messed this up
                 $info['avdataend'] = $Original['avdataend'];
                 $thisfile_audio['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds'];
                 fseek($this->getid3->fp, $info['avdataoffset'] - 44, SEEK_SET);
                 $RIFFdata = fread($this->getid3->fp, 44);
                 $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
                 $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
                 if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
                     $info['avdataend'] -= $OrignalRIFFheaderSize - $OrignalRIFFdataSize;
                     fseek($this->getid3->fp, $info['avdataend'], SEEK_SET);
                     $RIFFdata .= fread($this->getid3->fp, $OrignalRIFFheaderSize - $OrignalRIFFdataSize);
                 }
                 // move the data chunk after all other chunks (if any)
                 // so that the RIFF parser doesn't see EOF when trying
                 // to skip over the data chunk
                 $RIFFdata = substr($RIFFdata, 0, 36) . substr($RIFFdata, 44) . substr($RIFFdata, 36, 8);
                 $getid3_riff = new getid3_riff($this->getid3);
                 $getid3_riff->ParseRIFFdata($RIFFdata);
                 unset($getid3_riff);
             }
             if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
                 switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
                     case 0x1:
                         // PCM
                         if (!empty($info['ac3'])) {
                             // Dolby Digital WAV files masquerade as PCM-WAV, but they're not
                             $thisfile_audio['wformattag'] = 0x2000;
                             $thisfile_audio['codec'] = $this->RIFFwFormatTagLookup($thisfile_audio['wformattag']);
                             $thisfile_audio['lossless'] = false;
                             $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
                             $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate'];
                         }
                         break;
                     case 0x8ae:
                         // ClearJump LiteWave
                         $thisfile_audio['bitrate_mode'] = 'vbr';
                         $thisfile_audio_dataformat = 'litewave';
                         //typedef struct tagSLwFormat {
                         //  WORD    m_wCompFormat;     // low byte defines compression method, high byte is compression flags
                         //  DWORD   m_dwScale;         // scale factor for lossy compression
                         //  DWORD   m_dwBlockSize;     // number of samples in encoded blocks
                         //  WORD    m_wQuality;        // alias for the scale factor
                         //  WORD    m_wMarkDistance;   // distance between marks in bytes
                         //  WORD    m_wReserved;
                         //
                         //  //following paramters are ignored if CF_FILESRC is not set
                         //  DWORD   m_dwOrgSize;       // original file size in bytes
                         //  WORD    m_bFactExists;     // indicates if 'fact' chunk exists in the original file
                         //  DWORD   m_dwRiffChunkSize; // riff chunk size in the original file
                         //
                         //  PCMWAVEFORMAT m_OrgWf;     // original wave format
                         // }SLwFormat, *PSLwFormat;
                         // shortcut
                         $thisfile_riff['litewave']['raw'] = array();
                         $thisfile_riff_litewave =& $thisfile_riff['litewave'];
                         $thisfile_riff_litewave_raw =& $thisfile_riff_litewave['raw'];
                         $thisfile_riff_litewave_raw['compression_method'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 18, 1));
                         $thisfile_riff_litewave_raw['compression_flags'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 19, 1));
                         $thisfile_riff_litewave_raw['m_dwScale'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 20, 4));
                         $thisfile_riff_litewave_raw['m_dwBlockSize'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 24, 4));
                         $thisfile_riff_litewave_raw['m_wQuality'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 28, 2));
                         $thisfile_riff_litewave_raw['m_wMarkDistance'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 30, 2));
                         $thisfile_riff_litewave_raw['m_wReserved'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 32, 2));
                         $thisfile_riff_litewave_raw['m_dwOrgSize'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 34, 4));
                         $thisfile_riff_litewave_raw['m_bFactExists'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 38, 2));
                         $thisfile_riff_litewave_raw['m_dwRiffChunkSize'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], 40, 4));
                         //$thisfile_riff_litewave['quality_factor'] = intval(round((2000 - $thisfile_riff_litewave_raw['m_dwScale']) / 20));
                         $thisfile_riff_litewave['quality_factor'] = $thisfile_riff_litewave_raw['m_wQuality'];
                         $thisfile_riff_litewave['flags']['raw_source'] = $thisfile_riff_litewave_raw['compression_flags'] & 0x1 ? false : true;
                         $thisfile_riff_litewave['flags']['vbr_blocksize'] = $thisfile_riff_litewave_raw['compression_flags'] & 0x2 ? false : true;
                         $thisfile_riff_litewave['flags']['seekpoints'] = (bool) ($thisfile_riff_litewave_raw['compression_flags'] & 0x4);
                         $thisfile_audio['lossless'] = $thisfile_riff_litewave_raw['m_wQuality'] == 100 ? true : false;
                         $thisfile_audio['encoder_options'] = '-q' . $thisfile_riff_litewave['quality_factor'];
                         break;
                     default:
                         break;
                 }
             }
             if ($info['avdataend'] > $info['filesize']) {
                 switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') {
                     case 'wavpack':
                         // WavPack
                     // WavPack
                     case 'lpac':
                         // LPAC
                     // LPAC
                     case 'ofr':
                         // OptimFROG
                     // OptimFROG
                     case 'ofs':
                         // OptimFROG DualStream
                         // lossless compressed audio formats that keep original RIFF headers - skip warning
                         break;
                     case 'litewave':
                         if ($info['avdataend'] - $info['filesize'] == 1) {
                             // LiteWave appears to incorrectly *not* pad actual output file
                             // to nearest WORD boundary so may appear to be short by one
                             // byte, in which case - skip warning
                         } else {
                             // Short by more than one byte, throw warning
                             $info['warning'][] = 'Probably truncated file - expecting ' . $thisfile_riff[$RIFFsubtype]['data'][0]['size'] . ' bytes of data, only found ' . ($info['filesize'] - $info['avdataoffset']) . ' (short by ' . ($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])) . ' bytes)';
                             $info['avdataend'] = $info['filesize'];
                         }
                         break;
                     default:
                         if ($info['avdataend'] - $info['filesize'] == 1 && $thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2 == 0 && ($info['filesize'] - $info['avdataoffset']) % 2 == 1) {
                             // output file appears to be incorrectly *not* padded to nearest WORD boundary
                             // Output less severe warning
                             $info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting ' . $thisfile_riff[$RIFFsubtype]['data'][0]['size'] . ' bytes of data, only found ' . ($info['filesize'] - $info['avdataoffset']) . ' therefore short by ' . ($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])) . ' bytes)';
                             $info['avdataend'] = $info['filesize'];
                         } else {
                             // Short by more than one byte, throw warning
                             $info['warning'][] = 'Probably truncated file - expecting ' . $thisfile_riff[$RIFFsubtype]['data'][0]['size'] . ' bytes of data, only found ' . ($info['filesize'] - $info['avdataoffset']) . ' (short by ' . ($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])) . ' bytes)';
                             $info['avdataend'] = $info['filesize'];
                         }
                         break;
                 }
             }
             if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
                 if ($info['avdataend'] - $info['avdataoffset'] - $info['mpeg']['audio']['LAME']['audio_bytes'] == 1) {
                     $info['avdataend']--;
                     $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
                 }
             }
             if (isset($thisfile_audio_dataformat) && $thisfile_audio_dataformat == 'ac3') {
                 unset($thisfile_audio['bits_per_sample']);
                 if (!empty($info['ac3']['bitrate']) && $info['ac3']['bitrate'] != $thisfile_audio['bitrate']) {
                     $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
                 }
             }
             break;
         case 'AVI ':
             $thisfile_video['bitrate_mode'] = 'vbr';
             // maybe not, but probably
             $thisfile_video['dataformat'] = 'avi';
             $info['mime_type'] = 'video/avi';
             if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
                 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
                 if (isset($thisfile_riff['AVIX'])) {
                     $info['avdataend'] = $thisfile_riff['AVIX'][count($thisfile_riff['AVIX']) - 1]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][count($thisfile_riff['AVIX']) - 1]['chunks']['movi']['size'];
                 } else {
                     $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size'];
                 }
                 if ($info['avdataend'] > $info['filesize']) {
                     $info['warning'][] = 'Probably truncated file - expecting ' . ($info['avdataend'] - $info['avdataoffset']) . ' bytes of data, only found ' . ($info['filesize'] - $info['avdataoffset']) . ' (short by ' . ($info['avdataend'] - $info['filesize']) . ' bytes)';
                     $info['avdataend'] = $info['filesize'];
                 }
             }
             if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) {
                 //$bIndexType = array(
                 //	0x00 => 'AVI_INDEX_OF_INDEXES',
                 //	0x01 => 'AVI_INDEX_OF_CHUNKS',
                 //	0x80 => 'AVI_INDEX_IS_DATA',
                 //);
                 //$bIndexSubtype = array(
                 //	0x01 => array(
                 //		0x01 => 'AVI_INDEX_2FIELD',
                 //	),
                 //);
                 foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) {
                     $thisfile_riff_avi_hdrl_strl_indx_stream_data =& $thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data'];
                     $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 0, 2));
                     $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType'] = $this->EitherEndian2Int(substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 2, 1));
                     $thisfile_riff_raw['indx'][$streamnumber]['bIndexType'] = $this->EitherEndian2Int(substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 3, 1));
                     $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse'] = $this->EitherEndian2Int(substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 4, 4));
                     $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId'] = substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 8, 4);
                     $thisfile_riff_raw['indx'][$streamnumber]['dwReserved'] = $this->EitherEndian2Int(substr($thisfile_riff_avi_hdrl_strl_indx_stream_data, 12, 4));
                     //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name']    =    $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']];
                     //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']];
                     unset($thisfile_riff_avi_hdrl_strl_indx_stream_data);
                 }
             }
             if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
                 $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
                 // shortcut
                 $thisfile_riff_raw['avih'] = array();
                 $thisfile_riff_raw_avih =& $thisfile_riff_raw['avih'];
                 $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4));
                 // frame display rate (or 0L)
                 if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
                     $info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
                     return false;
                 }
                 $thisfile_riff_raw_avih['dwMaxBytesPerSec'] = $this->EitherEndian2Int(substr($avihData, 4, 4));
                 // max. transfer rate
                 $thisfile_riff_raw_avih['dwPaddingGranularity'] = $this->EitherEndian2Int(substr($avihData, 8, 4));
                 // pad to multiples of this size; normally 2K.
                 $thisfile_riff_raw_avih['dwFlags'] = $this->EitherEndian2Int(substr($avihData, 12, 4));
                 // the ever-present flags
                 $thisfile_riff_raw_avih['dwTotalFrames'] = $this->EitherEndian2Int(substr($avihData, 16, 4));
                 // # frames in file
                 $thisfile_riff_raw_avih['dwInitialFrames'] = $this->EitherEndian2Int(substr($avihData, 20, 4));
                 $thisfile_riff_raw_avih['dwStreams'] = $this->EitherEndian2Int(substr($avihData, 24, 4));
                 $thisfile_riff_raw_avih['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($avihData, 28, 4));
                 $thisfile_riff_raw_avih['dwWidth'] = $this->EitherEndian2Int(substr($avihData, 32, 4));
                 $thisfile_riff_raw_avih['dwHeight'] = $this->EitherEndian2Int(substr($avihData, 36, 4));
                 $thisfile_riff_raw_avih['dwScale'] = $this->EitherEndian2Int(substr($avihData, 40, 4));
                 $thisfile_riff_raw_avih['dwRate'] = $this->EitherEndian2Int(substr($avihData, 44, 4));
                 $thisfile_riff_raw_avih['dwStart'] = $this->EitherEndian2Int(substr($avihData, 48, 4));
                 $thisfile_riff_raw_avih['dwLength'] = $this->EitherEndian2Int(substr($avihData, 52, 4));
                 $thisfile_riff_raw_avih['flags']['hasindex'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x10);
                 $thisfile_riff_raw_avih['flags']['mustuseindex'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x20);
                 $thisfile_riff_raw_avih['flags']['interleaved'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x100);
                 $thisfile_riff_raw_avih['flags']['trustcktype'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x800);
                 $thisfile_riff_raw_avih['flags']['capturedfile'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x10000);
                 $thisfile_riff_raw_avih['flags']['copyrighted'] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & 0x20010);
                 // shortcut
                 $thisfile_riff_video[$streamindex] = array();
                 $thisfile_riff_video_current =& $thisfile_riff_video[$streamindex];
                 if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
                     $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
                     $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width'];
                 }
                 if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
                     $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
                     $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height'];
                 }
                 if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
                     $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
                     $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames'];
                 }
                 $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
                 $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate'];
             }
             if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
                 if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
                     for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
                         if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
                             $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
                             $strhfccType = substr($strhData, 0, 4);
                             if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
                                 $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
                                 // shortcut
                                 $thisfile_riff_raw_strf_strhfccType_streamindex =& $thisfile_riff_raw['strf'][$strhfccType][$streamindex];
                                 switch ($strhfccType) {
                                     case 'auds':
                                         $thisfile_audio['bitrate_mode'] = 'cbr';
                                         $thisfile_audio_dataformat = 'wav';
                                         if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) {
                                             $streamindex = count($thisfile_riff_audio);
                                         }
                                         $thisfile_riff_audio[$streamindex] = getid3_riff::RIFFparseWAVEFORMATex($strfData);
                                         $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
                                         // shortcut
                                         $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
                                         $thisfile_audio_streams_currentstream =& $thisfile_audio['streams'][$streamindex];
                                         if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
                                             unset($thisfile_audio_streams_currentstream['bits_per_sample']);
                                         }
                                         $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
                                         unset($thisfile_audio_streams_currentstream['raw']);
                                         // shortcut
                                         $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
                                         unset($thisfile_riff_audio[$streamindex]['raw']);
                                         $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
                                         $thisfile_audio['lossless'] = false;
                                         switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
                                             case 0x1:
                                                 // PCM
                                                 $thisfile_audio_dataformat = 'wav';
                                                 $thisfile_audio['lossless'] = true;
                                                 break;
                                             case 0x50:
                                                 // MPEG Layer 2 or Layer 1
                                                 $thisfile_audio_dataformat = 'mp2';
                                                 // Assume Layer-2
                                                 break;
                                             case 0x55:
                                                 // MPEG Layer 3
                                                 $thisfile_audio_dataformat = 'mp3';
                                                 break;
                                             case 0xff:
                                                 // AAC
                                                 $thisfile_audio_dataformat = 'aac';
                                                 break;
                                             case 0x161:
                                                 // Windows Media v7 / v8 / v9
                                             // Windows Media v7 / v8 / v9
                                             case 0x162:
                                                 // Windows Media Professional v9
                                             // Windows Media Professional v9
                                             case 0x163:
                                                 // Windows Media Lossess v9
                                                 $thisfile_audio_dataformat = 'wma';
                                                 break;
                                             case 0x2000:
                                                 // AC-3
                                                 $thisfile_audio_dataformat = 'ac3';
                                                 break;
                                             case 0x2001:
                                                 // DTS
                                                 $thisfile_audio_dataformat = 'dts';
                                                 break;
                                             default:
                                                 $thisfile_audio_dataformat = 'wav';
                                                 break;
                                         }
                                         $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat;
                                         $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless'];
                                         $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
                                         break;
                                     case 'iavs':
                                     case 'vids':
                                         // shortcut
                                         $thisfile_riff_raw['strh'][$i] = array();
                                         $thisfile_riff_raw_strh_current =& $thisfile_riff_raw['strh'][$i];
                                         $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4);
                                         // same as $strhfccType;
                                         $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4);
                                         $thisfile_riff_raw_strh_current['dwFlags'] = $this->EitherEndian2Int(substr($strhData, 8, 4));
                                         // Contains AVITF_* flags
                                         $thisfile_riff_raw_strh_current['wPriority'] = $this->EitherEndian2Int(substr($strhData, 12, 2));
                                         $thisfile_riff_raw_strh_current['wLanguage'] = $this->EitherEndian2Int(substr($strhData, 14, 2));
                                         $thisfile_riff_raw_strh_current['dwInitialFrames'] = $this->EitherEndian2Int(substr($strhData, 16, 4));
                                         $thisfile_riff_raw_strh_current['dwScale'] = $this->EitherEndian2Int(substr($strhData, 20, 4));
                                         $thisfile_riff_raw_strh_current['dwRate'] = $this->EitherEndian2Int(substr($strhData, 24, 4));
                                         $thisfile_riff_raw_strh_current['dwStart'] = $this->EitherEndian2Int(substr($strhData, 28, 4));
                                         $thisfile_riff_raw_strh_current['dwLength'] = $this->EitherEndian2Int(substr($strhData, 32, 4));
                                         $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4));
                                         $thisfile_riff_raw_strh_current['dwQuality'] = $this->EitherEndian2Int(substr($strhData, 40, 4));
                                         $thisfile_riff_raw_strh_current['dwSampleSize'] = $this->EitherEndian2Int(substr($strhData, 44, 4));
                                         $thisfile_riff_raw_strh_current['rcFrame'] = $this->EitherEndian2Int(substr($strhData, 48, 4));
                                         $thisfile_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strh_current['fccHandler']);
                                         $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler'];
                                         if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
                                             $thisfile_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
                                             $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
                                         }
                                         $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
                                         $thisfile_video['pixel_aspect_ratio'] = (double) 1;
                                         switch ($thisfile_riff_raw_strh_current['fccHandler']) {
                                             case 'HFYU':
                                                 // Huffman Lossless Codec
                                             // Huffman Lossless Codec
                                             case 'IRAW':
                                                 // Intel YUV Uncompressed
                                             // Intel YUV Uncompressed
                                             case 'YUY2':
                                                 // Uncompressed YUV 4:2:2
                                                 $thisfile_video['lossless'] = true;
                                                 break;
                                             default:
                                                 $thisfile_video['lossless'] = false;
                                                 break;
                                         }
                                         switch ($strhfccType) {
                                             case 'vids':
                                                 $thisfile_riff_raw_strf_strhfccType_streamindex = getid3_riff::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), $info['fileformat'] == 'riff');
                                                 //echo '<pre>'.print_r($thisfile_riff_raw_strf_strhfccType_streamindex, true).'</pre>';
                                                 $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
                                                 if ($thisfile_riff_video_current['codec'] == 'DV') {
                                                     $thisfile_riff_video_current['dv_type'] = 2;
                                                 }
                                                 break;
                                             case 'iavs':
                                                 $thisfile_riff_video_current['dv_type'] = 1;
                                                 break;
                                         }
                                         break;
                                     default:
                                         $info['warning'][] = 'Unhandled fccType for stream (' . $i . '): "' . $strhfccType . '"';
                                         break;
                                 }
                             }
                         }
                         if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
                             $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
                             if (getid3_riff::RIFFfourccLookup($thisfile_video['fourcc'])) {
                                 $thisfile_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($thisfile_video['fourcc']);
                                 $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
                             }
                             switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) {
                                 case 'HFYU':
                                     // Huffman Lossless Codec
                                 // Huffman Lossless Codec
                                 case 'IRAW':
                                     // Intel YUV Uncompressed
                                 // Intel YUV Uncompressed
                                 case 'YUY2':
                                     // Uncompressed YUV 4:2:2
                                     $thisfile_video['lossless'] = true;
                                     //$thisfile_video['bits_per_sample'] = 24;
                                     break;
                                 default:
                                     $thisfile_video['lossless'] = false;
                                     //$thisfile_video['bits_per_sample'] = 24;
                                     break;
                             }
                         }
                     }
                 }
             }
             break;
         case 'CDDA':
             $thisfile_audio['bitrate_mode'] = 'cbr';
             $thisfile_audio_dataformat = 'cda';
             $thisfile_audio['lossless'] = true;
             unset($info['mime_type']);
             $info['avdataoffset'] = 44;
             if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
                 // shortcut
                 $thisfile_riff_CDDA_fmt_0 =& $thisfile_riff['CDDA']['fmt '][0];
                 $thisfile_riff_CDDA_fmt_0['unknown1'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2));
                 $thisfile_riff_CDDA_fmt_0['track_num'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2));
                 $thisfile_riff_CDDA_fmt_0['disc_id'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4));
                 $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4));
                 $thisfile_riff_CDDA_fmt_0['playtime_frames'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4));
                 $thisfile_riff_CDDA_fmt_0['unknown6'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4));
                 $thisfile_riff_CDDA_fmt_0['unknown7'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4));
                 $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (double) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
                 $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (double) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
                 $info['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num'];
                 $info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
                 // hardcoded data for CD-audio
                 $thisfile_audio['sample_rate'] = 44100;
                 $thisfile_audio['channels'] = 2;
                 $thisfile_audio['bits_per_sample'] = 16;
                 $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
                 $thisfile_audio['bitrate_mode'] = 'cbr';
             }
             break;
         case 'AIFF':
         case 'AIFC':
             $thisfile_audio['bitrate_mode'] = 'cbr';
             $thisfile_audio_dataformat = 'aiff';
             $thisfile_audio['lossless'] = true;
             $info['mime_type'] = 'audio/x-aiff';
             if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
                 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
                 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
                 if ($info['avdataend'] > $info['filesize']) {
                     if ($info['avdataend'] == $info['filesize'] + 1 && $info['filesize'] % 2 == 1) {
                         // structures rounded to 2-byte boundary, but dumb encoders
                         // forget to pad end of file to make this actually work
                     } else {
                         $info['warning'][] = 'Probable truncated AIFF file: expecting ' . $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'] . ' bytes of audio data, only ' . ($info['filesize'] - $info['avdataoffset']) . ' bytes found';
                     }
                     $info['avdataend'] = $info['filesize'];
                 }
             }
             if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
                 // shortcut
                 $thisfile_riff_RIFFsubtype_COMM_0_data =& $thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
                 $thisfile_riff_audio['channels'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true);
                 $thisfile_riff_audio['total_samples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false);
                 $thisfile_riff_audio['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true);
                 $thisfile_riff_audio['sample_rate'] = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10));
                 if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) {
                     $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4);
                     $CodecNameSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false);
                     $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize);
                     switch ($thisfile_riff_audio['codec_name']) {
                         case 'NONE':
                             $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
                             $thisfile_audio['lossless'] = true;
                             break;
                         case '':
                             switch ($thisfile_riff_audio['codec_fourcc']) {
                                 // http://developer.apple.com/qa/snd/snd07.html
                                 case 'sowt':
                                     $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
                                     $thisfile_audio['lossless'] = true;
                                     break;
                                 case 'twos':
                                     $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
                                     $thisfile_audio['lossless'] = true;
                                     break;
                                 default:
                                     break;
                             }
                             break;
                         default:
                             $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name'];
                             $thisfile_audio['lossless'] = false;
                             break;
                     }
                 }
                 $thisfile_audio['channels'] = $thisfile_riff_audio['channels'];
                 if ($thisfile_riff_audio['bits_per_sample'] > 0) {
                     $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample'];
                 }
                 $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
                 if ($thisfile_audio['sample_rate'] == 0) {
                     $info['error'][] = 'Corrupted AIFF file: sample_rate == zero';
                     return false;
                 }
                 $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
             }
             if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
                 $offset = 0;
                 $CommentCount = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
                 $offset += 2;
                 for ($i = 0; $i < $CommentCount; $i++) {
                     $info['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false);
                     $offset += 4;
                     $info['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
                     $offset += 2;
                     $CommentLength = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
                     $offset += 2;
                     $info['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
                     $offset += $CommentLength;
                     $info['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($info['comments_raw'][$i]['timestamp']);
                     $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment'];
                 }
             }
             $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
             foreach ($CommentsChunkNames as $key => $value) {
                 if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
                     $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
                 }
             }
             if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
                 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.tag.id3v2.php', __FILE__, true);
                 $getid3_temp = new getID3();
                 $getid3_temp->openfile($this->getid3->filename);
                 $getid3_id3v2 = new getid3_id3v2($getid3_temp);
                 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
                 if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
                     $info['id3v2'] = $getid3_temp->info['id3v2'];
                 }
                 unset($getid3_temp, $getid3_id3v2);
             }
             break;
         case '8SVX':
             $thisfile_audio['bitrate_mode'] = 'cbr';
             $thisfile_audio_dataformat = '8svx';
             $thisfile_audio['bits_per_sample'] = 8;
             $thisfile_audio['channels'] = 1;
             // overridden below, if need be
             $info['mime_type'] = 'audio/x-aiff';
             if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
                 $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
                 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
                 if ($info['avdataend'] > $info['filesize']) {
                     $info['warning'][] = 'Probable truncated AIFF file: expecting ' . $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'] . ' bytes of audio data, only ' . ($info['filesize'] - $info['avdataoffset']) . ' bytes found';
                 }
             }
             if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
                 // shortcut
                 $thisfile_riff_RIFFsubtype_VHDR_0 =& $thisfile_riff[$RIFFsubtype]['VHDR'][0];
                 $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4));
                 $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4));
                 $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4));
                 $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2));
                 $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1));
                 $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1));
                 $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4));
                 $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
                 switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
                     case 0:
                         $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
                         $thisfile_audio['lossless'] = true;
                         $ActualBitsPerSample = 8;
                         break;
                     case 1:
                         $thisfile_audio['codec'] = 'Fibonacci-delta encoding';
                         $thisfile_audio['lossless'] = false;
                         $ActualBitsPerSample = 4;
                         break;
                     default:
                         $info['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "' . sCompression . '"';
                         break;
                 }
             }
             if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) {
                 $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4));
                 switch ($ChannelsIndex) {
                     case 6:
                         // Stereo
                         $thisfile_audio['channels'] = 2;
                         break;
                     case 2:
                         // Left channel only
                     // Left channel only
                     case 4:
                         // Right channel only
                         $thisfile_audio['channels'] = 1;
                         break;
                     default:
                         $info['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "' . $ChannelsIndex . '"';
                         break;
                 }
             }
             $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
             foreach ($CommentsChunkNames as $key => $value) {
                 if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
                     $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
                 }
             }
             $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels'];
             if (!empty($thisfile_audio['bitrate'])) {
                 $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8);
             }
             break;
         case 'CDXA':
             $info['mime_type'] = 'video/mpeg';
             if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
                 if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio-video.mpeg.php', __FILE__, false)) {
                     $getid3_temp = new getID3();
                     $getid3_temp->openfile($this->getid3->filename);
                     $getid3_mpeg = new getid3_mpeg($getid3_temp);
                     $getid3_mpeg->Analyze();
                     if (empty($getid3_temp->info['error'])) {
                         $info['audio'] = $getid3_temp->info['audio'];
                         $info['video'] = $getid3_temp->info['video'];
                         $info['mpeg'] = $getid3_temp->info['mpeg'];
                         $info['warning'] = $getid3_temp->info['warning'];
                     }
                     unset($getid3_temp, $getid3_mpeg);
                 }
             }
             break;
         default:
             $info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "' . $RIFFsubtype . '" instead';
             unset($info['fileformat']);
             break;
     }
     if (isset($thisfile_riff_raw['fmt ']['wFormatTag']) && $thisfile_riff_raw['fmt ']['wFormatTag'] == 1) {
         // http://www.mega-nerd.com/erikd/Blog/Windiots/dts.html
         fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
         $FirstFourBytes = fread($this->getid3->fp, 4);
         if (preg_match('/^\\xFF\\x1F\\x00\\xE8/s', $FirstFourBytes)) {
             // DTSWAV
             $thisfile_audio_dataformat = 'dts';
         } elseif (preg_match('/^\\x7F\\xFF\\x80\\x01/s', $FirstFourBytes)) {
             // DTS, but this probably shouldn't happen
             $thisfile_audio_dataformat = 'dts';
         }
     }
     if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) {
         $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4));
     }
     if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
         $this->RIFFcommentsParse($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
     }
     if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) {
         $this->RIFFcommentsParse($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']);
     }
     if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) {
         $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version'];
     }
     if (!isset($info['playtime_seconds'])) {
         $info['playtime_seconds'] = 0;
     }
     if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
         // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
         $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
     } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
         $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
     }
     if ($info['playtime_seconds'] > 0) {
         if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
             if (!isset($info['bitrate'])) {
                 $info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'] * 8;
             }
         } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
             if (!isset($thisfile_audio['bitrate'])) {
                 $thisfile_audio['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'] * 8;
             }
         } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
             if (!isset($thisfile_video['bitrate'])) {
                 $thisfile_video['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'] * 8;
             }
         }
     }
     if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && $thisfile_audio['bitrate'] > 0 && $info['playtime_seconds'] > 0) {
         $info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'] * 8;
         $thisfile_audio['bitrate'] = 0;
         $thisfile_video['bitrate'] = $info['bitrate'];
         foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) {
             $thisfile_video['bitrate'] -= $audioinfoarray['bitrate'];
             $thisfile_audio['bitrate'] += $audioinfoarray['bitrate'];
         }
         if ($thisfile_video['bitrate'] <= 0) {
             unset($thisfile_video['bitrate']);
         }
         if ($thisfile_audio['bitrate'] <= 0) {
             unset($thisfile_audio['bitrate']);
         }
     }
     if (isset($info['mpeg']['audio'])) {
         $thisfile_audio_dataformat = 'mp' . $info['mpeg']['audio']['layer'];
         $thisfile_audio['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
         $thisfile_audio['channels'] = $info['mpeg']['audio']['channels'];
         $thisfile_audio['bitrate'] = $info['mpeg']['audio']['bitrate'];
         $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
         if (!empty($info['mpeg']['audio']['codec'])) {
             $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'] . ' ' . $thisfile_audio['codec'];
         }
         if (!empty($thisfile_audio['streams'])) {
             foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) {
                 if ($streamdata['dataformat'] == $thisfile_audio_dataformat) {
                     $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate'];
                     $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels'];
                     $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate'];
                     $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
                     $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec'];
                 }
             }
         }
         $getid3_mp3 = new getid3_mp3($this->getid3);
         $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions();
         unset($getid3_mp3);
     }
     if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && $thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0) {
         switch ($thisfile_audio_dataformat) {
             case 'ac3':
                 // ignore bits_per_sample
                 break;
             default:
                 $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
                 break;
         }
     }
     if (empty($thisfile_riff_raw)) {
         unset($thisfile_riff['raw']);
     }
     if (empty($thisfile_riff_audio)) {
         unset($thisfile_riff['audio']);
     }
     if (empty($thisfile_riff_video)) {
         unset($thisfile_riff['video']);
     }
     return true;
 }
 function getid3_matroska(&$fd, &$ThisFileInfo)
 {
     // http://www.matroska.org/technical/specs/index.html#EBMLBasics
     $offset = $ThisFileInfo['avdataoffset'];
     $EBMLdata = '';
     $EBMLdata_offset = $offset;
     if ($ThisFileInfo['avdataend'] > 2147483648) {
         $this->warnings[] = 'This version of getID3() may or may not correctly handle Matroska files larger than 2GB';
     }
     while ($offset < $ThisFileInfo['avdataend']) {
         $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
         $top_element_offset = $offset;
         $top_element_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
         $top_element_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
         if ($top_element_length === false) {
             $this->warnings[] = 'invalid chunk length at ' . $top_element_offset;
             $offset = pow(2, 63);
             break;
         }
         $top_element_endoffset = $offset + $top_element_length;
         switch ($top_element_id) {
             case EBML_ID_EBML:
                 $ThisFileInfo['fileformat'] = 'matroska';
                 $ThisFileInfo['matroska']['header']['offset'] = $top_element_offset;
                 $ThisFileInfo['matroska']['header']['length'] = $top_element_length;
                 while ($offset < $top_element_endoffset) {
                     $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                     $element_data = array();
                     $element_data_offset = $offset;
                     $element_data['id'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                     $element_data['id_name'] = $this->EBMLidName($element_data['id']);
                     $element_data_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                     $end_offset = $offset + $element_data_length;
                     switch ($element_data['id']) {
                         case EBML_ID_EBMLVERSION:
                         case EBML_ID_EBMLREADVERSION:
                         case EBML_ID_EBMLMAXIDLENGTH:
                         case EBML_ID_EBMLMAXSIZELENGTH:
                         case EBML_ID_DOCTYPEVERSION:
                         case EBML_ID_DOCTYPEREADVERSION:
                             $element_data['data'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $element_data_length));
                             break;
                         case EBML_ID_DOCTYPE:
                             $element_data['data'] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $element_data_length), "");
                             break;
                         default:
                             $this->warnings[] = 'Unhandled track.video element[' . __LINE__ . '] (' . $element_data['id'] . '::' . $element_data['id_name'] . ') at ' . $element_data_offset;
                             break;
                     }
                     $offset = $end_offset;
                     $ThisFileInfo['matroska']['header']['elements'][] = $element_data;
                 }
                 break;
             case EBML_ID_SEGMENT:
                 $ThisFileInfo['matroska']['segment'][0]['offset'] = $top_element_offset;
                 $ThisFileInfo['matroska']['segment'][0]['length'] = $top_element_length;
                 $segment_key = -1;
                 while ($offset < $ThisFileInfo['avdataend']) {
                     $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                     $element_data = array();
                     $element_data['offset'] = $offset;
                     $element_data['id'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                     $element_data['id_name'] = $this->EBMLidName($element_data['id']);
                     $element_data_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                     if ($element_data_length === false) {
                         $this->warnings[] = 'invalid chunk length at ' . $element_data['offset'];
                         $offset = pow(2, 63);
                         break;
                     }
                     $element_end = $offset + $element_data_length;
                     switch ($element_data['id']) {
                         //case EBML_ID_CLUSTER:
                         //	// too many cluster entries, probably not useful
                         //	break;
                         case false:
                             $this->warnings[] = 'invalid ID at ' . $element_data['offset'];
                             $offset = $element_end;
                             continue 3;
                         default:
                             $ThisFileInfo['matroska']['segments'][] = $element_data;
                             break;
                     }
                     $segment_key++;
                     switch ($element_data['id']) {
                         case EBML_ID_SEEKHEAD:
                             // Contains the position of other level 1 elements
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                 $seek_entry = array();
                                 $seek_entry['offset'] = $offset;
                                 $seek_entry['id'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $seek_entry['id_name'] = $this->EBMLidName($seek_entry['id']);
                                 $seek_entry['length'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $seek_end_offset = $offset + $seek_entry['length'];
                                 switch ($seek_entry['id']) {
                                     case EBML_ID_SEEK:
                                         // Contains a single seek entry to an EBML element
                                         while ($offset < $seek_end_offset) {
                                             $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                             $id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $value = substr($EBMLdata, $offset - $EBMLdata_offset, $length);
                                             $offset += $length;
                                             switch ($id) {
                                                 case EBML_ID_SEEKID:
                                                     $dummy = 0;
                                                     $seek_entry['target_id'] = $this->readEBMLint($value, $dummy);
                                                     $seek_entry['target_name'] = $this->EBMLidName($seek_entry['target_id']);
                                                     break;
                                                 case EBML_ID_SEEKPOSITION:
                                                     $seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($value);
                                                     break;
                                                 default:
                                                     $ThisFileInfo['error'][] = 'Unhandled segment[' . __LINE__ . '] (' . $id . ') at ' . $offset;
                                                     break;
                                             }
                                         }
                                         $ThisFileInfo['matroska']['seek'][] = $seek_entry;
                                         //switch ($seek_entry['target_id']) {
                                         //	case EBML_ID_CLUSTER:
                                         //		// too many cluster seek points, probably not useful
                                         //		break;
                                         //	default:
                                         //		$ThisFileInfo['matroska']['seek'][] = $seek_entry;
                                         //		break;
                                         //}
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled seekhead element[' . __LINE__ . '] (' . $seek_entry['id'] . ') at ' . $offset;
                                         break;
                                 }
                                 $offset = $seek_end_offset;
                             }
                             break;
                         case EBML_ID_TRACKS:
                             // information about all tracks in segment
                             $ThisFileInfo['matroska']['tracks'] = $element_data;
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                 $track_entry = array();
                                 $track_entry['offset'] = $offset;
                                 $track_entry['id'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $track_entry['id_name'] = $this->EBMLidName($track_entry['id']);
                                 $track_entry['length'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $track_entry_endoffset = $offset + $track_entry['length'];
                                 switch ($track_entry['id']) {
                                     case EBML_ID_TRACKENTRY:
                                         //subelements: Describes a track with all elements.
                                         while ($offset < $track_entry_endoffset) {
                                             $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                             $subelement_offset = $offset;
                                             $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $subelement_idname = $this->EBMLidName($subelement_id);
                                             $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $subelement_end = $offset + $subelement_length;
                                             switch ($subelement_id) {
                                                 case EBML_ID_TRACKNUMBER:
                                                 case EBML_ID_TRACKUID:
                                                 case EBML_ID_TRACKTYPE:
                                                 case EBML_ID_MINCACHE:
                                                 case EBML_ID_MAXCACHE:
                                                 case EBML_ID_MAXBLOCKADDITIONID:
                                                 case EBML_ID_DEFAULTDURATION:
                                                     // nanoseconds per frame
                                                     $track_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                                     break;
                                                 case EBML_ID_TRACKTIMECODESCALE:
                                                     $track_entry[$subelement_idname] = getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                                     break;
                                                 case EBML_ID_CODECID:
                                                 case EBML_ID_LANGUAGE:
                                                 case EBML_ID_NAME:
                                                 case EBML_ID_CODECPRIVATE:
                                                     $track_entry[$subelement_idname] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "");
                                                     break;
                                                 case EBML_ID_FLAGENABLED:
                                                 case EBML_ID_FLAGDEFAULT:
                                                 case EBML_ID_FLAGFORCED:
                                                 case EBML_ID_FLAGLACING:
                                                 case EBML_ID_CODECDECODEALL:
                                                     $track_entry[$subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                                     break;
                                                 case EBML_ID_VIDEO:
                                                     while ($offset < $subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_offset = $offset;
                                                         $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                                         $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_end = $offset + $sub_subelement_length;
                                                         switch ($sub_subelement_id) {
                                                             case EBML_ID_PIXELWIDTH:
                                                             case EBML_ID_PIXELHEIGHT:
                                                             case EBML_ID_STEREOMODE:
                                                             case EBML_ID_PIXELCROPBOTTOM:
                                                             case EBML_ID_PIXELCROPTOP:
                                                             case EBML_ID_PIXELCROPLEFT:
                                                             case EBML_ID_PIXELCROPRIGHT:
                                                             case EBML_ID_DISPLAYWIDTH:
                                                             case EBML_ID_DISPLAYHEIGHT:
                                                             case EBML_ID_DISPLAYUNIT:
                                                             case EBML_ID_ASPECTRATIOTYPE:
                                                                 $track_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_FLAGINTERLACED:
                                                                 $track_entry[$sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_GAMMAVALUE:
                                                                 $track_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_COLOURSPACE:
                                                                 $track_entry[$sub_subelement_idname] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length), "");
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled track.video element[' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_subelement_end;
                                                     }
                                                     if (@$track_entry[$this->EBMLidName(EBML_ID_CODECID)] == 'V_MS/VFW/FOURCC' && isset($track_entry[$this->EBMLidName(EBML_ID_CODECPRIVATE)])) {
                                                         if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio-video.riff.php', __FILE__, false)) {
                                                             $track_entry['codec_private_parsed'] = getid3_riff::ParseBITMAPINFOHEADER($track_entry[$this->EBMLidName(EBML_ID_CODECPRIVATE)]);
                                                         } else {
                                                             $this->warnings[] = 'Unable to parse codec private data[' . __LINE__ . '] because cannot include "module.audio-video.riff.php"';
                                                         }
                                                     }
                                                     break;
                                                 case EBML_ID_AUDIO:
                                                     while ($offset < $subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_offset = $offset;
                                                         $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                                         $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_subelement_end = $offset + $sub_subelement_length;
                                                         switch ($sub_subelement_id) {
                                                             case EBML_ID_CHANNELS:
                                                             case EBML_ID_BITDEPTH:
                                                                 $track_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_SAMPLINGFREQUENCY:
                                                             case EBML_ID_OUTPUTSAMPLINGFREQUENCY:
                                                                 $track_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_CHANNELPOSITIONS:
                                                                 $track_entry[$sub_subelement_idname] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length), "");
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled track.video element[' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_subelement_end;
                                                     }
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled track element[' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ') at ' . $subelement_offset;
                                                     break;
                                             }
                                             $offset = $subelement_end;
                                         }
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled track element[' . __LINE__ . '] (' . $track_entry['id'] . '::' . $track_entry['id_name'] . ') at ' . $track_entry['offset'];
                                         $offset = $track_entry_endoffset;
                                         break;
                                 }
                                 $ThisFileInfo['matroska']['tracks']['tracks'][] = $track_entry;
                             }
                             break;
                         case EBML_ID_INFO:
                             // Contains the position of other level 1 elements
                             $info_entry = array();
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 switch ($subelement_id) {
                                     case EBML_ID_CHAPTERTRANSLATEEDITIONUID:
                                     case EBML_ID_CHAPTERTRANSLATECODEC:
                                     case EBML_ID_TIMECODESCALE:
                                         $info_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                         break;
                                     case EBML_ID_DURATION:
                                         $info_entry[$subelement_idname] = getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                         break;
                                     case EBML_ID_DATEUTC:
                                         $info_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
                                         $info_entry[$subelement_idname . '_unix'] = $this->EBMLdate2unix($info_entry[$subelement_idname]);
                                         break;
                                     case EBML_ID_SEGMENTUID:
                                     case EBML_ID_PREVUID:
                                     case EBML_ID_NEXTUID:
                                     case EBML_ID_SEGMENTFAMILY:
                                     case EBML_ID_CHAPTERTRANSLATEID:
                                         $info_entry[$subelement_idname] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "");
                                         break;
                                     case EBML_ID_SEGMENTFILENAME:
                                     case EBML_ID_PREVFILENAME:
                                     case EBML_ID_NEXTFILENAME:
                                     case EBML_ID_TITLE:
                                     case EBML_ID_MUXINGAPP:
                                     case EBML_ID_WRITINGAPP:
                                         $info_entry[$subelement_idname] = trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "");
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled info element[' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ') at ' . $subelement_offset;
                                         break;
                                 }
                                 $offset = $subelement_end;
                             }
                             $ThisFileInfo['matroska']['info'][] = $info_entry;
                             break;
                         case EBML_ID_CUES:
                             $cues_entry = array();
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 switch ($subelement_id) {
                                     case EBML_ID_CUEPOINT:
                                         $cuepoint_entry = array();
                                         while ($offset < $subelement_end) {
                                             $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_offset = $offset;
                                             $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                             $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_end = $offset + $sub_subelement_length;
                                             switch ($sub_subelement_id) {
                                                 case EBML_ID_CUETRACKPOSITIONS:
                                                     while ($offset < $sub_subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_offset = $offset;
                                                         $sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                         $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_end = $offset + $sub_sub_subelement_length;
                                                         switch ($sub_sub_subelement_id) {
                                                             case EBML_ID_CUETRACK:
                                                                 $cuepoint_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled cues.cuepoint.cuetrackpositions element[' . __LINE__ . '] (' . $sub_sub_subelement_id . '::' . $sub_sub_subelement_idname . ') at ' . $sub_sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_subelement_end;
                                                     }
                                                     break;
                                                 case EBML_ID_CUETIME:
                                                     $cuepoint_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled cues.cuepoint element[' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                     break;
                                             }
                                             $offset = $sub_subelement_end;
                                         }
                                         $cues_entry[] = $cuepoint_entry;
                                         $offset = $sub_subelement_end;
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled cues element[' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ') at ' . $subelement_offset;
                                         break;
                                 }
                                 $offset = $subelement_end;
                             }
                             $ThisFileInfo['matroska']['cues'] = $cues_entry;
                             break;
                         case EBML_ID_TAGS:
                             $tags_entry = array();
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 switch ($subelement_id) {
                                     case EBML_ID_WRITINGAPP:
                                         $tags_entry[$subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length);
                                         break;
                                     case EBML_ID_TAG:
                                         $tag_entry = array();
                                         while ($offset < $subelement_end) {
                                             $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_offset = $offset;
                                             $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                             $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_end = $offset + $sub_subelement_length;
                                             switch ($sub_subelement_id) {
                                                 case EBML_ID_TARGETS:
                                                     $targets_entry = array();
                                                     while ($offset < $sub_subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_offset = $offset;
                                                         $sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                         $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_end = $offset + $sub_sub_subelement_length;
                                                         switch ($sub_sub_subelement_id) {
                                                             case EBML_ID_TARGETTYPEVALUE:
                                                             case EBML_ID_EDITIONUID:
                                                             case EBML_ID_CHAPTERUID:
                                                             case EBML_ID_ATTACHMENTUID:
                                                             case EBML_ID_TAGTRACKUID:
                                                             case EBML_ID_TAGCHAPTERUID:
                                                                 $targets_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled tag.targets element[' . __LINE__ . '] (' . $sub_sub_subelement_id . '::' . $sub_sub_subelement_idname . ') at ' . $sub_sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_sub_subelement_end;
                                                     }
                                                     $tag_entry[$sub_subelement_idname][] = $targets_entry;
                                                     break;
                                                 case EBML_ID_SIMPLETAG:
                                                     $simpletag_entry = array();
                                                     while ($offset < $sub_subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_offset = $offset;
                                                         $sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                         $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_end = $offset + $sub_sub_subelement_length;
                                                         switch ($sub_sub_subelement_id) {
                                                             case EBML_ID_TAGNAME:
                                                             case EBML_ID_TAGLANGUAGE:
                                                             case EBML_ID_TAGSTRING:
                                                             case EBML_ID_TAGBINARY:
                                                                 $simpletag_entry[$sub_sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length);
                                                                 break;
                                                             case EBML_ID_TAGDEFAULT:
                                                                 $simpletag_entry[$sub_sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled tag.simpletag element[' . __LINE__ . '] (' . $sub_sub_subelement_id . '::' . $sub_sub_subelement_idname . ') at ' . $sub_sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_sub_subelement_end;
                                                     }
                                                     $tag_entry[$sub_subelement_idname][] = $simpletag_entry;
                                                     break;
                                                 case EBML_ID_TARGETTYPE:
                                                     $tag_entry[$sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
                                                     break;
                                                 case EBML_ID_TRACKUID:
                                                     $tag_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled tags.tag element[' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                     break;
                                             }
                                             $offset = $sub_subelement_end;
                                         }
                                         $tags_entry['tags'][] = $tag_entry;
                                         $offset = $sub_subelement_end;
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled tags element[' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ') at ' . $subelement_offset;
                                         break;
                                 }
                                 $offset = $subelement_end;
                             }
                             $ThisFileInfo['matroska']['tags'] = $tags_entry;
                             break;
                         case EBML_ID_ATTACHMENTS:
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 switch ($subelement_id) {
                                     case EBML_ID_ATTACHEDFILE:
                                         $attachedfile_entry = array();
                                         while ($offset < $subelement_end) {
                                             $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_offset = $offset;
                                             $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                             $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_end = $offset + $sub_subelement_length;
                                             switch ($sub_subelement_id) {
                                                 case EBML_ID_FILEDESCRIPTION:
                                                 case EBML_ID_FILENAME:
                                                 case EBML_ID_FILEMIMETYPE:
                                                     $attachedfile_entry[$sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
                                                     break;
                                                 case EBML_ID_FILEDATA:
                                                     $attachedfile_entry['data_offset'] = $offset;
                                                     $attachedfile_entry['data_length'] = $sub_subelement_length;
                                                     if ($sub_subelement_length < 1024) {
                                                         $attachedfile_entry[$sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
                                                     }
                                                     break;
                                                 case EBML_ID_FILEUID:
                                                     $attachedfile_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled attachment.attachedfile element[' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                     break;
                                             }
                                             $offset = $sub_subelement_end;
                                         }
                                         $ThisFileInfo['matroska']['attachments'][] = $attachedfile_entry;
                                         $offset = $sub_subelement_end;
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled tags element[' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ') at ' . $subelement_offset;
                                         break;
                                 }
                                 $offset = $subelement_end;
                             }
                             break;
                         case EBML_ID_CHAPTERS:
                             // not important to us, contains mostly actual audio/video data, ignore
                             while ($offset < $element_end) {
                                 $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_offset = $offset;
                                 $subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_idname = $this->EBMLidName($subelement_id);
                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                 $subelement_end = $offset + $subelement_length;
                                 switch ($subelement_id) {
                                     case EBML_ID_EDITIONENTRY:
                                         $editionentry_entry = array();
                                         while ($offset < $subelement_end) {
                                             $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_offset = $offset;
                                             $sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
                                             $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                             $sub_subelement_end = $offset + $sub_subelement_length;
                                             switch ($sub_subelement_id) {
                                                 case EBML_ID_EDITIONUID:
                                                     $editionentry_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 case EBML_ID_EDITIONFLAGHIDDEN:
                                                 case EBML_ID_EDITIONFLAGDEFAULT:
                                                 case EBML_ID_EDITIONFLAGORDERED:
                                                     $editionentry_entry[$sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
                                                     break;
                                                 case EBML_ID_CHAPTERATOM:
                                                     $chapteratom_entry = array();
                                                     while ($offset < $sub_subelement_end) {
                                                         $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_offset = $offset;
                                                         $sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                         $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                         $sub_sub_subelement_end = $offset + $sub_sub_subelement_length;
                                                         switch ($sub_sub_subelement_id) {
                                                             case EBML_ID_CHAPTERSEGMENTUID:
                                                             case EBML_ID_CHAPTERSEGMENTEDITIONUID:
                                                                 $chapteratom_entry[$sub_sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length);
                                                                 break;
                                                             case EBML_ID_CHAPTERFLAGENABLED:
                                                             case EBML_ID_CHAPTERFLAGHIDDEN:
                                                                 $chapteratom_entry[$sub_sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_CHAPTERUID:
                                                             case EBML_ID_CHAPTERTIMESTART:
                                                             case EBML_ID_CHAPTERTIMEEND:
                                                                 $chapteratom_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                 break;
                                                             case EBML_ID_CHAPTERTRACK:
                                                                 $chaptertrack_entry = array();
                                                                 while ($offset < $sub_sub_subelement_end) {
                                                                     $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_offset = $offset;
                                                                     $sub_sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
                                                                     $sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_end = $offset + $sub_sub_sub_subelement_length;
                                                                     switch ($sub_sub_sub_subelement_id) {
                                                                         case EBML_ID_CHAPTERTRACKNUMBER:
                                                                             $chaptertrack_entry[$sub_sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
                                                                             break;
                                                                         default:
                                                                             $this->warnings[] = 'Unhandled chapters.editionentry.chapteratom.chaptertrack element[' . __LINE__ . '] (' . $sub_sub_sub_subelement_id . '::' . $sub_sub_sub_subelement_idname . ') at ' . $sub_sub_sub_subelement_offset;
                                                                             break;
                                                                     }
                                                                     $offset = $sub_sub_sub_subelement_end;
                                                                 }
                                                                 $chapteratom_entry[$sub_sub_subelement_idname][] = $chaptertrack_entry;
                                                                 break;
                                                             case EBML_ID_CHAPTERDISPLAY:
                                                                 $chapterdisplay_entry = array();
                                                                 while ($offset < $sub_sub_subelement_end) {
                                                                     $this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_offset = $offset;
                                                                     $sub_sub_sub_subelement_id = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_sub_subelement_id);
                                                                     $sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
                                                                     $sub_sub_sub_subelement_end = $offset + $sub_sub_sub_subelement_length;
                                                                     switch ($sub_sub_sub_subelement_id) {
                                                                         case EBML_ID_CHAPSTRING:
                                                                         case EBML_ID_CHAPLANGUAGE:
                                                                         case EBML_ID_CHAPCOUNTRY:
                                                                             $chapterdisplay_entry[$sub_sub_sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length);
                                                                             break;
                                                                         default:
                                                                             $this->warnings[] = 'Unhandled chapters.editionentry.chapteratom.chapterdisplay element[' . __LINE__ . '] (' . $sub_sub_sub_subelement_id . '::' . $sub_sub_sub_subelement_idname . ') at ' . $sub_sub_sub_subelement_offset;
                                                                             break;
                                                                     }
                                                                     $offset = $sub_sub_sub_subelement_end;
                                                                 }
                                                                 $chapteratom_entry[$sub_sub_subelement_idname][] = $chapterdisplay_entry;
                                                                 break;
                                                             default:
                                                                 $this->warnings[] = 'Unhandled chapters.editionentry.chapteratom element[' . __LINE__ . '] (' . $sub_sub_subelement_id . '::' . $sub_sub_subelement_idname . ') at ' . $sub_sub_subelement_offset;
                                                                 break;
                                                         }
                                                         $offset = $sub_sub_subelement_end;
                                                     }
                                                     $editionentry_entry[$sub_subelement_idname][] = $chapteratom_entry;
                                                     break;
                                                 default:
                                                     $this->warnings[] = 'Unhandled chapters.editionentry element[' . __LINE__ . '] (' . $sub_subelement_id . '::' . $sub_subelement_idname . ') at ' . $sub_subelement_offset;
                                                     break;
                                             }
                                             $offset = $sub_subelement_end;
                                         }
                                         $ThisFileInfo['matroska']['chapters'][] = $editionentry_entry;
                                         $offset = $sub_subelement_end;
                                         break;
                                     default:
                                         $this->warnings[] = 'Unhandled chapters element[' . __LINE__ . '] (' . $subelement_id . '::' . $subelement_idname . ') at ' . $subelement_offset;
                                         break;
                                 }
                                 $offset = $subelement_end;
                             }
                             break;
                         case EBML_ID_VOID:
                             // padding, ignore
                         // padding, ignore
                         case EBML_ID_CLUSTER:
                             // not important to us, contains mostly actual audio/video data, ignore
                             break;
                         default:
                             if ($element_data['id_name'] == dechex($element_data['id'])) {
                                 $ThisFileInfo['error'][] = 'Unhandled segment[' . __LINE__ . '] (' . $element_data['id'] . ') at ' . $element_data_offset;
                             } else {
                                 $this->warnings[] = 'Unhandled segment[' . __LINE__ . '] (' . $element_data['id'] . '::' . $element_data['id_name'] . ') at ' . $element_data['offset'];
                             }
                             break;
                     }
                     $offset = $element_end;
                 }
                 break;
             default:
                 $ThisFileInfo['error'][] = 'Unhandled chunk[' . __LINE__ . '] (' . $top_element_id . ') at ' . $offset;
                 break;
         }
         $offset = $top_element_endoffset;
     }
     if ($this->hide_clusters) {
         // too much data returned that is usually not useful
         if (isset($ThisFileInfo['matroska']['segments']) && is_array($ThisFileInfo['matroska']['segments'])) {
             foreach ($ThisFileInfo['matroska']['segments'] as $key => $segmentsarray) {
                 if ($segmentsarray['id'] == EBML_ID_CLUSTER) {
                     unset($ThisFileInfo['matroska']['segments'][$key]);
                 }
             }
         }
         if (isset($ThisFileInfo['matroska']['seek']) && is_array($ThisFileInfo['matroska']['seek'])) {
             foreach ($ThisFileInfo['matroska']['seek'] as $key => $seekarray) {
                 if ($seekarray['target_id'] == EBML_ID_CLUSTER) {
                     unset($ThisFileInfo['matroska']['seek'][$key]);
                 }
             }
         }
     }
     if (isset($ThisFileInfo['matroska']['info']) && is_array($ThisFileInfo['matroska']['info'])) {
         foreach ($ThisFileInfo['matroska']['info'] as $key => $infoarray) {
             if (isset($infoarray['Duration'])) {
                 // TimecodeScale is how many nanoseconds each Duration unit is
                 $ThisFileInfo['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000);
                 break;
             }
         }
     }
     if (isset($ThisFileInfo['matroska']['tracks']['tracks']) && is_array($ThisFileInfo['matroska']['tracks']['tracks'])) {
         foreach ($ThisFileInfo['matroska']['tracks']['tracks'] as $key => $trackarray) {
             $track_info = array();
             switch (@$trackarray['TrackType']) {
                 case 1:
                     // Video
                     if (@$trackarray['PixelWidth']) {
                         $track_info['resolution_x'] = $trackarray['PixelWidth'];
                     }
                     if (@$trackarray['PixelHeight']) {
                         $track_info['resolution_y'] = $trackarray['PixelHeight'];
                     }
                     if (@$trackarray['DisplayWidth']) {
                         $track_info['display_x'] = $trackarray['DisplayWidth'];
                     }
                     if (@$trackarray['DisplayHeight']) {
                         $track_info['display_y'] = $trackarray['DisplayHeight'];
                     }
                     if (@$trackarray['DefaultDuration']) {
                         $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3);
                     }
                     if (@$trackarray['CodecID']) {
                         $track_info['codec'] = $this->MatroskaCodecIDtoCommonName($trackarray['CodecID']);
                     }
                     if (!empty($trackarray['codec_private_parsed']['fourcc'])) {
                         $track_info['fourcc'] = $trackarray['codec_private_parsed']['fourcc'];
                     }
                     $ThisFileInfo['video']['streams'][] = $track_info;
                     if (isset($track_info['resolution_x']) && empty($ThisFileInfo['video']['resolution_x'])) {
                         foreach ($track_info as $key => $value) {
                             $ThisFileInfo['video'][$key] = $value;
                         }
                     }
                     break;
                 case 2:
                     // Audio
                     if (@$trackarray['CodecID']) {
                         $track_info['dataformat'] = $this->MatroskaCodecIDtoCommonName($trackarray['CodecID']);
                     }
                     if (@$trackarray['SamplingFrequency']) {
                         $track_info['sample_rate'] = $trackarray['SamplingFrequency'];
                     }
                     if (@$trackarray['Channels']) {
                         $track_info['channels'] = $trackarray['Channels'];
                     }
                     if (@$trackarray['BitDepth']) {
                         $track_info['bits_per_sample'] = $trackarray['BitDepth'];
                     }
                     switch (@$trackarray[$this->EBMLidName(EBML_ID_CODECID)]) {
                         case 'A_PCM/INT/LIT':
                         case 'A_PCM/INT/BIG':
                             $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
                             break;
                         default:
                             break;
                     }
                     $ThisFileInfo['audio']['streams'][] = $track_info;
                     if (isset($track_info['dataformat']) && empty($ThisFileInfo['audio']['dataformat'])) {
                         foreach ($track_info as $key => $value) {
                             $ThisFileInfo['audio'][$key] = $value;
                         }
                     }
                     break;
                 default:
                     // ignore, do nothing
                     break;
             }
         }
     }
     if (!empty($ThisFileInfo['video']['streams'])) {
         $ThisFileInfo['mime_type'] = 'video/x-matroska';
     } elseif (!empty($ThisFileInfo['video']['streams'])) {
         $ThisFileInfo['mime_type'] = 'audio/x-matroska';
     } elseif (isset($ThisFileInfo['mime_type'])) {
         unset($ThisFileInfo['mime_type']);
     }
     foreach ($this->warnings as $key => $value) {
         $ThisFileInfo['warning'][] = $value;
     }
     return true;
 }
	function getid3_matroska(&$fd, &$ThisFileInfo) {

		// http://www.matroska.org/technical/specs/index.html#EBMLBasics
		$offset = $ThisFileInfo['avdataoffset'];
		$EBMLdata = '';
		$EBMLdata_offset = $offset;

		if ($ThisFileInfo['avdataend'] > 2147483648) {
			$this->warnings[] = 'This version of getID3() may or may not correctly handle Matroska files larger than 2GB';
		}

		while ($offset < $ThisFileInfo['avdataend']) {
			$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);

			$top_element_offset    = $offset;
			$top_element_id        = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
			$top_element_length    = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
			if ($top_element_length === false) {
				$this->warnings[] = 'invalid chunk length at '.$top_element_offset;
				$offset = pow(2, 63);
				break;
			}
			$top_element_endoffset = $offset + $top_element_length;
			switch ($top_element_id) {
				case EBML_ID_EBML:
					$ThisFileInfo['fileformat'] = 'matroska';
					$ThisFileInfo['matroska']['header']['offset'] = $top_element_offset;
					$ThisFileInfo['matroska']['header']['length'] = $top_element_length;

					while ($offset < $top_element_endoffset) {
						$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
						$element_data = array();
						$element_data_offset     = $offset;
						$element_data['id']      = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
						$element_data['id_name'] = $this->EBMLidName($element_data['id']);
						$element_data['length']     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
						$end_offset              = $offset + $element_data['length'];

						switch ($element_data['id']) {
							case EBML_ID_VOID:    // padding, ignore
								break;
							case EBML_ID_EBMLVERSION:
							case EBML_ID_EBMLREADVERSION:
							case EBML_ID_EBMLMAXIDLENGTH:
							case EBML_ID_EBMLMAXSIZELENGTH:
							case EBML_ID_DOCTYPEVERSION:
							case EBML_ID_DOCTYPEREADVERSION:
								$element_data['data'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $element_data['length']));
								break;
							case EBML_ID_DOCTYPE:
								$element_data['data'] =                      trim(substr($EBMLdata, $offset - $EBMLdata_offset, $element_data['length']), "\x00");
								break;
							default:
								$this->warnings[] = 'Unhandled track.video element ['.basename(__FILE__).':'.__LINE__.'] ('.$element_data['id'].'::'.$element_data['id_name'].') at '.$element_data_offset;
								break;
						}
						$offset = $end_offset;
						$ThisFileInfo['matroska']['header']['elements'][] = $element_data;
					}
					break;


				case EBML_ID_SEGMENT:
					$ThisFileInfo['matroska']['segment'][0]['offset'] = $top_element_offset;
					$ThisFileInfo['matroska']['segment'][0]['length'] = $top_element_length;

					$segment_key = -1;
					while ($offset < $ThisFileInfo['avdataend']) {
						$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);

						$element_data = array();
						$element_data['offset']  = $offset;
						$element_data['id']      = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
						$element_data['id_name'] = $this->EBMLidName($element_data['id']);
						$element_data['length']  = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
						if ($element_data['length'] === false) {
							$this->warnings[] = 'invalid chunk length at '.$element_data['offset'];
							//$offset = pow(2, 63);
							$offset = $ThisFileInfo['avdataend'];
							break;
						}
						$element_end             = $offset + $element_data['length'];
						switch ($element_data['id']) {
							//case EBML_ID_CLUSTER:
							//	// too many cluster entries, probably not useful
							//	break;
							case false:
								$this->warnings[] = 'invalid ID at '.$element_data['offset'];
								$offset = $element_end;
								continue 3;
							default:
								$ThisFileInfo['matroska']['segments'][] = $element_data;
								break;
						}
						$segment_key++;

						switch ($element_data['id']) {
							case EBML_ID_SEEKHEAD: // Contains the position of other level 1 elements
								while ($offset < $element_end) {
									$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
									$seek_entry = array();
									$seek_entry['offset']  = $offset;
									$seek_entry['id']      = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$seek_entry['id_name'] = $this->EBMLidName($seek_entry['id']);
									$seek_entry['length']  = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$seek_end_offset       = $offset + $seek_entry['length'];
									switch ($seek_entry['id']) {
										case EBML_ID_SEEK: // Contains a single seek entry to an EBML element
											while ($offset < $seek_end_offset) {
												$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
												$id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$value  =             substr($EBMLdata, $offset - $EBMLdata_offset, $length);
												$offset += $length;
												switch ($id) {
													case EBML_ID_SEEKID:
														$dummy = 0;
														$seek_entry['target_id']   = $this->readEBMLint($value, $dummy);
														$seek_entry['target_name'] = $this->EBMLidName($seek_entry['target_id']);
														break;
													case EBML_ID_SEEKPOSITION:
														$seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($value);
														break;
													default:
														$ThisFileInfo['error'][] = 'Unhandled segment ['.basename(__FILE__).':'.__LINE__.'] ('.$id.') at '.$offset;
														break;
												}
											}
											$ThisFileInfo['matroska']['seek'][] = $seek_entry;
											//switch ($seek_entry['target_id']) {
											//	case EBML_ID_CLUSTER:
											//		// too many cluster seek points, probably not useful
											//		break;
											//	default:
											//		$ThisFileInfo['matroska']['seek'][] = $seek_entry;
											//		break;
											//}
											break;
										default:
											$this->warnings[] = 'Unhandled seekhead element ['.basename(__FILE__).':'.__LINE__.'] ('.$seek_entry['id'].') at '.$offset;
											break;
									}
									$offset = $seek_end_offset;
								}
								break;

							case EBML_ID_TRACKS: // information about all tracks in segment
								$ThisFileInfo['matroska']['tracks'] = $element_data;
								while ($offset < $element_end) {
									$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
									$track_entry = array();
									$track_entry['offset']  = $offset;
									$track_entry['id']      = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$track_entry['id_name'] = $this->EBMLidName($track_entry['id']);
									$track_entry['length']  = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$track_entry_endoffset  = $offset + $track_entry['length'];
									switch ($track_entry['id']) {
										case EBML_ID_TRACKENTRY: //subelements: Describes a track with all elements.
											while ($offset < $track_entry_endoffset) {
												$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
												$subelement_offset = $offset;
												$subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$subelement_idname = $this->EBMLidName($subelement_id);
												$subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$subelement_end    = $offset + $subelement_length;
												switch ($subelement_id) {
													case EBML_ID_TRACKNUMBER:
													case EBML_ID_TRACKUID:
													case EBML_ID_TRACKTYPE:
													case EBML_ID_MINCACHE:
													case EBML_ID_MAXCACHE:
													case EBML_ID_MAXBLOCKADDITIONID:
													case EBML_ID_DEFAULTDURATION: // nanoseconds per frame
														$track_entry[$subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
														break;

													case EBML_ID_TRACKTIMECODESCALE:
														$track_entry[$subelement_idname] =      getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
														break;

													case EBML_ID_CODECID:
													case EBML_ID_LANGUAGE:
													case EBML_ID_NAME:
													case EBML_ID_CODECNAME:
													case EBML_ID_CODECPRIVATE:
														$track_entry[$subelement_idname] =                              trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "\x00");
														break;

													case EBML_ID_FLAGENABLED:
													case EBML_ID_FLAGDEFAULT:
													case EBML_ID_FLAGFORCED:
													case EBML_ID_FLAGLACING:
													case EBML_ID_CODECDECODEALL:
														$track_entry[$subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
														break;

													case EBML_ID_VIDEO:
														while ($offset < $subelement_end) {
															$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
															$sub_subelement_offset = $offset;
															$sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
															$sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_subelement_end    = $offset + $sub_subelement_length;
															switch ($sub_subelement_id) {
																case EBML_ID_PIXELWIDTH:
																case EBML_ID_PIXELHEIGHT:
																case EBML_ID_STEREOMODE:
																case EBML_ID_PIXELCROPBOTTOM:
																case EBML_ID_PIXELCROPTOP:
																case EBML_ID_PIXELCROPLEFT:
																case EBML_ID_PIXELCROPRIGHT:
																case EBML_ID_DISPLAYWIDTH:
																case EBML_ID_DISPLAYHEIGHT:
																case EBML_ID_DISPLAYUNIT:
																case EBML_ID_ASPECTRATIOTYPE:
																	$track_entry[$sub_subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
																	break;
																case EBML_ID_FLAGINTERLACED:
																	$track_entry[$sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
																	break;
																case EBML_ID_GAMMAVALUE:
																	$track_entry[$sub_subelement_idname] =      getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
																	break;
																case EBML_ID_COLOURSPACE:
																	$track_entry[$sub_subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length), "\x00");
																	break;
																default:
																	$this->warnings[] = 'Unhandled track.video element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
																	break;
															}
															$offset = $sub_subelement_end;
														}

														if (isset($track_entry[$this->EBMLidName(EBML_ID_CODECID)]) && ($track_entry[$this->EBMLidName(EBML_ID_CODECID)] == 'V_MS/VFW/FOURCC') && isset($track_entry[$this->EBMLidName(EBML_ID_CODECPRIVATE)])) {
															if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
																$track_entry['codec_private_parsed'] = getid3_riff::ParseBITMAPINFOHEADER($track_entry[$this->EBMLidName(EBML_ID_CODECPRIVATE)]);
															} else {
																$this->warnings[] = 'Unable to parse codec private data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"';
															}
														}
														break;

													case EBML_ID_AUDIO:
														while ($offset < $subelement_end) {
															$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
															$sub_subelement_offset = $offset;
															$sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
															$sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_subelement_end    = $offset + $sub_subelement_length;
															switch ($sub_subelement_id) {
																case EBML_ID_CHANNELS:
																case EBML_ID_BITDEPTH:
																	$track_entry[$sub_subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
																	break;
																case EBML_ID_SAMPLINGFREQUENCY:
																case EBML_ID_OUTPUTSAMPLINGFREQUENCY:
																	$track_entry[$sub_subelement_idname] =      getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
																	break;
																case EBML_ID_CHANNELPOSITIONS:
																	$track_entry[$sub_subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length), "\x00");
																	break;
																default:
																	$this->warnings[] = 'Unhandled track.video element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
																	break;
															}
															$offset = $sub_subelement_end;
														}
														break;

													case EBML_ID_CONTENTENCODINGS:
														while ($offset < $subelement_end) {
															$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
															$sub_subelement_offset = $offset;
															$sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
															$sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_subelement_end    = $offset + $sub_subelement_length;
															switch ($sub_subelement_id) {
																case EBML_ID_CONTENTENCODING:
																	while ($offset < $sub_subelement_end) {
																		$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
																		$sub_sub_subelement_offset = $offset;
																		$sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
																		$sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
																		$sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
																		$sub_sub_subelement_end    = $offset + $sub_sub_subelement_length;
																		switch ($sub_sub_subelement_id) {
																			case EBML_ID_CONTENTENCODINGORDER:
																			case EBML_ID_CONTENTENCODINGSCOPE:
																			case EBML_ID_CONTENTENCODINGTYPE:
																				$track_entry[$sub_subelement_idname][$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
																				break;
																			case EBML_ID_CONTENTCOMPRESSION:
																				while ($offset < $sub_sub_subelement_end) {
																					$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
																					$sub_sub_sub_subelement_offset = $offset;
																					$sub_sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
																					$sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
																					$sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
																					$sub_sub_sub_subelement_end    = $offset + $sub_sub_sub_subelement_length;
																					switch ($sub_sub_sub_subelement_id) {
																						case EBML_ID_CONTENTCOMPALGO:
																							$track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length));
																							break;
																						case EBML_ID_CONTENTCOMPSETTINGS:
																							$track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] =                           substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length);
																							break;
																						default:
																							$this->warnings[] = 'Unhandled track.contentencodings.contentencoding.contentcompression element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
																							break;
																					}
																					$offset = $sub_sub_sub_subelement_end;
																				}
																				break;

																			case EBML_ID_CONTENTENCRYPTION:
																				while ($offset < $sub_sub_subelement_end) {
																					$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
																					$sub_sub_sub_subelement_offset = $offset;
																					$sub_sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
																					$sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
																					$sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
																					$sub_sub_sub_subelement_end    = $offset + $sub_sub_sub_subelement_length;
																					switch ($sub_sub_sub_subelement_id) {
																						case EBML_ID_CONTENTENCALGO:
																						case EBML_ID_CONTENTSIGALGO:
																						case EBML_ID_CONTENTSIGHASHALGO:
																							$track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length));
																							break;
																						case EBML_ID_CONTENTENCKEYID:
																						case EBML_ID_CONTENTSIGNATURE:
																						case EBML_ID_CONTENTSIGKEYID:
																							$track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] =                           substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length);
																							break;
																						default:
																							$this->warnings[] = 'Unhandled track.contentencodings.contentencoding.contentcompression element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
																							break;
																					}
																					$offset = $sub_sub_sub_subelement_end;
																				}
																				break;

																			default:
																				$this->warnings[] = 'Unhandled track.contentencodings.contentencoding element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
																				break;
																		}
																		$offset = $sub_sub_subelement_end;
																	}
																	break;
																default:
																	$this->warnings[] = 'Unhandled track.contentencodings element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
																	break;
															}
															$offset = $sub_subelement_end;
														}
														break;

													default:
														$this->warnings[] = 'Unhandled track element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
														break;
												}
												$offset = $subelement_end;
											}
											break;
										default:
											$this->warnings[] = 'Unhandled track element ['.basename(__FILE__).':'.__LINE__.'] ('.$track_entry['id'].'::'.$track_entry['id_name'].') at '.$track_entry['offset'];
											$offset = $track_entry_endoffset;
											break;
									}
									$ThisFileInfo['matroska']['tracks']['tracks'][] = $track_entry;
								}
								break;

							case EBML_ID_INFO: // Contains the position of other level 1 elements
								$info_entry = array();
								while ($offset < $element_end) {
									$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
									$subelement_offset = $offset;
									$subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_idname = $this->EBMLidName($subelement_id);
									$subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_end    = $offset + $subelement_length;
									switch ($subelement_id) {
										case EBML_ID_CHAPTERTRANSLATEEDITIONUID:
										case EBML_ID_CHAPTERTRANSLATECODEC:
										case EBML_ID_TIMECODESCALE:
											$info_entry[$subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
											break;
										case EBML_ID_DURATION:
											$info_entry[$subelement_idname] =      getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
											break;
										case EBML_ID_DATEUTC:
											$info_entry[$subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
											$info_entry[$subelement_idname.'_unix'] = $this->EBMLdate2unix($info_entry[$subelement_idname]);
											break;
										case EBML_ID_SEGMENTUID:
										case EBML_ID_PREVUID:
										case EBML_ID_NEXTUID:
										case EBML_ID_SEGMENTFAMILY:
										case EBML_ID_CHAPTERTRANSLATEID:
											$info_entry[$subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "\x00");
											break;
										case EBML_ID_SEGMENTFILENAME:
										case EBML_ID_PREVFILENAME:
										case EBML_ID_NEXTFILENAME:
										case EBML_ID_TITLE:
										case EBML_ID_MUXINGAPP:
										case EBML_ID_WRITINGAPP:
											$info_entry[$subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "\x00");
											break;
										default:
											$this->warnings[] = 'Unhandled info element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
											break;
									}
									$offset = $subelement_end;
								}
								$ThisFileInfo['matroska']['info'][] = $info_entry;
								break;

							case EBML_ID_CUES:
								$cues_entry = array();
								while ($offset < $element_end) {
									$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
									$subelement_offset = $offset;
									$subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_idname = $this->EBMLidName($subelement_id);
									$subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_end    = $offset + $subelement_length;
									switch ($subelement_id) {
										case EBML_ID_CUEPOINT:
											$cuepoint_entry = array();
											while ($offset < $subelement_end) {
												$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_offset = $offset;
												$sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
												$sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_end    = $offset + $sub_subelement_length;
												switch ($sub_subelement_id) {
													case EBML_ID_CUETRACKPOSITIONS:
														while ($offset < $sub_subelement_end) {
															$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_offset = $offset;
															$sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
															$sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_end    = $offset + $sub_sub_subelement_length;
															switch ($sub_sub_subelement_id) {
																case EBML_ID_CUETRACK:
																	$cuepoint_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
																	break;
																default:
																	$this->warnings[] = 'Unhandled cues.cuepoint.cuetrackpositions element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_subelement_id.'::'.$sub_sub_subelement_idname.') at '.$sub_sub_subelement_offset;
																	break;
															}
															$offset = $sub_subelement_end;
														}
														break;
													case EBML_ID_CUETIME:
														$cuepoint_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
														break;
													default:
														$this->warnings[] = 'Unhandled cues.cuepoint element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
														break;
												}
												$offset = $sub_subelement_end;
											}
											$cues_entry[] = $cuepoint_entry;
											$offset = $sub_subelement_end;
											break;
										default:
											$this->warnings[] = 'Unhandled cues element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
											break;
									}
									$offset = $subelement_end;
								}
								$ThisFileInfo['matroska']['cues'] = $cues_entry;
								break;

							case EBML_ID_TAGS:
								$tags_entry = array();
								while ($offset < $element_end) {
									$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
									$subelement_offset = $offset;
									$subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_idname = $this->EBMLidName($subelement_id);
									$subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_end    = $offset + $subelement_length;
									switch ($subelement_id) {
										case EBML_ID_WRITINGAPP:
											$tags_entry[$subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length);
											break;
										case EBML_ID_TAG:
											$tag_entry = array();
											while ($offset < $subelement_end) {
												$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_offset = $offset;
												$sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
												$sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_end    = $offset + $sub_subelement_length;
												switch ($sub_subelement_id) {
													case EBML_ID_TARGETS:
														$targets_entry = array();
														while ($offset < $sub_subelement_end) {
															$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_offset = $offset;
															$sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
															$sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_end    = $offset + $sub_sub_subelement_length;
															switch ($sub_sub_subelement_id) {
																case EBML_ID_TARGETTYPEVALUE:
																case EBML_ID_EDITIONUID:
																case EBML_ID_CHAPTERUID:
																case EBML_ID_ATTACHMENTUID:
																case EBML_ID_TAGTRACKUID:
																case EBML_ID_TAGCHAPTERUID:
																	$targets_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
																	break;
																default:
																	$this->warnings[] = 'Unhandled tag.targets element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_subelement_id.'::'.$sub_sub_subelement_idname.') at '.$sub_sub_subelement_offset;
																	break;
															}
															$offset = $sub_sub_subelement_end;
														}
														$tag_entry[$sub_subelement_idname][] = $targets_entry;
														break;
													case EBML_ID_SIMPLETAG:
														$simpletag_entry = array();
														while ($offset < $sub_subelement_end) {
															$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_offset = $offset;
															$sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
															$sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_end    = $offset + $sub_sub_subelement_length;
															switch ($sub_sub_subelement_id) {
																case EBML_ID_TAGNAME:
																case EBML_ID_TAGLANGUAGE:
																case EBML_ID_TAGSTRING:
																case EBML_ID_TAGBINARY:
																	$simpletag_entry[$sub_sub_subelement_idname] =                                  substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length);
																	break;
																case EBML_ID_TAGDEFAULT:
																	$simpletag_entry[$sub_sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
																	break;
																default:
																	$this->warnings[] = 'Unhandled tag.simpletag element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_subelement_id.'::'.$sub_sub_subelement_idname.') at '.$sub_sub_subelement_offset;
																	break;
															}
															$offset = $sub_sub_subelement_end;
														}
														$tag_entry[$sub_subelement_idname][] = $simpletag_entry;
														break;
													case EBML_ID_TARGETTYPE:
														$tag_entry[$sub_subelement_idname] =                           substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
														break;
													case EBML_ID_TRACKUID:
														$tag_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
														break;
													default:
														$this->warnings[] = 'Unhandled tags.tag element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
														break;
												}
												$offset = $sub_subelement_end;
											}
											$tags_entry['tags'][] = $tag_entry;
											$offset = $sub_subelement_end;
											break;
										default:
											$this->warnings[] = 'Unhandled tags element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
											break;
									}
									$offset = $subelement_end;
								}
								$ThisFileInfo['matroska']['tags'] = $tags_entry;
								break;


							case EBML_ID_ATTACHMENTS:
								while ($offset < $element_end) {
									$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
									$subelement_offset = $offset;
									$subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_idname = $this->EBMLidName($subelement_id);
									$subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_end    = $offset + $subelement_length;
									switch ($subelement_id) {
										case EBML_ID_ATTACHEDFILE:
											$attachedfile_entry = array();
											while ($offset < $subelement_end) {
												$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_offset = $offset;
												$sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
												$sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_end    = $offset + $sub_subelement_length;
												switch ($sub_subelement_id) {
													case EBML_ID_FILEDESCRIPTION:
													case EBML_ID_FILENAME:
													case EBML_ID_FILEMIMETYPE:
														$attachedfile_entry[$sub_subelement_idname] =                           substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
														break;

													case EBML_ID_FILEDATA:
														$attachedfile_entry['data_offset'] = $offset;
														$attachedfile_entry['data_length'] = $sub_subelement_length;
														if ($sub_subelement_length < 1024) {
															$attachedfile_entry[$sub_subelement_idname] =                           substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
														}
														break;

													case EBML_ID_FILEUID:
														$attachedfile_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
														break;

													default:
														$this->warnings[] = 'Unhandled attachment.attachedfile element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
														break;
												}
												$offset = $sub_subelement_end;
											}
											$ThisFileInfo['matroska']['attachments'][] = $attachedfile_entry;
											$offset = $sub_subelement_end;
											break;
										default:
											$this->warnings[] = 'Unhandled tags element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
											break;
									}
									$offset = $subelement_end;
								}
								break;


							case EBML_ID_CHAPTERS: // not important to us, contains mostly actual audio/video data, ignore
								while ($offset < $element_end) {
									$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
									$subelement_offset = $offset;
									$subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_idname = $this->EBMLidName($subelement_id);
									$subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_end    = $offset + $subelement_length;
									switch ($subelement_id) {
										case EBML_ID_EDITIONENTRY:
											$editionentry_entry = array();
											while ($offset < $subelement_end) {
												$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_offset = $offset;
												$sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
												$sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_end    = $offset + $sub_subelement_length;
												switch ($sub_subelement_id) {
													case EBML_ID_EDITIONUID:
														$editionentry_entry[$sub_subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
														break;
													case EBML_ID_EDITIONFLAGHIDDEN:
													case EBML_ID_EDITIONFLAGDEFAULT:
													case EBML_ID_EDITIONFLAGORDERED:
														$editionentry_entry[$sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
														break;
													case EBML_ID_CHAPTERATOM:
														$chapteratom_entry = array();
														while ($offset < $sub_subelement_end) {
															$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_offset = $offset;
															$sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
															$sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
															$sub_sub_subelement_end    = $offset + $sub_sub_subelement_length;
															switch ($sub_sub_subelement_id) {
																case EBML_ID_CHAPTERSEGMENTUID:
																case EBML_ID_CHAPTERSEGMENTEDITIONUID:
																	$chapteratom_entry[$sub_sub_subelement_idname] =                                  substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length);
																	break;
																case EBML_ID_CHAPTERFLAGENABLED:
																case EBML_ID_CHAPTERFLAGHIDDEN:
																	$chapteratom_entry[$sub_sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
																	break;
																case EBML_ID_CHAPTERUID:
																case EBML_ID_CHAPTERTIMESTART:
																case EBML_ID_CHAPTERTIMEEND:
																	$chapteratom_entry[$sub_sub_subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
																	break;
																case EBML_ID_CHAPTERTRACK:
																	$chaptertrack_entry = array();
																	while ($offset < $sub_sub_subelement_end) {
																		$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
																		$sub_sub_sub_subelement_offset = $offset;
																		$sub_sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
																		$sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
																		$sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
																		$sub_sub_sub_subelement_end    = $offset + $sub_sub_sub_subelement_length;
																		switch ($sub_sub_sub_subelement_id) {
																			case EBML_ID_CHAPTERTRACKNUMBER:
																				$chaptertrack_entry[$sub_sub_sub_subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length));
																				break;
																			default:
																				$this->warnings[] = 'Unhandled chapters.editionentry.chapteratom.chaptertrack element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_sub_subelement_id.'::'.$sub_sub_sub_subelement_idname.') at '.$sub_sub_sub_subelement_offset;
																				break;
																		}
																		$offset = $sub_sub_sub_subelement_end;
																	}
																	$chapteratom_entry[$sub_sub_subelement_idname][] = $chaptertrack_entry;
																	break;
																case EBML_ID_CHAPTERDISPLAY:
																	$chapterdisplay_entry = array();
																	while ($offset < $sub_sub_subelement_end) {
																		$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
																		$sub_sub_sub_subelement_offset = $offset;
																		$sub_sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
																		$sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_sub_subelement_id);
																		$sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
																		$sub_sub_sub_subelement_end    = $offset + $sub_sub_sub_subelement_length;
																		switch ($sub_sub_sub_subelement_id) {
																			case EBML_ID_CHAPSTRING:
																			case EBML_ID_CHAPLANGUAGE:
																			case EBML_ID_CHAPCOUNTRY:
																				$chapterdisplay_entry[$sub_sub_sub_subelement_idname] =                                  substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length);
																				break;
																			default:
																				$this->warnings[] = 'Unhandled chapters.editionentry.chapteratom.chapterdisplay element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_sub_subelement_id.'::'.$sub_sub_sub_subelement_idname.') at '.$sub_sub_sub_subelement_offset;
																				break;
																		}
																		$offset = $sub_sub_sub_subelement_end;
																	}
																	$chapteratom_entry[$sub_sub_subelement_idname][] = $chapterdisplay_entry;
																	break;
																default:
																	$this->warnings[] = 'Unhandled chapters.editionentry.chapteratom element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_subelement_id.'::'.$sub_sub_subelement_idname.') at '.$sub_sub_subelement_offset;
																	break;
															}
															$offset = $sub_sub_subelement_end;
														}
														$editionentry_entry[$sub_subelement_idname][] = $chapteratom_entry;
														break;
													default:
														$this->warnings[] = 'Unhandled chapters.editionentry element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
														break;
												}
												$offset = $sub_subelement_end;
											}
											$ThisFileInfo['matroska']['chapters'][] = $editionentry_entry;
											$offset = $sub_subelement_end;
											break;
										default:
											$this->warnings[] = 'Unhandled chapters element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
											break;
									}
									$offset = $subelement_end;
								}
								break;


							case EBML_ID_VOID:    // padding, ignore
								$void_entry = array();
								$void_entry['offset'] = $offset;
								$ThisFileInfo['matroska']['void'][] = $void_entry;
								break;

							case EBML_ID_CLUSTER: // not important to us, contains mostly actual audio/video data, ignore
								$cluster_entry = array();
								while ($offset < $element_end) {
									$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
									$subelement_offset = $offset;
									$subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_idname = $this->EBMLidName($subelement_id);
									$subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
									$subelement_end    = $offset + $subelement_length;
									switch ($subelement_id) {
										case EBML_ID_CLUSTERTIMECODE:
										case EBML_ID_CLUSTERPOSITION:
										case EBML_ID_CLUSTERPREVSIZE:
											$cluster_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
											break;

										case EBML_ID_CLUSTERSILENTTRACKS:
											$cluster_silent_tracks = array();
											while ($offset < $subelement_end) {
												$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_offset = $offset;
												$sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
												$sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_end    = $offset + $sub_subelement_length;
												switch ($sub_subelement_id) {
													case EBML_ID_CLUSTERSILENTTRACKNUMBER:
														$cluster_silent_tracks[] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
														break;
													default:
														$this->warnings[] = 'Unhandled clusters.silenttracks element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
														break;
												}
												$offset = $sub_subelement_end;
											}
											$cluster_entry[$subelement_idname][] = $cluster_silent_tracks;
											$offset = $sub_subelement_end;
											break;

										case EBML_ID_CLUSTERBLOCKGROUP:
											$cluster_block_group = array('offset'=>$offset);
											while ($offset < $subelement_end) {
												$this->EnsureBufferHasEnoughData($fd, $EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_offset = $offset;
												$sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
												$sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
												$sub_subelement_end    = $offset + $sub_subelement_length;
												switch ($sub_subelement_id) {
													case EBML_ID_CLUSTERBLOCK:
														$cluster_block_data = array();
														$cluster_block_data['tracknumber'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
														$cluster_block_data['timecode'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 2));
														$offset += 2;
														// unsure whether this is 1 octect or 2 octets? (http://matroska.org/technical/specs/index.html#block_structure)
														$cluster_block_data['flags_raw'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
														$offset += 1;
														//$cluster_block_data['flags']['reserved1'] =      (($cluster_block_data['flags_raw'] & 0xF0) >> 4);
														$cluster_block_data['flags']['invisible'] = (bool) (($cluster_block_data['flags_raw'] & 0x08) >> 3);
														$cluster_block_data['flags']['lacing']    =        (($cluster_block_data['flags_raw'] & 0x06) >> 1);
														//$cluster_block_data['flags']['reserved2'] =      (($cluster_block_data['flags_raw'] & 0x01) >> 0);
														$cluster_block_data['flags']['lacing_type'] = $this->MatroskaBlockLacingType($cluster_block_data['flags']['lacing']);
														if ($cluster_block_data['flags']['lacing'] != 0) {
															$cluster_block_data['lace_frames'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1)); // Number of frames in the lace-1 (uint8)
															$offset += 1;
															if ($cluster_block_data['flags']['lacing'] != 2) {
																$cluster_block_data['lace_frames'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1)); // Lace-coded size of each frame of the lace, except for the last one (multiple uint8). *This is not used with Fixed-size lacing as it is calculated automatically from (total size of lace) / (number of frames in lace).
																$offset += 1;
															}
														}
														if (!isset($ThisFileInfo['matroska']['track_data_offsets'][$cluster_block_data['tracknumber']])) {
															$ThisFileInfo['matroska']['track_data_offsets'][$cluster_block_data['tracknumber']] = $offset;
														}
														$cluster_block_group[$sub_subelement_idname] = $cluster_block_data;
														break;

													case EBML_ID_CLUSTERREFERENCEPRIORITY: // unsigned-int
													case EBML_ID_CLUSTERBLOCKDURATION:     // unsigned-int
														$cluster_block_group[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
														break;

													case EBML_ID_CLUSTERREFERENCEBLOCK:    // signed-int
														$cluster_block_group[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length), false, true);
														break;

													default:
														$this->warnings[] = 'Unhandled clusters.blockgroup element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
														break;
												}
												$offset = $sub_subelement_end;
											}
											$cluster_entry[$subelement_idname][] = $cluster_block_group;
											$offset = $sub_subelement_end;
											break;

										case EBML_ID_CLUSTERSIMPLEBLOCK:
											// http://www.matroska.org/technical/specs/index.html#simpleblock_structure
											$cluster_block_data = array();
											$cluster_block_data['tracknumber'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
											$cluster_block_data['timecode'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 2));
											$offset += 2;
											$cluster_block_data['flags_raw'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
											$offset += 1;
											$cluster_block_data['flags']['keyframe']    = (($cluster_block_data['flags_raw'] & 0x80) >> 7);
											$cluster_block_data['flags']['reserved1']   = (($cluster_block_data['flags_raw'] & 0x70) >> 4);
											$cluster_block_data['flags']['invisible']   = (($cluster_block_data['flags_raw'] & 0x08) >> 3);
											$cluster_block_data['flags']['lacing']      = (($cluster_block_data['flags_raw'] & 0x06) >> 1);  // 00=no lacing; 01=Xiph lacing; 11=EBML lacing; 10=fixed-size lacing
											$cluster_block_data['flags']['discardable'] = (($cluster_block_data['flags_raw'] & 0x01));

											if ($cluster_block_data['flags']['lacing'] > 0) {
												$cluster_block_data['lace_frames'] = 1 + getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
												$offset += 1;
												if ($cluster_block_data['flags']['lacing'] != 0x02) {
													// *This is not used with Fixed-size lacing as it is calculated automatically from (total size of lace) / (number of frames in lace).
													$cluster_block_data['lace_frame_size'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
													$offset += 1;
												}
											}

											if (!isset($ThisFileInfo['matroska']['track_data_offsets'][$cluster_block_data['tracknumber']])) {
												$ThisFileInfo['matroska']['track_data_offsets'][$cluster_block_data['tracknumber']] = $offset;
											}
											$cluster_block_group[$sub_subelement_idname] = $cluster_block_data;
											break;

										default:
											$this->warnings[] = 'Unhandled cluster element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
											break;
									}
									$offset = $subelement_end;
								}
								$ThisFileInfo['matroska']['cluster'][] = $cluster_entry;

								// check to see if all the data we need exists already, if so, break out of the loop
								if (isset($ThisFileInfo['matroska']['info']) && is_array($ThisFileInfo['matroska']['info'])) {
									if (isset($ThisFileInfo['matroska']['tracks']['tracks']) && is_array($ThisFileInfo['matroska']['tracks']['tracks'])) {
										break 2;
									}
								}
								break;

							default:
								if ($element_data['id_name'] == dechex($element_data['id'])) {
									$ThisFileInfo['error'][] = 'Unhandled segment ['.basename(__FILE__).':'.__LINE__.'] ('.$element_data['id'].') at '.$element_data_offset;
								} else {
									$this->warnings[] = 'Unhandled segment ['.basename(__FILE__).':'.__LINE__.'] ('.$element_data['id'].'::'.$element_data['id_name'].') at '.$element_data['offset'];
								}
								break;
						}
						$offset = $element_end;
					}
					break;


				default:
					$ThisFileInfo['error'][] = 'Unhandled chunk ['.basename(__FILE__).':'.__LINE__.'] ('.$top_element_id.') at '.$offset;
					break;
			}
			$offset = $top_element_endoffset;
		}



		if (isset($ThisFileInfo['matroska']['info']) && is_array($ThisFileInfo['matroska']['info'])) {
			foreach ($ThisFileInfo['matroska']['info'] as $key => $infoarray) {
				if (isset($infoarray['Duration'])) {
					// TimecodeScale is how many nanoseconds each Duration unit is
					$ThisFileInfo['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000);
					break;
				}
			}
		}
		if (isset($ThisFileInfo['matroska']['tracks']['tracks']) && is_array($ThisFileInfo['matroska']['tracks']['tracks'])) {
			foreach ($ThisFileInfo['matroska']['tracks']['tracks'] as $key => $trackarray) {
				$track_info = array();
				switch (isset($trackarray['TrackType']) ? $trackarray['TrackType'] : '') {
					case 1: // Video
						if (!empty($trackarray['PixelWidth']))                     { $track_info['resolution_x']  =                                    $trackarray['PixelWidth'];                     }
						if (!empty($trackarray['PixelHeight']))                    { $track_info['resolution_y']  =                                    $trackarray['PixelHeight'];                    }
						if (!empty($trackarray['DisplayWidth']))                   { $track_info['display_x']     =                                    $trackarray['DisplayWidth'];                   }
						if (!empty($trackarray['DisplayHeight']))                  { $track_info['display_y']     =                                    $trackarray['DisplayHeight'];                  }
						if (!empty($trackarray['DefaultDuration']))                { $track_info['frame_rate']    =                 round(1000000000 / $trackarray['DefaultDuration'], 3);            }
						if (!empty($trackarray['CodecID']))                        { $track_info['dataformat']    = $this->MatroskaCodecIDtoCommonName($trackarray['CodecID']);                       }
						if (!empty($trackarray['codec_private_parsed']['fourcc'])) { $track_info['fourcc']        =                                    $trackarray['codec_private_parsed']['fourcc']; }
						$ThisFileInfo['video']['streams'][] = $track_info;
						if (isset($track_info['resolution_x']) && empty($ThisFileInfo['video']['resolution_x'])) {
							foreach ($track_info as $key => $value) {
								$ThisFileInfo['video'][$key] = $value;
							}
						}
						break;
					case 2: // Audio
						if (!empty($trackarray['CodecID']))           { $track_info['dataformat']      = $this->MatroskaCodecIDtoCommonName($trackarray['CodecID']);          }
						if (!empty($trackarray['SamplingFrequency'])) { $track_info['sample_rate']     =                                    $trackarray['SamplingFrequency']; }
						if (!empty($trackarray['Channels']))          { $track_info['channels']        =                                    $trackarray['Channels'];          }
						if (!empty($trackarray['BitDepth']))          { $track_info['bits_per_sample'] =                                    $trackarray['BitDepth'];          }
						switch (isset($trackarray[$this->EBMLidName(EBML_ID_CODECID)]) ? $trackarray[$this->EBMLidName(EBML_ID_CODECID)] : '') {
							case 'A_PCM/INT/LIT':
							case 'A_PCM/INT/BIG':
								$track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
								break;

							case 'A_AC3':
								if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, false)) {
									if (isset($ThisFileInfo['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
										$ac3_thisfileinfo = array('avdataoffset'=>$ThisFileInfo['matroska']['track_data_offsets'][$trackarray['TrackNumber']]);
										$getid3_ac3 = new getid3_ac3($fd, $ac3_thisfileinfo);
										$ThisFileInfo['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $ac3_thisfileinfo;
										if (!empty($ac3_thisfileinfo['error'])) {
											foreach ($ac3_thisfileinfo['error'] as $newerror) {
												$this->warnings[] = 'getid3_ac3() says: ['.$newerror.']';
											}
										}
										if (!empty($ac3_thisfileinfo['warning'])) {
											foreach ($ac3_thisfileinfo['warning'] as $newerror) {
												$this->warnings[] = 'getid3_ac3() says: ['.$newerror.']';
											}
										}
										if (isset($ac3_thisfileinfo['audio']) && is_array($ac3_thisfileinfo['audio'])) {
											foreach ($ac3_thisfileinfo['audio'] as $key => $value) {
												$track_info[$key] = $value;
											}
										}
										unset($ac3_thisfileinfo);
										unset($getid3_ac3);
									} else {
										$this->warnings[] = 'Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $ThisFileInfo[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set';
									}
								} else {
									$this->warnings[] = 'Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.ac3.php"';
								}
								break;

							case 'A_DTS':
								$dts_offset = $ThisFileInfo['matroska']['track_data_offsets'][$trackarray['TrackNumber']];
								// this is a NASTY hack, but sometimes audio data is off by a byte or two and not sure why, email info@getid3.org if you can explain better
								fseek($fd, $dts_offset, SEEK_SET);
								$magic_test = fread($fd, 8);
								for ($i = 0; $i < 4; $i++) {
									// look to see if DTS "magic" is here, if so adjust offset by that many bytes
									if (substr($magic_test, $i, 4) == "\x7F\xFE\x80\x01") {
										$dts_offset += $i;
										break;
									}
								}
								if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, false)) {
									$dts_thisfileinfo = array('avdataoffset'=>$dts_offset);
									$getid3_dts = new getid3_dts($fd, $dts_thisfileinfo);
									$ThisFileInfo['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $dts_thisfileinfo;
									if (!empty($dts_thisfileinfo['error'])) {
										foreach ($dts_thisfileinfo['error'] as $newerror) {
											$this->warnings[] = 'getid3_dts() says: ['.$newerror.']';
										}
									}
									if (!empty($dts_thisfileinfo['warning'])) {
										foreach ($dts_thisfileinfo['warning'] as $newerror) {
											$this->warnings[] = 'getid3_dts() says: ['.$newerror.']';
										}
									}
									if (isset($dts_thisfileinfo['audio']) && is_array($dts_thisfileinfo['audio'])) {
										foreach ($dts_thisfileinfo['audio'] as $key => $value) {
											$track_info[$key] = $value;
										}
									}
									unset($dts_thisfileinfo);
									unset($getid3_dts);
								} else {
									$this->warnings[] = 'Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.dts.php"';
								}
								break;

							case 'A_AAC':
$this->warnings[] = 'This version of getID3() [v'.GETID3_VERSION.'] has problems parsing AAC audio in Matroska containers ['.basename(__FILE__).':'.__LINE__.']';
								if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.aac.php', __FILE__, false)) {
							//		$aac_thisfileinfo = array('avdataoffset'=>$ThisFileInfo['matroska']['track_data_offsets'][$trackarray['TrackNumber']]);
							//		$getid3_aac = new getid3_aac($fd, $aac_thisfileinfo);
							//		$ThisFileInfo['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $aac_thisfileinfo;
							//		if (isset($aac_thisfileinfo['audio']) && is_array($aac_thisfileinfo['audio'])) {
							//			foreach ($aac_thisfileinfo['audio'] as $key => $value) {
							//				$track_info[$key] = $value;
							//			}
							//		}
							//		unset($aac_thisfileinfo);
							//		unset($getid3_aac);
								} else {
									$this->warnings[] = 'Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.aac.php"';
								}
								break;

							case 'A_MPEG/L3':
								if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, false)) {
									$mp3_thisfileinfo = array(
										'avdataoffset' => $ThisFileInfo['matroska']['track_data_offsets'][$trackarray['TrackNumber']],
										'avdataend'    => $ThisFileInfo['matroska']['track_data_offsets'][$trackarray['TrackNumber']] + 1024,
									);
									$getid3_mp3 = new getid3_mp3($fd, $mp3_thisfileinfo);
									$getid3_mp3->allow_bruteforce = true;
									//getid3_mp3::getOnlyMPEGaudioInfo($fd, $mp3_thisfileinfo, $offset, false);
									$ThisFileInfo['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $mp3_thisfileinfo;
									if (!empty($mp3_thisfileinfo['error'])) {
										foreach ($mp3_thisfileinfo['error'] as $newerror) {
											$this->warnings[] = 'getid3_mp3() says: ['.$newerror.']';
										}
									}
									if (!empty($mp3_thisfileinfo['warning'])) {
										foreach ($mp3_thisfileinfo['warning'] as $newerror) {
											$this->warnings[] = 'getid3_mp3() says: ['.$newerror.']';
										}
									}
									if (isset($mp3_thisfileinfo['audio']) && is_array($mp3_thisfileinfo['audio'])) {
										foreach ($mp3_thisfileinfo['audio'] as $key => $value) {
											$track_info[$key] = $value;
										}
									}
									unset($mp3_thisfileinfo);
									unset($getid3_mp3);
								} else {
									$this->warnings[] = 'Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.mp3.php"';
								}
								break;

							case 'A_VORBIS':
								if (isset($trackarray['CodecPrivate'])) {
									// this is a NASTY hack, email info@getid3.org if you have a better idea how to get this info out
									$found_vorbis = false;
									for ($vorbis_offset = 1; $vorbis_offset < 16; $vorbis_offset++) {
										if (substr($trackarray['CodecPrivate'], $vorbis_offset, 6) == 'vorbis') {
											$vorbis_offset--;
											$found_vorbis = true;
											break;
										}
									}
									if ($found_vorbis) {
										if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, false)) {
											$vorbis_fileinfo = array();
											$oggpageinfo['page_seqno'] = 0;
											getid3_ogg::ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $vorbis_fileinfo, $oggpageinfo);
											$ThisFileInfo['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $vorbis_fileinfo;
											if (!empty($vorbis_fileinfo['error'])) {
												foreach ($vorbis_fileinfo['error'] as $newerror) {
													$this->warnings[] = 'getid3_ogg() says: ['.$newerror.']';
												}
											}
											if (!empty($vorbis_fileinfo['warning'])) {
												foreach ($vorbis_fileinfo['warning'] as $newerror) {
													$this->warnings[] = 'getid3_ogg() says: ['.$newerror.']';
												}
											}
											if (isset($vorbis_fileinfo['audio']) && is_array($vorbis_fileinfo['audio'])) {
												foreach ($vorbis_fileinfo['audio'] as $key => $value) {
													$track_info[$key] = $value;
												}
											}
											if (!empty($vorbis_fileinfo['ogg']['bitrate_average'])) {
												$track_info['bitrate'] = $vorbis_fileinfo['ogg']['bitrate_average'];
											} elseif (!empty($vorbis_fileinfo['ogg']['bitrate_nominal'])) {
												$track_info['bitrate'] = $vorbis_fileinfo['ogg']['bitrate_nominal'];
											}
											unset($vorbis_fileinfo);
											unset($oggpageinfo);
										} else {
											$this->warnings[] = 'Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.ogg.php"';
										}
									} else {
									}
								} else {
								}
								break;

							default:
								$this->warnings[] = 'Unhandled audio type "'.(isset($trackarray[$this->EBMLidName(EBML_ID_CODECID)]) ? $trackarray[$this->EBMLidName(EBML_ID_CODECID)] : '').'"';
								break;
						}


						$ThisFileInfo['audio']['streams'][] = $track_info;
						if (isset($track_info['dataformat']) && empty($ThisFileInfo['audio']['dataformat'])) {
							foreach ($track_info as $key => $value) {
								$ThisFileInfo['audio'][$key] = $value;
							}
						}
						break;
					default:
						// ignore, do nothing
						break;
				}
			}
		}

		if ($this->hide_clusters) {
			// too much data returned that is usually not useful
			if (isset($ThisFileInfo['matroska']['segments']) && is_array($ThisFileInfo['matroska']['segments'])) {
				foreach ($ThisFileInfo['matroska']['segments'] as $key => $segmentsarray) {
					if ($segmentsarray['id'] == EBML_ID_CLUSTER) {
						unset($ThisFileInfo['matroska']['segments'][$key]);
					}
				}
			}
			if (isset($ThisFileInfo['matroska']['seek']) && is_array($ThisFileInfo['matroska']['seek'])) {
				foreach ($ThisFileInfo['matroska']['seek'] as $key => $seekarray) {
					if ($seekarray['target_id'] == EBML_ID_CLUSTER) {
						unset($ThisFileInfo['matroska']['seek'][$key]);
					}
				}
			}
			//unset($ThisFileInfo['matroska']['cluster']);
			//unset($ThisFileInfo['matroska']['track_data_offsets']);
		}

		if (!empty($ThisFileInfo['video']['streams'])) {
			$ThisFileInfo['mime_type'] = 'video/x-matroska';
		} elseif (!empty($ThisFileInfo['video']['streams'])) {
			$ThisFileInfo['mime_type'] = 'audio/x-matroska';
		} elseif (isset($ThisFileInfo['mime_type'])) {
			unset($ThisFileInfo['mime_type']);
		}

		foreach ($this->warnings as $key => $value) {
			$ThisFileInfo['warning'][] = $value;
		}

		return true;
	}
 private function parseEBML(&$info)
 {
     // http://www.matroska.org/technical/specs/index.html#EBMLBasics
     $this->current_offset = $info['avdataoffset'];
     while ($this->getEBMLelement($top_element, $info['avdataend'])) {
         switch ($top_element['id']) {
             case EBML_ID_EBML:
                 $info['fileformat'] = 'matroska';
                 $info['matroska']['header']['offset'] = $top_element['offset'];
                 $info['matroska']['header']['length'] = $top_element['length'];
                 while ($this->getEBMLelement($element_data, $top_element['end'], true)) {
                     switch ($element_data['id']) {
                         case EBML_ID_EBMLVERSION:
                         case EBML_ID_EBMLREADVERSION:
                         case EBML_ID_EBMLMAXIDLENGTH:
                         case EBML_ID_EBMLMAXSIZELENGTH:
                         case EBML_ID_DOCTYPEVERSION:
                         case EBML_ID_DOCTYPEREADVERSION:
                             $element_data['data'] = getid3_lib::BigEndian2Int($element_data['data']);
                             break;
                         case EBML_ID_DOCTYPE:
                             $element_data['data'] = getid3_lib::trimNullByte($element_data['data']);
                             break;
                         case EBML_ID_CRC32:
                             // not useful, ignore
                             $this->current_offset = $element_data['end'];
                             unset($element_data);
                             break;
                         default:
                             $this->unhandledElement('header', __LINE__, $element_data);
                     }
                     if (!empty($element_data)) {
                         unset($element_data['offset'], $element_data['end']);
                         $info['matroska']['header']['elements'][] = $element_data;
                     }
                 }
                 break;
             case EBML_ID_SEGMENT:
                 $info['matroska']['segment'][0]['offset'] = $top_element['offset'];
                 $info['matroska']['segment'][0]['length'] = $top_element['length'];
                 while ($this->getEBMLelement($element_data, $top_element['end'])) {
                     if ($element_data['id'] != EBML_ID_CLUSTER || !self::$hide_clusters) {
                         // collect clusters only if required
                         $info['matroska']['segments'][] = $element_data;
                     }
                     switch ($element_data['id']) {
                         case EBML_ID_SEEKHEAD:
                             // Contains the position of other level 1 elements.
                             while ($this->getEBMLelement($seek_entry, $element_data['end'])) {
                                 switch ($seek_entry['id']) {
                                     case EBML_ID_SEEK:
                                         // Contains a single seek entry to an EBML element
                                         while ($this->getEBMLelement($sub_seek_entry, $seek_entry['end'], true)) {
                                             switch ($sub_seek_entry['id']) {
                                                 case EBML_ID_SEEKID:
                                                     $seek_entry['target_id'] = self::EBML2Int($sub_seek_entry['data']);
                                                     $seek_entry['target_name'] = self::EBMLidName($seek_entry['target_id']);
                                                     break;
                                                 case EBML_ID_SEEKPOSITION:
                                                     $seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($sub_seek_entry['data']);
                                                     break;
                                                 default:
                                                     $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry);
                                             }
                                         }
                                         if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) {
                                             // collect clusters only if required
                                             $info['matroska']['seek'][] = $seek_entry;
                                         }
                                         break;
                                     default:
                                         $this->unhandledElement('seekhead', __LINE__, $seek_entry);
                                 }
                             }
                             break;
                         case EBML_ID_TRACKS:
                             // A top-level block of information with many tracks described.
                             $info['matroska']['tracks'] = $element_data;
                             while ($this->getEBMLelement($track_entry, $element_data['end'])) {
                                 switch ($track_entry['id']) {
                                     case EBML_ID_TRACKENTRY:
                                         //subelements: Describes a track with all elements.
                                         while ($this->getEBMLelement($subelement, $track_entry['end'], array(EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS))) {
                                             switch ($subelement['id']) {
                                                 case EBML_ID_TRACKNUMBER:
                                                 case EBML_ID_TRACKUID:
                                                 case EBML_ID_TRACKTYPE:
                                                 case EBML_ID_MINCACHE:
                                                 case EBML_ID_MAXCACHE:
                                                 case EBML_ID_MAXBLOCKADDITIONID:
                                                 case EBML_ID_DEFAULTDURATION:
                                                     // nanoseconds per frame
                                                     $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
                                                     break;
                                                 case EBML_ID_TRACKTIMECODESCALE:
                                                     $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']);
                                                     break;
                                                 case EBML_ID_CODECID:
                                                 case EBML_ID_LANGUAGE:
                                                 case EBML_ID_NAME:
                                                 case EBML_ID_CODECNAME:
                                                 case EBML_ID_CODECPRIVATE:
                                                     $track_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
                                                     break;
                                                 case EBML_ID_FLAGENABLED:
                                                 case EBML_ID_FLAGDEFAULT:
                                                 case EBML_ID_FLAGFORCED:
                                                 case EBML_ID_FLAGLACING:
                                                 case EBML_ID_CODECDECODEALL:
                                                     $track_entry[$subelement['id_name']] = (bool) getid3_lib::BigEndian2Int($subelement['data']);
                                                     break;
                                                 case EBML_ID_VIDEO:
                                                     while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
                                                         switch ($sub_subelement['id']) {
                                                             case EBML_ID_PIXELWIDTH:
                                                             case EBML_ID_PIXELHEIGHT:
                                                             case EBML_ID_STEREOMODE:
                                                             case EBML_ID_PIXELCROPBOTTOM:
                                                             case EBML_ID_PIXELCROPTOP:
                                                             case EBML_ID_PIXELCROPLEFT:
                                                             case EBML_ID_PIXELCROPRIGHT:
                                                             case EBML_ID_DISPLAYWIDTH:
                                                             case EBML_ID_DISPLAYHEIGHT:
                                                             case EBML_ID_DISPLAYUNIT:
                                                             case EBML_ID_ASPECTRATIOTYPE:
                                                                 $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
                                                                 break;
                                                             case EBML_ID_FLAGINTERLACED:
                                                                 $track_entry[$sub_subelement['id_name']] = (bool) getid3_lib::BigEndian2Int($sub_subelement['data']);
                                                                 break;
                                                             case EBML_ID_GAMMAVALUE:
                                                                 $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
                                                                 break;
                                                             case EBML_ID_COLOURSPACE:
                                                                 $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
                                                                 break;
                                                             default:
                                                                 $this->unhandledElement('track.video', __LINE__, $sub_subelement);
                                                         }
                                                     }
                                                     if (isset($track_entry[$this->EBMLidName(EBML_ID_CODECID)]) && $track_entry[$this->EBMLidName(EBML_ID_CODECID)] == 'V_MS/VFW/FOURCC' && isset($track_entry[$this->EBMLidName(EBML_ID_CODECPRIVATE)])) {
                                                         if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH . 'module.audio-video.riff.php', __FILE__, false)) {
                                                             $track_entry['codec_private_parsed'] = getid3_riff::ParseBITMAPINFOHEADER($track_entry[$this->EBMLidName(EBML_ID_CODECPRIVATE)]);
                                                         } else {
                                                             $this->getid3->warning('Unable to parse codec private data [' . basename(__FILE__) . ':' . __LINE__ . '] because cannot include "module.audio-video.riff.php"');
                                                         }
                                                     }
                                                     break;
                                                 case EBML_ID_AUDIO:
                                                     while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
                                                         switch ($sub_subelement['id']) {
                                                             case EBML_ID_CHANNELS:
                                                             case EBML_ID_BITDEPTH:
                                                                 $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
                                                                 break;
                                                             case EBML_ID_SAMPLINGFREQUENCY:
                                                             case EBML_ID_OUTPUTSAMPLINGFREQUENCY:
                                                                 $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
                                                                 break;
                                                             case EBML_ID_CHANNELPOSITIONS:
                                                                 $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
                                                                 break;
                                                             default:
                                                                 $this->unhandledElement('track.audio', __LINE__, $sub_subelement);
                                                         }
                                                     }
                                                     break;
                                                 case EBML_ID_CONTENTENCODINGS:
                                                     while ($this->getEBMLelement($sub_subelement, $subelement['end'])) {
                                                         switch ($sub_subelement['id']) {
                                                             case EBML_ID_CONTENTENCODING:
                                                                 while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CONTENTCOMPRESSION, EBML_ID_CONTENTENCRYPTION))) {
                                                                     switch ($sub_sub_subelement['id']) {
                                                                         case EBML_ID_CONTENTENCODINGORDER:
                                                                         case EBML_ID_CONTENTENCODINGSCOPE:
                                                                         case EBML_ID_CONTENTENCODINGTYPE:
                                                                             $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
                                                                             break;
                                                                         case EBML_ID_CONTENTCOMPRESSION:
                                                                             while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
                                                                                 switch ($sub_sub_sub_subelement['id']) {
                                                                                     case EBML_ID_CONTENTCOMPALGO:
                                                                                         $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
                                                                                         break;
                                                                                     case EBML_ID_CONTENTCOMPSETTINGS:
                                                                                         $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
                                                                                         break;
                                                                                     default:
                                                                                         $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
                                                                                 }
                                                                             }
                                                                             break;
                                                                         case EBML_ID_CONTENTENCRYPTION:
                                                                             while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
                                                                                 switch ($sub_sub_sub_subelement['id']) {
                                                                                     case EBML_ID_CONTENTENCALGO:
                                                                                     case EBML_ID_CONTENTSIGALGO:
                                                                                     case EBML_ID_CONTENTSIGHASHALGO:
                                                                                         $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
                                                                                         break;
                                                                                     case EBML_ID_CONTENTENCKEYID:
                                                                                     case EBML_ID_CONTENTSIGNATURE:
                                                                                     case EBML_ID_CONTENTSIGKEYID:
                                                                                         $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
                                                                                         break;
                                                                                     default:
                                                                                         $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
                                                                                 }
                                                                             }
                                                                             break;
                                                                         default:
                                                                             $this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement);
                                                                     }
                                                                 }
                                                                 break;
                                                             default:
                                                                 $this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement);
                                                         }
                                                     }
                                                     break;
                                                 default:
                                                     $this->unhandledElement('track', __LINE__, $subelement);
                                             }
                                         }
                                         $info['matroska']['tracks']['tracks'][] = $track_entry;
                                         break;
                                     default:
                                         $this->unhandledElement('tracks', __LINE__, $track_entry);
                                 }
                             }
                             break;
                         case EBML_ID_INFO:
                             // Contains miscellaneous general information and statistics on the file.
                             $info_entry = array();
                             while ($this->getEBMLelement($subelement, $element_data['end'], true)) {
                                 switch ($subelement['id']) {
                                     case EBML_ID_CHAPTERTRANSLATEEDITIONUID:
                                     case EBML_ID_CHAPTERTRANSLATECODEC:
                                     case EBML_ID_TIMECODESCALE:
                                         $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
                                         break;
                                     case EBML_ID_DURATION:
                                         $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']);
                                         break;
                                     case EBML_ID_DATEUTC:
                                         $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
                                         $info_entry[$subelement['id_name'] . '_unix'] = self::EBMLdate2unix($info_entry[$subelement['id_name']]);
                                         break;
                                     case EBML_ID_SEGMENTUID:
                                     case EBML_ID_PREVUID:
                                     case EBML_ID_NEXTUID:
                                     case EBML_ID_SEGMENTFAMILY:
                                     case EBML_ID_CHAPTERTRANSLATEID:
                                         $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
                                         break;
                                     case EBML_ID_SEGMENTFILENAME:
                                     case EBML_ID_PREVFILENAME:
                                     case EBML_ID_NEXTFILENAME:
                                     case EBML_ID_TITLE:
                                     case EBML_ID_MUXINGAPP:
                                     case EBML_ID_WRITINGAPP:
                                         $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
                                         $info['matroska']['comments'][strtolower($subelement['id_name'])][] = $info_entry[$subelement['id_name']];
                                         break;
                                     default:
                                         $this->unhandledElement('info', __LINE__, $subelement);
                                 }
                             }
                             $info['matroska']['info'][] = $info_entry;
                             break;
                         case EBML_ID_CUES:
                             // A top-level element to speed seeking access. All entries are local to the segment. Should be mandatory for non "live" streams.
                             if (self::$hide_clusters) {
                                 // do not parse cues if hide clusters is "ON" till they point to clusters anyway
                                 $this->current_offset = $element_data['end'];
                                 break;
                             }
                             $cues_entry = array();
                             while ($this->getEBMLelement($subelement, $element_data['end'])) {
                                 switch ($subelement['id']) {
                                     case EBML_ID_CUEPOINT:
                                         $cuepoint_entry = array();
                                         while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CUETRACKPOSITIONS))) {
                                             switch ($sub_subelement['id']) {
                                                 case EBML_ID_CUETRACKPOSITIONS:
                                                     while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
                                                         switch ($sub_sub_subelement['id']) {
                                                             case EBML_ID_CUETRACK:
                                                             case EBML_ID_CUECLUSTERPOSITION:
                                                                 $cuepoint_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
                                                                 break;
                                                             default:
                                                                 $this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement);
                                                         }
                                                     }
                                                     break;
                                                 case EBML_ID_CUETIME:
                                                     $cuepoint_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
                                                     break;
                                                 default:
                                                     $this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement);
                                             }
                                         }
                                         $cues_entry[] = $cuepoint_entry;
                                         break;
                                     default:
                                         $this->unhandledElement('cues', __LINE__, $subelement);
                                 }
                             }
                             $info['matroska']['cues'] = $cues_entry;
                             break;
                         case EBML_ID_TAGS:
                             // Element containing elements specific to Tracks/Chapters.
                             $tags_entry = array();
                             while ($this->getEBMLelement($subelement, $element_data['end'], array(EBML_ID_TAG))) {
                                 $tag_entry = array();
                                 switch ($subelement['id']) {
                                     case EBML_ID_WRITINGAPP:
                                         $tag_entry[$subelement['id_name']] = $subelement['data'];
                                         break;
                                     case EBML_ID_TAG:
                                         while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_TARGETS, EBML_ID_SIMPLETAG))) {
                                             switch ($sub_subelement['id']) {
                                                 case EBML_ID_TARGETS:
                                                     $targets_entry = array();
                                                     while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
                                                         switch ($sub_sub_subelement['id']) {
                                                             case EBML_ID_TARGETTYPEVALUE:
                                                                 $targets_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
                                                                 $targets_entry[strtolower($sub_sub_subelement['id_name']) . '_long'] = $this->MatroskaTargetTypeValue($targets_entry[$sub_sub_subelement['id_name']]);
                                                                 break;
                                                             case EBML_ID_EDITIONUID:
                                                             case EBML_ID_CHAPTERUID:
                                                             case EBML_ID_ATTACHMENTUID:
                                                             case EBML_ID_TAGTRACKUID:
                                                             case EBML_ID_TAGCHAPTERUID:
                                                                 $targets_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
                                                                 break;
                                                             default:
                                                                 $this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement);
                                                         }
                                                     }
                                                     $tag_entry[$sub_subelement['id_name']][] = $targets_entry;
                                                     break;
                                                 case EBML_ID_SIMPLETAG:
                                                     $tag_entry[$sub_subelement['id_name']][] = $this->HandleEMBLSimpleTag($sub_subelement['end']);
                                                     break;
                                                 case EBML_ID_TARGETTYPE:
                                                     $tag_entry[$sub_subelement['id_name']] = $sub_subelement['data'];
                                                     break;
                                                 case EBML_ID_TRACKUID:
                                                     $tag_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
                                                     break;
                                                 default:
                                                     $this->unhandledElement('tags.tag', __LINE__, $sub_subelement);
                                             }
                                         }
                                         break;
                                     default:
                                         $this->unhandledElement('tags', __LINE__, $subelement);
                                 }
                                 $tags_entry['tags'][] = $tag_entry;
                             }
                             $info['matroska']['tags'] = $tags_entry['tags'];
                             break;
                         case EBML_ID_ATTACHMENTS:
                             // Contain attached files.
                             while ($this->getEBMLelement($subelement, $element_data['end'])) {
                                 switch ($subelement['id']) {
                                     case EBML_ID_ATTACHEDFILE:
                                         $attachedfile_entry = array();
                                         while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_FILEDATA))) {
                                             switch ($sub_subelement['id']) {
                                                 case EBML_ID_FILEDESCRIPTION:
                                                 case EBML_ID_FILENAME:
                                                 case EBML_ID_FILEMIMETYPE:
                                                     $attachedfile_entry[$sub_subelement['id_name']] = $sub_subelement['data'];
                                                     break;
                                                 case EBML_ID_FILEDATA:
                                                     $attachedfile_entry['data_offset'] = $this->current_offset;
                                                     $attachedfile_entry['data_length'] = $sub_subelement['length'];
                                                     $this->getid3->saveAttachment($attachedfile_entry[$sub_subelement['id_name']], $attachedfile_entry[$this->EBMLidName(EBML_ID_FILENAME)], $attachedfile_entry['data_offset'], $attachedfile_entry['data_length']);
                                                     if (@$attachedfile_entry[$sub_subelement['id_name']] && is_file($attachedfile_entry[$sub_subelement['id_name']])) {
                                                         $attachedfile_entry[$sub_subelement['id_name'] . '_filename'] = $attachedfile_entry[$sub_subelement['id_name']];
                                                         unset($attachedfile_entry[$sub_subelement['id_name']]);
                                                     }
                                                     $this->current_offset = $sub_subelement['end'];
                                                     break;
                                                 case EBML_ID_FILEUID:
                                                     $attachedfile_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
                                                     break;
                                                 default:
                                                     $this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement);
                                             }
                                         }
                                         if (!empty($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)]) && !empty($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)]) && preg_match('#^image/#i', $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)])) {
                                             if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_INLINE) {
                                                 $attachedfile_entry['data'] = $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)];
                                                 $attachedfile_entry['image_mime'] = $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)];
                                                 $info['matroska']['comments']['picture'][] = array('data' => $attachedfile_entry['data'], 'image_mime' => $attachedfile_entry['image_mime'], 'filename' => !empty($attachedfile_entry[$this->EBMLidName(EBML_ID_FILENAME)]) ? $attachedfile_entry[$this->EBMLidName(EBML_ID_FILENAME)] : '');
                                                 unset($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)], $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)]);
                                             }
                                         }
                                         if (!empty($attachedfile_entry['image_mime']) && preg_match('#^image/#i', $attachedfile_entry['image_mime'])) {
                                             // don't add a second copy of attached images, which are grouped under the standard location [comments][picture]
                                         } else {
                                             $info['matroska']['attachments'][] = $attachedfile_entry;
                                         }
                                         break;
                                     default:
                                         $this->unhandledElement('attachments', __LINE__, $subelement);
                                 }
                             }
                             break;
                         case EBML_ID_CHAPTERS:
                             while ($this->getEBMLelement($subelement, $element_data['end'])) {
                                 switch ($subelement['id']) {
                                     case EBML_ID_EDITIONENTRY:
                                         $editionentry_entry = array();
                                         while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CHAPTERATOM))) {
                                             switch ($sub_subelement['id']) {
                                                 case EBML_ID_EDITIONUID:
                                                     $editionentry_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
                                                     break;
                                                 case EBML_ID_EDITIONFLAGHIDDEN:
                                                 case EBML_ID_EDITIONFLAGDEFAULT:
                                                 case EBML_ID_EDITIONFLAGORDERED:
                                                     $editionentry_entry[$sub_subelement['id_name']] = (bool) getid3_lib::BigEndian2Int($sub_subelement['data']);
                                                     break;
                                                 case EBML_ID_CHAPTERATOM:
                                                     $chapteratom_entry = array();
                                                     while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CHAPTERTRACK, EBML_ID_CHAPTERDISPLAY))) {
                                                         switch ($sub_sub_subelement['id']) {
                                                             case EBML_ID_CHAPTERSEGMENTUID:
                                                             case EBML_ID_CHAPTERSEGMENTEDITIONUID:
                                                                 $chapteratom_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
                                                                 break;
                                                             case EBML_ID_CHAPTERFLAGENABLED:
                                                             case EBML_ID_CHAPTERFLAGHIDDEN:
                                                                 $chapteratom_entry[$sub_sub_subelement['id_name']] = (bool) getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
                                                                 break;
                                                             case EBML_ID_CHAPTERUID:
                                                             case EBML_ID_CHAPTERTIMESTART:
                                                             case EBML_ID_CHAPTERTIMEEND:
                                                                 $chapteratom_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
                                                                 break;
                                                             case EBML_ID_CHAPTERTRACK:
                                                                 $chaptertrack_entry = array();
                                                                 while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
                                                                     switch ($sub_sub_sub_subelement['id']) {
                                                                         case EBML_ID_CHAPTERTRACKNUMBER:
                                                                             $chaptertrack_entry[$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
                                                                             break;
                                                                         default:
                                                                             $this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement);
                                                                     }
                                                                 }
                                                                 $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chaptertrack_entry;
                                                                 break;
                                                             case EBML_ID_CHAPTERDISPLAY:
                                                                 $chapterdisplay_entry = array();
                                                                 while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
                                                                     switch ($sub_sub_sub_subelement['id']) {
                                                                         case EBML_ID_CHAPSTRING:
                                                                         case EBML_ID_CHAPLANGUAGE:
                                                                         case EBML_ID_CHAPCOUNTRY:
                                                                             $chapterdisplay_entry[$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
                                                                             break;
                                                                         default:
                                                                             $this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement);
                                                                     }
                                                                 }
                                                                 $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chapterdisplay_entry;
                                                                 break;
                                                             default:
                                                                 $this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement);
                                                         }
                                                     }
                                                     $editionentry_entry[$sub_subelement['id_name']][] = $chapteratom_entry;
                                                     break;
                                                 default:
                                                     $this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement);
                                             }
                                         }
                                         $info['matroska']['chapters'][] = $editionentry_entry;
                                         break;
                                     default:
                                         $this->unhandledElement('chapters', __LINE__, $subelement);
                                 }
                             }
                             break;
                         case EBML_ID_VOID:
                             // padding, ignore
                             $void_entry = array();
                             // TODO: do we really need to collect void's?
                             $void_entry['offset'] = $this->current_offset;
                             $info['matroska']['void'][] = $void_entry;
                             $this->current_offset = $element_data['end'];
                             break;
                         case EBML_ID_CLUSTER:
                             // The lower level element containing the (monolithic) Block structure.
                             $cluster_entry = array();
                             while ($this->getEBMLelement($subelement, $element_data['end'], array(EBML_ID_CLUSTERSILENTTRACKS, EBML_ID_CLUSTERBLOCKGROUP, EBML_ID_CLUSTERSIMPLEBLOCK))) {
                                 switch ($subelement['id']) {
                                     case EBML_ID_CLUSTERTIMECODE:
                                     case EBML_ID_CLUSTERPOSITION:
                                     case EBML_ID_CLUSTERPREVSIZE:
                                         $cluster_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
                                         break;
                                     case EBML_ID_CLUSTERSILENTTRACKS:
                                         $cluster_silent_tracks = array();
                                         while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
                                             switch ($sub_subelement['id']) {
                                                 case EBML_ID_CLUSTERSILENTTRACKNUMBER:
                                                     $cluster_silent_tracks[] = getid3_lib::BigEndian2Int($sub_subelement['data']);
                                                     break;
                                                 default:
                                                     $this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement);
                                             }
                                         }
                                         $cluster_entry[$subelement['id_name']][] = $cluster_silent_tracks;
                                         break;
                                     case EBML_ID_CLUSTERBLOCKGROUP:
                                         $cluster_block_group = array('offset' => $this->current_offset);
                                         while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CLUSTERBLOCK))) {
                                             switch ($sub_subelement['id']) {
                                                 case EBML_ID_CLUSTERBLOCK:
                                                     $cluster_block_group[$sub_subelement['id_name']] = $this->HandleEMBLClusterBlock($sub_subelement, EBML_ID_CLUSTERBLOCK, $info);
                                                     break;
                                                 case EBML_ID_CLUSTERREFERENCEPRIORITY:
                                                     // unsigned-int
                                                 // unsigned-int
                                                 case EBML_ID_CLUSTERBLOCKDURATION:
                                                     // unsigned-int
                                                     $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
                                                     break;
                                                 case EBML_ID_CLUSTERREFERENCEBLOCK:
                                                     // signed-int
                                                     $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data'], false, true);
                                                     break;
                                                 default:
                                                     $this->unhandledElement('clusters.blockgroup', __LINE__, $sub_subelement);
                                             }
                                         }
                                         $cluster_entry[$subelement['id_name']][] = $cluster_block_group;
                                         break;
                                     case EBML_ID_CLUSTERSIMPLEBLOCK:
                                         $cluster_entry[$subelement['id_name']][] = $this->HandleEMBLClusterBlock($subelement, EBML_ID_CLUSTERSIMPLEBLOCK, $info);
                                         break;
                                     default:
                                         $this->unhandledElement('cluster', __LINE__, $subelement);
                                 }
                                 $this->current_offset = $subelement['end'];
                             }
                             if (!self::$hide_clusters) {
                                 $info['matroska']['cluster'][] = $cluster_entry;
                             }
                             // check to see if all the data we need exists already, if so, break out of the loop
                             if (!self::$parse_whole_file) {
                                 if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
                                     if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
                                         return;
                                     }
                                 }
                             }
                             break;
                         default:
                             $this->unhandledElement('segment', __LINE__, $element_data);
                     }
                 }
                 break;
             default:
                 $this->unhandledElement('root', __LINE__, $top_element);
         }
     }
 }