/** * * @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); } } }