public function ParseRIFF($startoffset, $maxoffset)
 {
     $info =& $this->getid3->info;
     $RIFFchunk = false;
     $FoundAllChunksWeNeed = false;
     try {
         $this->fseek($startoffset);
         $maxoffset = min($maxoffset, $info['avdataend']);
         while ($this->ftell() < $maxoffset) {
             $chunknamesize = $this->fread(8);
             //$chunkname =                          substr($chunknamesize, 0, 4);
             $chunkname = str_replace("", '_', substr($chunknamesize, 0, 4));
             // note: chunk names of 4 null bytes do appear to be legal (has been observed inside INFO and PRMI chunks, for example), but makes traversing array keys more difficult
             $chunksize = $this->EitherEndian2Int(substr($chunknamesize, 4, 4));
             //if (strlen(trim($chunkname, "\x00")) < 4) {
             if (strlen($chunkname) < 4) {
                 $this->error('Expecting chunk name at offset ' . ($this->ftell() - 8) . ' but found nothing. Aborting RIFF parsing.');
                 break;
             }
             if ($chunksize == 0 && $chunkname != 'JUNK') {
                 $this->warning('Chunk (' . $chunkname . ') size at offset ' . ($this->ftell() - 4) . ' is zero. Aborting RIFF parsing.');
                 break;
             }
             if ($chunksize % 2 != 0) {
                 // all structures are packed on word boundaries
                 $chunksize++;
             }
             switch ($chunkname) {
                 case 'LIST':
                     $listname = $this->fread(4);
                     if (preg_match('#^(movi|rec )$#i', $listname)) {
                         $RIFFchunk[$listname]['offset'] = $this->ftell() - 4;
                         $RIFFchunk[$listname]['size'] = $chunksize;
                         if (!$FoundAllChunksWeNeed) {
                             $WhereWeWere = $this->ftell();
                             $AudioChunkHeader = $this->fread(12);
                             $AudioChunkStreamNum = substr($AudioChunkHeader, 0, 2);
                             $AudioChunkStreamType = substr($AudioChunkHeader, 2, 2);
                             $AudioChunkSize = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4));
                             if ($AudioChunkStreamType == 'wb') {
                                 $FirstFourBytes = substr($AudioChunkHeader, 8, 4);
                                 if (preg_match('/^\\xFF[\\xE2-\\xE7\\xF2-\\xF7\\xFA-\\xFF][\\x00-\\xEB]/s', $FirstFourBytes)) {
                                     // MP3
                                     if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
                                         $getid3_temp = new getID3();
                                         $getid3_temp->openfile($this->getid3->filename);
                                         $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
                                         $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
                                         $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
                                         $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
                                         if (isset($getid3_temp->info['mpeg']['audio'])) {
                                             $info['mpeg']['audio'] = $getid3_temp->info['mpeg']['audio'];
                                             $info['audio'] = $getid3_temp->info['audio'];
                                             $info['audio']['dataformat'] = 'mp' . $info['mpeg']['audio']['layer'];
                                             $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
                                             $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
                                             $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
                                             $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
                                             //$info['bitrate']               = $info['audio']['bitrate'];
                                         }
                                         unset($getid3_temp, $getid3_mp3);
                                     }
                                 } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) {
                                     // AC3
                                     $getid3_temp = new getID3();
                                     $getid3_temp->openfile($this->getid3->filename);
                                     $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
                                     $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
                                     $getid3_ac3 = new getid3_ac3($getid3_temp);
                                     $getid3_ac3->Analyze();
                                     if (empty($getid3_temp->info['error'])) {
                                         $info['audio'] = $getid3_temp->info['audio'];
                                         $info['ac3'] = $getid3_temp->info['ac3'];
                                         if (!empty($getid3_temp->info['warning'])) {
                                             foreach ($getid3_temp->info['warning'] as $key => $value) {
                                                 $info['warning'][] = $value;
                                             }
                                         }
                                     }
                                     unset($getid3_temp, $getid3_ac3);
                                 }
                             }
                             $FoundAllChunksWeNeed = true;
                             $this->fseek($WhereWeWere);
                         }
                         $this->fseek($chunksize - 4, SEEK_CUR);
                     } else {
                         if (!isset($RIFFchunk[$listname])) {
                             $RIFFchunk[$listname] = array();
                         }
                         $LISTchunkParent = $listname;
                         $LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize;
                         if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) {
                             $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk);
                         }
                     }
                     break;
                 default:
                     if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) {
                         $this->fseek($chunksize, SEEK_CUR);
                         break;
                     }
                     $thisindex = 0;
                     if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) {
                         $thisindex = count($RIFFchunk[$chunkname]);
                     }
                     $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8;
                     $RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize;
                     switch ($chunkname) {
                         case 'data':
                             $info['avdataoffset'] = $this->ftell();
                             $info['avdataend'] = $info['avdataoffset'] + $chunksize;
                             $testData = $this->fread(36);
                             if ($testData === '') {
                                 break;
                             }
                             if (preg_match('/^\\xFF[\\xE2-\\xE7\\xF2-\\xF7\\xFA-\\xFF][\\x00-\\xEB]/s', substr($testData, 0, 4))) {
                                 // Probably is MP3 data
                                 if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
                                     $getid3_temp = new getID3();
                                     $getid3_temp->openfile($this->getid3->filename);
                                     $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
                                     $getid3_temp->info['avdataend'] = $info['avdataend'];
                                     $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
                                     $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
                                     if (empty($getid3_temp->info['error'])) {
                                         $info['audio'] = $getid3_temp->info['audio'];
                                         $info['mpeg'] = $getid3_temp->info['mpeg'];
                                     }
                                     unset($getid3_temp, $getid3_mp3);
                                 }
                             } elseif (($isRegularAC3 = substr($testData, 0, 2) == getid3_ac3::syncword) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) {
                                 // This is probably AC-3 data
                                 $getid3_temp = new getID3();
                                 if ($isRegularAC3) {
                                     $getid3_temp->openfile($this->getid3->filename);
                                     $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
                                     $getid3_temp->info['avdataend'] = $info['avdataend'];
                                 }
                                 $getid3_ac3 = new getid3_ac3($getid3_temp);
                                 if ($isRegularAC3) {
                                     $getid3_ac3->Analyze();
                                 } else {
                                     // Dolby Digital WAV
                                     // AC-3 content, but not encoded in same format as normal AC-3 file
                                     // For one thing, byte order is swapped
                                     $ac3_data = '';
                                     for ($i = 0; $i < 28; $i += 2) {
                                         $ac3_data .= substr($testData, 8 + $i + 1, 1);
                                         $ac3_data .= substr($testData, 8 + $i + 0, 1);
                                     }
                                     $getid3_ac3->AnalyzeString($ac3_data);
                                 }
                                 if (empty($getid3_temp->info['error'])) {
                                     $info['audio'] = $getid3_temp->info['audio'];
                                     $info['ac3'] = $getid3_temp->info['ac3'];
                                     if (!empty($getid3_temp->info['warning'])) {
                                         foreach ($getid3_temp->info['warning'] as $newerror) {
                                             $this->warning('getid3_ac3() says: [' . $newerror . ']');
                                         }
                                     }
                                 }
                                 unset($getid3_temp, $getid3_ac3);
                             } elseif (preg_match('/^(' . implode('|', array_map('preg_quote', getid3_dts::$syncwords)) . ')/', $testData)) {
                                 // This is probably DTS data
                                 $getid3_temp = new getID3();
                                 $getid3_temp->openfile($this->getid3->filename);
                                 $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
                                 $getid3_dts = new getid3_dts($getid3_temp);
                                 $getid3_dts->Analyze();
                                 if (empty($getid3_temp->info['error'])) {
                                     $info['audio'] = $getid3_temp->info['audio'];
                                     $info['dts'] = $getid3_temp->info['dts'];
                                     $info['playtime_seconds'] = $getid3_temp->info['playtime_seconds'];
                                     // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing
                                     if (!empty($getid3_temp->info['warning'])) {
                                         foreach ($getid3_temp->info['warning'] as $newerror) {
                                             $this->warning('getid3_dts() says: [' . $newerror . ']');
                                         }
                                     }
                                 }
                                 unset($getid3_temp, $getid3_dts);
                             } elseif (substr($testData, 0, 4) == 'wvpk') {
                                 // This is WavPack data
                                 $info['wavpack']['offset'] = $info['avdataoffset'];
                                 $info['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($testData, 4, 4));
                                 $this->parseWavPackHeader(substr($testData, 8, 28));
                             } else {
                                 // This is some other kind of data (quite possibly just PCM)
                                 // do nothing special, just skip it
                             }
                             $nextoffset = $info['avdataend'];
                             $this->fseek($nextoffset);
                             break;
                         case 'iXML':
                         case 'bext':
                         case 'cart':
                         case 'fmt ':
                         case 'strh':
                         case 'strf':
                         case 'indx':
                         case 'MEXT':
                         case 'DISP':
                             // always read data in
                         // always read data in
                         case 'JUNK':
                             // should be: never read data in
                             // but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc)
                             if ($chunksize < 1048576) {
                                 if ($chunksize > 0) {
                                     $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
                                     if ($chunkname == 'JUNK') {
                                         if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) {
                                             // only keep text characters [chr(32)-chr(127)]
                                             $info['riff']['comments']['junk'][] = trim($matches[1]);
                                         }
                                         // but if nothing there, ignore
                                         // remove the key in either case
                                         unset($RIFFchunk[$chunkname][$thisindex]['data']);
                                     }
                                 }
                             } else {
                                 $this->warning('Chunk "' . $chunkname . '" at offset ' . $this->ftell() . ' is unexpectedly larger than 1MB (claims to be ' . number_format($chunksize) . ' bytes), skipping data');
                                 $this->fseek($chunksize, SEEK_CUR);
                             }
                             break;
                             //case 'IDVX':
                             //	$info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
                             //	break;
                         //case 'IDVX':
                         //	$info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
                         //	break;
                         default:
                             if (!empty($LISTchunkParent) && $RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size'] <= $LISTchunkMaxOffset) {
                                 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
                                 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size'];
                                 unset($RIFFchunk[$chunkname][$thisindex]['offset']);
                                 unset($RIFFchunk[$chunkname][$thisindex]['size']);
                                 if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
                                     unset($RIFFchunk[$chunkname][$thisindex]);
                                 }
                                 if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) {
                                     unset($RIFFchunk[$chunkname]);
                                 }
                                 $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize);
                             } elseif ($chunksize < 2048) {
                                 // only read data in if smaller than 2kB
                                 $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
                             } else {
                                 $this->fseek($chunksize, SEEK_CUR);
                             }
                             break;
                     }
                     break;
             }
         }
     } catch (getid3_exception $e) {
         if ($e->getCode() == 10) {
             $this->warning('RIFF parser: ' . $e->getMessage());
         } else {
             throw $e;
         }
     }
     return $RIFFchunk;
 }
 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;
 }