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