270 $info = &$this->getid3->info;
276 $info[
'error'][] =
'EBML parser: '.$e->getMessage();
280 if (isset(
$info[
'matroska'][
'info']) && is_array(
$info[
'matroska'][
'info'])) {
281 foreach (
$info[
'matroska'][
'info'] as $key => $infoarray) {
282 if (isset($infoarray[
'Duration'])) {
284 $info[
'playtime_seconds'] = $infoarray[
'Duration'] * ((isset($infoarray[
'TimecodeScale']) ? $infoarray[
'TimecodeScale'] : 1000000) / 1000000000);
291 if (isset(
$info[
'matroska'][
'tags']) && is_array(
$info[
'matroska'][
'tags'])) {
292 foreach (
$info[
'matroska'][
'tags'] as $key => $infoarray) {
298 if (isset(
$info[
'matroska'][
'tracks'][
'tracks']) && is_array(
$info[
'matroska'][
'tracks'][
'tracks'])) {
299 foreach (
$info[
'matroska'][
'tracks'][
'tracks'] as $key => $trackarray) {
301 $track_info = array();
303 $track_info[
'default'] = (isset($trackarray[
'FlagDefault']) ? $trackarray[
'FlagDefault'] :
true);
304 if (isset($trackarray[
'Name'])) { $track_info[
'name'] = $trackarray[
'Name']; }
306 switch ($trackarray[
'TrackType']) {
309 $track_info[
'resolution_x'] = $trackarray[
'PixelWidth'];
310 $track_info[
'resolution_y'] = $trackarray[
'PixelHeight'];
311 if (isset($trackarray[
'DisplayWidth'])) { $track_info[
'display_x'] = $trackarray[
'DisplayWidth']; }
312 if (isset($trackarray[
'DisplayHeight'])) { $track_info[
'display_y'] = $trackarray[
'DisplayHeight']; }
313 if (isset($trackarray[
'DefaultDuration'])) { $track_info[
'frame_rate'] = round(1000000000 / $trackarray[
'DefaultDuration'], 3); }
314 if (isset($trackarray[
'CodecName'])) { $track_info[
'codec'] = $trackarray[
'CodecName']; }
316 switch ($trackarray[
'CodecID']) {
317 case 'V_MS/VFW/FOURCC':
318 if (!class_exists(
'GetId3\Module\AudioVideo\Riff')) {
319 $this->getid3->warning(
'Unable to parse codec private data ['.basename(__FILE__).
':'.__LINE__.
'] because cannot include "' . str_replace(
'_', DIRECTORY_SEPARATOR,
'GetId3\Module\AudioVideo\Riff') .
'.php"');
324 $info[
'matroska'][
'track_codec_parsed'][$trackarray[
'TrackNumber']] = $parsed;
351 $info[
'video'][
'streams'][] = $track_info;
355 $track_info[
'sample_rate'] = (isset($trackarray[
'SamplingFrequency']) ? $trackarray[
'SamplingFrequency'] : 8000.0);
356 $track_info[
'channels'] = (isset($trackarray[
'Channels']) ? $trackarray[
'Channels'] : 1);
357 $track_info[
'language'] = (isset($trackarray[
'Language']) ? $trackarray[
'Language'] :
'eng');
358 if (isset($trackarray[
'BitDepth'])) { $track_info[
'bits_per_sample'] = $trackarray[
'BitDepth']; }
359 if (isset($trackarray[
'CodecName'])) { $track_info[
'codec'] = $trackarray[
'CodecName']; }
361 switch ($trackarray[
'CodecID']) {
362 case 'A_PCM/INT/LIT':
363 case 'A_PCM/INT/BIG':
364 $track_info[
'bitrate'] = $trackarray[
'SamplingFrequency'] * $trackarray[
'Channels'] * $trackarray[
'BitDepth'];
372 $class =
'GetId3\\Module\\Audio\\' . ucfirst($track_info[
'dataformat'] ==
'mp2' ?
'mp3' : $track_info[
'dataformat']);
373 if (!class_exists($class)) {
374 $this->getid3->warning(
'Unable to parse audio data ['.basename(__FILE__).
':'.__LINE__.
'] because cannot include "module.audio.'.$track_info[
'dataformat'].
'.php"');
378 if (!isset(
$info[
'matroska'][
'track_data_offsets'][$trackarray[
'TrackNumber']])) {
379 $this->getid3->warning(
'Unable to parse audio data ['.basename(__FILE__).
':'.__LINE__.
'] because $info[matroska][track_data_offsets]['.$trackarray[
'TrackNumber'].
'] not set');
385 if ($track_info[
'dataformat'] !=
'flac') {
386 $getid3_temp->openfile($this->getid3->filename);
388 $getid3_temp->info[
'avdataoffset'] =
$info[
'matroska'][
'track_data_offsets'][$trackarray[
'TrackNumber']][
'offset'];
389 if ($track_info[
'dataformat'][0] ==
'm' || $track_info[
'dataformat'] ==
'flac') {
390 $getid3_temp->info[
'avdataend'] =
$info[
'matroska'][
'track_data_offsets'][$trackarray[
'TrackNumber']][
'offset'] +
$info[
'matroska'][
'track_data_offsets'][$trackarray[
'TrackNumber']][
'length'];
394 $header_data_key = $track_info[
'dataformat'][0] ==
'm' ?
'mpeg' : $track_info[
'dataformat'];
395 $getid3_audio =
new $class($getid3_temp, __CLASS__);
396 if ($track_info[
'dataformat'] ==
'flac') {
397 $getid3_audio->AnalyzeString($trackarray[
'CodecPrivate']);
399 $getid3_audio->analyze();
401 if (!empty($getid3_temp->info[$header_data_key])) {
402 $info[
'matroska'][
'track_codec_parsed'][$trackarray[
'TrackNumber']] = $getid3_temp->info[$header_data_key];
403 if (isset($getid3_temp->info[
'audio']) && is_array($getid3_temp->info[
'audio'])) {
404 foreach ($getid3_temp->info[
'audio'] as $key => $value) {
405 $track_info[$key] = $value;
409 $this->getid3->warning(
'Unable to parse audio data ['.basename(__FILE__).
':'.__LINE__.
'] because '.$class.
'::Analyze() failed at offset '.$getid3_temp->info[
'avdataoffset']);
413 if (!empty($getid3_temp->info[
'error'])) {
414 foreach ($getid3_temp->info[
'error'] as $newerror) {
415 $this->getid3->warning($class.
'() says: ['.$newerror.
']');
418 if (!empty($getid3_temp->info[
'warning'])) {
419 foreach ($getid3_temp->info[
'warning'] as $newerror) {
420 if ($track_info[
'dataformat'] ==
'mp3' && preg_match(
'/^Probable truncated file: expecting \d+ bytes of audio data, only found \d+ \(short by \d+ bytes\)$/', $newerror)) {
424 $this->getid3->warning($class.
'() says: ['.$newerror.
']');
427 unset($getid3_temp, $getid3_audio);
431 case 'A_AAC/MPEG2/LC':
432 case 'A_AAC/MPEG4/LC':
433 case 'A_AAC/MPEG4/LC/SBR':
434 $this->getid3->warning($trackarray[
'CodecID'].
' audio data contains no header, audio/video bitrates can\'t be calculated');
438 if (!isset($trackarray[
'CodecPrivate'])) {
439 $this->getid3->warning(
'Unable to parse audio data ['.basename(__FILE__).
':'.__LINE__.
'] because CodecPrivate data not set');
442 $vorbis_offset = strpos($trackarray[
'CodecPrivate'],
'vorbis', 1);
443 if ($vorbis_offset ===
false) {
444 $this->getid3->warning(
'Unable to parse audio data ['.basename(__FILE__).
':'.__LINE__.
'] because CodecPrivate data does not contain "vorbis" keyword');
449 if (!class_exists(
'GetId3\\Module\\Audio\\Ogg')) {
450 $this->getid3->warning(
'Unable to parse audio data ['.basename(__FILE__).
':'.__LINE__.
'] because cannot include "GetId3\\Module\\Audio\\Ogg.php"');
458 $getid3_ogg =
new Ogg($getid3_temp);
459 $oggpageinfo[
'page_seqno'] = 0;
460 $getid3_ogg->ParseVorbisPageHeader($trackarray[
'CodecPrivate'], $vorbis_offset, $oggpageinfo);
461 if (!empty($getid3_temp->info[
'ogg'])) {
462 $info[
'matroska'][
'track_codec_parsed'][$trackarray[
'TrackNumber']] = $getid3_temp->info[
'ogg'];
463 if (isset($getid3_temp->info[
'audio']) && is_array($getid3_temp->info[
'audio'])) {
464 foreach ($getid3_temp->info[
'audio'] as $key => $value) {
465 $track_info[$key] = $value;
471 if (!empty($getid3_temp->info[
'error'])) {
472 foreach ($getid3_temp->info[
'error'] as $newerror) {
473 $this->getid3->warning(
'getid3_ogg() says: ['.$newerror.
']');
476 if (!empty($getid3_temp->info[
'warning'])) {
477 foreach ($getid3_temp->info[
'warning'] as $newerror) {
478 $this->getid3->warning(
'getid3_ogg() says: ['.$newerror.
']');
482 if (!empty($getid3_temp->info[
'ogg'][
'bitrate_nominal'])) {
483 $track_info[
'bitrate'] = $getid3_temp->info[
'ogg'][
'bitrate_nominal'];
485 unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset);
489 if (!class_exists(
'GetId3\Module\AudioVideo\Riff')) {
490 $this->getid3->warning(
'Unable to parse audio data ['.basename(__FILE__).
':'.__LINE__.
'] because cannot include "' . str_replace(
'_', DIRECTORY_SEPARATOR,
'GetId3\Module\AudioVideo\Riff') .
'.php"');
495 foreach ($parsed as $key => $value) {
497 $track_info[$key] = $value;
500 $info[
'matroska'][
'track_codec_parsed'][$trackarray[
'TrackNumber']] = $parsed;
504 $this->getid3->warning(
'Unhandled audio type "'.(isset($trackarray[
'CodecID']) ? $trackarray[
'CodecID'] :
'').
'"');
507 $info[
'audio'][
'streams'][] = $track_info;
512 if (!empty(
$info[
'video'][
'streams'])) {
515 if (!empty(
$info[
'audio'][
'streams'])) {
521 if (!empty(
$info[
'video'][
'streams'])) {
522 $info[
'mime_type'] = (
$info[
'matroska'][
'doctype'] ==
'webm' ?
'video/webm' :
'video/x-matroska');
523 } elseif (!empty(
$info[
'audio'][
'streams'])) {
524 $info[
'mime_type'] = (
$info[
'matroska'][
'doctype'] ==
'webm' ?
'audio/webm' :
'audio/x-matroska');
525 } elseif (isset(
$info[
'mime_type'])) {
526 unset(
$info[
'mime_type']);
542 $this->current_offset =
$info[
'avdataoffset'];
545 switch ($top_element[
'id']) {
548 $info[
'fileformat'] =
'matroska';
549 $info[
'matroska'][
'header'][
'offset'] = $top_element[
'offset'];
550 $info[
'matroska'][
'header'][
'length'] = $top_element[
'length'];
552 while ($this->
getEBMLelement($element_data, $top_element[
'end'],
true)) {
553 switch ($element_data[
'id']) {
566 $info[
'matroska'][
'doctype'] = $element_data[
'data'];
570 $this->current_offset = $element_data[
'end'];
571 unset($element_data);
577 if (!empty($element_data)) {
578 unset($element_data[
'offset'], $element_data[
'end']);
579 $info[
'matroska'][
'header'][
'elements'][] = $element_data;
585 $info[
'matroska'][
'segment'][0][
'offset'] = $top_element[
'offset'];
586 $info[
'matroska'][
'segment'][0][
'length'] = $top_element[
'length'];
588 while ($this->
getEBMLelement($element_data, $top_element[
'end'])) {
589 if ($element_data[
'id'] != self::EBML_ID_CLUSTER || !self::$hide_clusters) {
590 $info[
'matroska'][
'segments'][] = $element_data;
592 switch ($element_data[
'id']) {
596 while ($this->
getEBMLelement($seek_entry, $element_data[
'end'])) {
597 switch ($seek_entry[
'id']) {
600 while ($this->
getEBMLelement($sub_seek_entry, $seek_entry[
'end'],
true)) {
602 switch ($sub_seek_entry[
'id']) {
605 $seek_entry[
'target_id'] =
self::EBML2Int($sub_seek_entry[
'data']);
610 $seek_entry[
'target_offset'] = $element_data[
'offset'] +
Helper::BigEndian2Int($sub_seek_entry[
'data']);
617 if ($seek_entry[
'target_id'] != self::EBML_ID_CLUSTER || !self::$hide_clusters) {
618 $info[
'matroska'][
'seek'][] = $seek_entry;
629 $info[
'matroska'][
'tracks'] = $element_data;
631 while ($this->
getEBMLelement($track_entry, $element_data[
'end'])) {
632 switch ($track_entry[
'id']) {
636 while ($this->
getEBMLelement($subelement, $track_entry[
'end'], array(self::EBML_ID_VIDEO, self::EBML_ID_AUDIO, self::EBML_ID_CONTENTENCODINGS))) {
637 switch ($subelement[
'id']) {
661 $track_entry[$subelement[
'id_name']] = $subelement[
'data'];
674 while ($this->
getEBMLelement($sub_subelement, $subelement[
'end'],
true)) {
675 switch ($sub_subelement[
'id']) {
711 while ($this->
getEBMLelement($sub_subelement, $subelement[
'end'],
true)) {
712 switch ($sub_subelement[
'id']) {
736 while ($this->
getEBMLelement($sub_subelement, $subelement[
'end'])) {
737 switch ($sub_subelement[
'id']) {
741 while ($this->
getEBMLelement($sub_sub_subelement, $sub_subelement[
'end'], array(self::EBML_ID_CONTENTCOMPRESSION, self::EBML_ID_CONTENTENCRYPTION))) {
742 switch ($sub_sub_subelement[
'id']) {
747 $track_entry[$sub_subelement[
'id_name']][$sub_sub_subelement[
'id_name']] =
Helper::BigEndian2Int($sub_sub_subelement[
'data']);
752 while ($this->
getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement[
'end'],
true)) {
753 switch ($sub_sub_sub_subelement[
'id']) {
756 $track_entry[$sub_subelement[
'id_name']][$sub_sub_subelement[
'id_name']][$sub_sub_sub_subelement[
'id_name']] =
Helper::BigEndian2Int($sub_sub_sub_subelement[
'data']);
760 $track_entry[$sub_subelement[
'id_name']][$sub_sub_subelement[
'id_name']][$sub_sub_sub_subelement[
'id_name']] = $sub_sub_sub_subelement[
'data'];
764 $this->
unhandledElement(
'track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
771 while ($this->
getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement[
'end'],
true)) {
772 switch ($sub_sub_sub_subelement[
'id']) {
777 $track_entry[$sub_subelement[
'id_name']][$sub_sub_subelement[
'id_name']][$sub_sub_sub_subelement[
'id_name']] =
Helper::BigEndian2Int($sub_sub_sub_subelement[
'data']);
783 $track_entry[$sub_subelement[
'id_name']][$sub_sub_subelement[
'id_name']][$sub_sub_sub_subelement[
'id_name']] = $sub_sub_sub_subelement[
'data'];
787 $this->
unhandledElement(
'track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
793 $this->
unhandledElement(
'track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement);
799 $this->
unhandledElement(
'track.contentencodings', __LINE__, $sub_subelement);
809 $info[
'matroska'][
'tracks'][
'tracks'][] = $track_entry;
819 $info_entry = array();
821 while ($this->
getEBMLelement($subelement, $element_data[
'end'],
true)) {
822 switch ($subelement[
'id']) {
834 $info_entry[$subelement[
'id_name'].
'_unix'] =
self::EBMLdate2unix($info_entry[$subelement[
'id_name']]);
854 $info[
'matroska'][
'comments'][strtolower($subelement[
'id_name'])][] = $info_entry[$subelement[
'id_name']];
858 $chaptertranslate_entry = array();
860 while ($this->
getEBMLelement($sub_subelement, $subelement[
'end'],
true)) {
861 switch ($sub_subelement[
'id']) {
864 $chaptertranslate_entry[$sub_subelement[
'id_name']][] =
Helper::BigEndian2Int($sub_subelement[
'data']);
868 $chaptertranslate_entry[$sub_subelement[
'id_name']] =
Helper::BigEndian2Int($sub_subelement[
'data']);
872 $chaptertranslate_entry[$sub_subelement[
'id_name']] =
Helper::trimNullByte($sub_subelement[
'data']);
876 $this->
unhandledElement(
'info.chaptertranslate', __LINE__, $sub_subelement);
879 $info_entry[$subelement[
'id_name']] = $chaptertranslate_entry;
886 $info[
'matroska'][
'info'][] = $info_entry;
890 if (self::$hide_clusters) {
891 $this->current_offset = $element_data[
'end'];
894 $cues_entry = array();
896 while ($this->
getEBMLelement($subelement, $element_data[
'end'])) {
897 switch ($subelement[
'id']) {
900 $cuepoint_entry = array();
902 while ($this->
getEBMLelement($sub_subelement, $subelement[
'end'], array(self::EBML_ID_CUETRACKPOSITIONS))) {
903 switch ($sub_subelement[
'id']) {
906 $cuetrackpositions_entry = array();
908 while ($this->
getEBMLelement($sub_sub_subelement, $sub_subelement[
'end'],
true)) {
909 switch ($sub_sub_subelement[
'id']) {
915 $cuetrackpositions_entry[$sub_sub_subelement[
'id_name']] =
Helper::BigEndian2Int($sub_sub_subelement[
'data']);
919 $this->
unhandledElement(
'cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement);
922 $cuepoint_entry[$sub_subelement[
'id_name']][] = $cuetrackpositions_entry;
933 $cues_entry[] = $cuepoint_entry;
940 $info[
'matroska'][
'cues'] = $cues_entry;
944 $tags_entry = array();
946 while ($this->
getEBMLelement($subelement, $element_data[
'end'],
false)) {
947 switch ($subelement[
'id']) {
950 $tag_entry = array();
952 while ($this->
getEBMLelement($sub_subelement, $subelement[
'end'],
false)) {
953 switch ($sub_subelement[
'id']) {
956 $targets_entry = array();
958 while ($this->
getEBMLelement($sub_sub_subelement, $sub_subelement[
'end'],
true)) {
959 switch ($sub_sub_subelement[
'id']) {
963 $targets_entry[strtolower($sub_sub_subelement[
'id_name']).
'_long'] =
self::MatroskaTargetTypeValue($targets_entry[$sub_sub_subelement[
'id_name']]);
967 $targets_entry[$sub_sub_subelement[
'id_name']] = $sub_sub_subelement[
'data'];
974 $targets_entry[$sub_sub_subelement[
'id_name']][] =
Helper::BigEndian2Int($sub_sub_subelement[
'data']);
981 $tag_entry[$sub_subelement[
'id_name']] = $targets_entry;
985 $tag_entry[$sub_subelement[
'id_name']][] = $this->
HandleEMBLSimpleTag($sub_subelement[
'end']);
992 $tags_entry[] = $tag_entry;
999 $info[
'matroska'][
'tags'] = $tags_entry;
1004 while ($this->
getEBMLelement($subelement, $element_data[
'end'])) {
1005 switch ($subelement[
'id']) {
1008 $attachedfile_entry = array();
1010 while ($this->
getEBMLelement($sub_subelement, $subelement[
'end'], array(self::EBML_ID_FILEDATA))) {
1011 switch ($sub_subelement[
'id']) {
1016 $attachedfile_entry[$sub_subelement[
'id_name']] = $sub_subelement[
'data'];
1021 $attachedfile_entry[
'data_length'] = $sub_subelement[
'length'];
1024 $attachedfile_entry[$sub_subelement[
'id_name']],
1025 $attachedfile_entry[
'FileName'],
1026 $attachedfile_entry[
'data_offset'],
1027 $attachedfile_entry[
'data_length']);
1029 $this->current_offset = $sub_subelement[
'end'];
1037 $this->
unhandledElement(
'attachments.attachedfile', __LINE__, $sub_subelement);
1040 if (!empty($attachedfile_entry[
'FileData']) && !empty($attachedfile_entry[
'FileMimeType']) && preg_match(
'#^image/#i', $attachedfile_entry[
'FileMimeType'])) {
1042 $attachedfile_entry[
'data'] = $attachedfile_entry[
'FileData'];
1043 $attachedfile_entry[
'image_mime'] = $attachedfile_entry[
'FileMimeType'];
1044 $info[
'matroska'][
'comments'][
'picture'][] = array(
'data' => $attachedfile_entry[
'data'],
'image_mime' => $attachedfile_entry[
'image_mime'],
'filename' => $attachedfile_entry[
'FileName']);
1045 unset($attachedfile_entry[
'FileData'], $attachedfile_entry[
'FileMimeType']);
1048 if (!empty($attachedfile_entry[
'image_mime']) && preg_match(
'#^image/#i', $attachedfile_entry[
'image_mime'])) {
1051 $info[
'matroska'][
'attachments'][] = $attachedfile_entry;
1063 while ($this->
getEBMLelement($subelement, $element_data[
'end'])) {
1064 switch ($subelement[
'id']) {
1067 $editionentry_entry = array();
1069 while ($this->
getEBMLelement($sub_subelement, $subelement[
'end'], array(self::EBML_ID_CHAPTERATOM))) {
1070 switch ($sub_subelement[
'id']) {
1079 $editionentry_entry[$sub_subelement[
'id_name']] = (bool)
Helper::BigEndian2Int($sub_subelement[
'data']);
1083 $chapteratom_entry = array();
1085 while ($this->
getEBMLelement($sub_sub_subelement, $sub_subelement[
'end'], array(self::EBML_ID_CHAPTERTRACK, self::EBML_ID_CHAPTERDISPLAY))) {
1086 switch ($sub_sub_subelement[
'id']) {
1090 $chapteratom_entry[$sub_sub_subelement[
'id_name']] = $sub_sub_subelement[
'data'];
1095 $chapteratom_entry[$sub_sub_subelement[
'id_name']] = (bool)
Helper::BigEndian2Int($sub_sub_subelement[
'data']);
1101 $chapteratom_entry[$sub_sub_subelement[
'id_name']] =
Helper::BigEndian2Int($sub_sub_subelement[
'data']);
1105 $chaptertrack_entry = array();
1107 while ($this->
getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement[
'end'],
true)) {
1108 switch ($sub_sub_sub_subelement[
'id']) {
1111 $chaptertrack_entry[$sub_sub_sub_subelement[
'id_name']] =
Helper::BigEndian2Int($sub_sub_sub_subelement[
'data']);
1115 $this->
unhandledElement(
'chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement);
1118 $chapteratom_entry[$sub_sub_subelement[
'id_name']][] = $chaptertrack_entry;
1122 $chapterdisplay_entry = array();
1124 while ($this->
getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement[
'end'],
true)) {
1125 switch ($sub_sub_sub_subelement[
'id']) {
1130 $chapterdisplay_entry[$sub_sub_sub_subelement[
'id_name']] = $sub_sub_sub_subelement[
'data'];
1134 $this->
unhandledElement(
'chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement);
1137 $chapteratom_entry[$sub_sub_subelement[
'id_name']][] = $chapterdisplay_entry;
1141 $this->
unhandledElement(
'chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement);
1144 $editionentry_entry[$sub_subelement[
'id_name']][] = $chapteratom_entry;
1148 $this->
unhandledElement(
'chapters.editionentry', __LINE__, $sub_subelement);
1151 $info[
'matroska'][
'chapters'][] = $editionentry_entry;
1161 $cluster_entry = array();
1163 while ($this->
getEBMLelement($subelement, $element_data[
'end'], array(self::EBML_ID_CLUSTERSILENTTRACKS, self::EBML_ID_CLUSTERBLOCKGROUP, self::EBML_ID_CLUSTERSIMPLEBLOCK))) {
1164 switch ($subelement[
'id']) {
1173 $cluster_silent_tracks = array();
1175 while ($this->
getEBMLelement($sub_subelement, $subelement[
'end'],
true)) {
1176 switch ($sub_subelement[
'id']) {
1183 $this->
unhandledElement(
'cluster.silenttracks', __LINE__, $sub_subelement);
1186 $cluster_entry[$subelement[
'id_name']][] = $cluster_silent_tracks;
1190 $cluster_block_group = array(
'offset' => $this->current_offset);
1192 while ($this->
getEBMLelement($sub_subelement, $subelement[
'end'], array(self::EBML_ID_CLUSTERBLOCK))) {
1193 switch ($sub_subelement[
'id']) {
1196 $cluster_block_group[$sub_subelement[
'id_name']] = $this->
HandleEMBLClusterBlock($sub_subelement, self::EBML_ID_CLUSTERBLOCK,
$info);
1205 $cluster_block_group[$sub_subelement[
'id_name']][] =
Helper::BigEndian2Int($sub_subelement[
'data'],
false,
true);
1209 $cluster_block_group[$sub_subelement[
'id_name']] =
Helper::trimNullByte($sub_subelement[
'data']);
1216 $cluster_entry[$subelement[
'id_name']][] = $cluster_block_group;
1226 $this->current_offset = $subelement[
'end'];
1228 if (!self::$hide_clusters) {
1229 $info[
'matroska'][
'cluster'][] = $cluster_entry;
1233 if (!self::$parse_whole_file) {
1234 if (isset(
$info[
'matroska'][
'info']) && is_array(
$info[
'matroska'][
'info'])) {
1235 if (isset(
$info[
'matroska'][
'tracks'][
'tracks']) && is_array(
$info[
'matroska'][
'tracks'][
'tracks'])) {
1236 if (count(
$info[
'matroska'][
'track_data_offsets']) == count(
$info[
'matroska'][
'tracks'][
'tracks'])) {
1263 if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) {
1266 $this->getid3->info[
'error'][] =
'EBML parser: cannot read past '.$this->current_offset;
1271 $this->
fseek($this->current_offset);
1273 $this->EBMLbuffer = $this->
fread(max($min_data, $this->getid3->fread_buffer_size()));
1274 $this->EBMLbuffer_length = strlen($this->EBMLbuffer);
1276 if ($this->EBMLbuffer_length == 0 && $this->
feof()) {
1277 $this->getid3->info[
'error'][] =
'EBML parser: ran out of file at offset '.$this->current_offset;
1296 $first_byte_int = ord($this->EBMLbuffer[$actual_offset]);
1297 if (0x80 & $first_byte_int) {
1299 } elseif (0x40 & $first_byte_int) {
1301 } elseif (0x20 & $first_byte_int) {
1303 } elseif (0x10 & $first_byte_int) {
1305 } elseif (0x08 & $first_byte_int) {
1307 } elseif (0x04 & $first_byte_int) {
1309 } elseif (0x02 & $first_byte_int) {
1311 } elseif (0x01 & $first_byte_int) {
1314 throw new DefaultException(
'invalid EBML integer (leading 0x00) at '.$this->current_offset);
1318 $int_value =
self::EBML2Int(substr($this->EBMLbuffer, $actual_offset, $length));
1319 $this->current_offset += $length;
1331 $data = substr($this->EBMLbuffer, $this->current_offset - $this->EBMLbuffer_offset, $length);
1332 $this->current_offset += $length;
1346 if ($this->current_offset >= $parent_end) {
1351 $this->current_offset = PHP_INT_MAX;
1371 $element[
'end'] = $this->current_offset + $element[
'length'];
1374 $dont_parse = (in_array($element[
'id'], $this->unuseful_elements) || $element[
'id_name'] == dechex($element[
'id']));
1375 if (($get_data ===
true || (is_array($get_data) && !in_array($element[
'id'], $get_data))) && !$dont_parse) {
1391 if (!in_array($element[
'id'], $this->unuseful_elements)) {
1392 $this->getid3->warning(
'Unhandled '.$type.
' element ['.basename(__FILE__).
':'.$line.
'] ('.$element[
'id'].
'::'.$element[
'id_name'].
' ['.$element[
'length'].
' bytes]) at '.$element[
'offset']);
1396 if (!isset($element[
'data'])) {
1397 $this->current_offset = $element[
'end'];
1408 if (!empty($SimpleTagArray[
'SimpleTag'])) {
1409 foreach ($SimpleTagArray[
'SimpleTag'] as $SimpleTagKey => $SimpleTagData) {
1410 if (!empty($SimpleTagData[
'TagName']) && !empty($SimpleTagData[
'TagString'])) {
1411 $this->getid3->info[
'matroska'][
'comments'][strtolower($SimpleTagData[
'TagName'])][] = $SimpleTagData[
'TagString'];
1413 if (!empty($SimpleTagData[
'SimpleTag'])) {
1429 $simpletag_entry = array();
1431 while ($this->
getEBMLelement($element, $parent_end, array(self::EBML_ID_SIMPLETAG))) {
1432 switch ($element[
'id']) {
1438 $simpletag_entry[$element[
'id_name']] = $element[
'data'];
1454 return $simpletag_entry;
1468 $block_data = array();
1469 $block_data[
'tracknumber'] = $this->
readEBMLint();
1473 if ($block_type == self::EBML_ID_CLUSTERSIMPLEBLOCK) {
1474 $block_data[
'flags'][
'keyframe'] = (($block_data[
'flags_raw'] & 0x80) >> 7);
1479 $block_data[
'flags'][
'invisible'] = (bool) (($block_data[
'flags_raw'] & 0x08) >> 3);
1480 $block_data[
'flags'][
'lacing'] = (($block_data[
'flags_raw'] & 0x06) >> 1);
1481 if ($block_type == self::EBML_ID_CLUSTERSIMPLEBLOCK) {
1482 $block_data[
'flags'][
'discardable'] = (($block_data[
'flags_raw'] & 0x01));
1489 if ($block_data[
'flags'][
'lacing'] > 0) {
1491 if ($block_data[
'flags'][
'lacing'] != 0x02) {
1492 for ($i = 1; $i < $block_data[
'lace_frames']; $i ++) {
1493 if ($block_data[
'flags'][
'lacing'] == 0x03) {
1494 $block_data[
'lace_frames_size'][$i] = $this->
readEBMLint();
1496 $block_data[
'lace_frames_size'][$i] = 0;
1499 $block_data[
'lace_frames_size'][$i] +=
$size;
1500 }
while (
$size == 255);
1503 if ($block_data[
'flags'][
'lacing'] == 0x01) {
1504 $block_data[
'lace_frames_size'][] = $element[
'end'] - $this->current_offset - array_sum($block_data[
'lace_frames_size']);
1509 if (!isset(
$info[
'matroska'][
'track_data_offsets'][$block_data[
'tracknumber']])) {
1518 $this->current_offset = $element[
'end'];
1548 $first_byte_int = ord($EBMLstring[0]);
1549 if (0x80 & $first_byte_int) {
1550 $EBMLstring[0] = chr($first_byte_int & 0x7F);
1551 } elseif (0x40 & $first_byte_int) {
1552 $EBMLstring[0] = chr($first_byte_int & 0x3F);
1553 } elseif (0x20 & $first_byte_int) {
1554 $EBMLstring[0] = chr($first_byte_int & 0x1F);
1555 } elseif (0x10 & $first_byte_int) {
1556 $EBMLstring[0] = chr($first_byte_int & 0x0F);
1557 } elseif (0x08 & $first_byte_int) {
1558 $EBMLstring[0] = chr($first_byte_int & 0x07);
1559 } elseif (0x04 & $first_byte_int) {
1560 $EBMLstring[0] = chr($first_byte_int & 0x03);
1561 } elseif (0x02 & $first_byte_int) {
1562 $EBMLstring[0] = chr($first_byte_int & 0x01);
1563 } elseif (0x01 & $first_byte_int) {
1564 $EBMLstring[0] = chr($first_byte_int & 0x00);
1579 return round(($EBMLdatestamp / 1000000000) + 978307200);
1591 static $MatroskaTargetTypeValue = array();
1592 if (empty($MatroskaTargetTypeValue)) {
1593 $MatroskaTargetTypeValue[10] =
'A: ~ V:shot';
1594 $MatroskaTargetTypeValue[20] =
'A:subtrack/part/movement ~ V:scene';
1595 $MatroskaTargetTypeValue[30] =
'A:track/song ~ V:chapter';
1596 $MatroskaTargetTypeValue[40] =
'A:part/session ~ V:part/session';
1597 $MatroskaTargetTypeValue[50] =
'A:album/opera/concert ~ V:movie/episode/concert';
1598 $MatroskaTargetTypeValue[60] =
'A:edition/issue/volume/opus ~ V:season/sequel/volume';
1599 $MatroskaTargetTypeValue[70] =
'A:collection ~ V:collection';
1614 static $MatroskaBlockLacingType = array();
1615 if (empty($MatroskaBlockLacingType)) {
1616 $MatroskaBlockLacingType[0x00] =
'no lacing';
1617 $MatroskaBlockLacingType[0x01] =
'Xiph lacing';
1618 $MatroskaBlockLacingType[0x02] =
'fixed-size lacing';
1619 $MatroskaBlockLacingType[0x03] =
'EBML lacing';
1622 return (isset($MatroskaBlockLacingType[$lacingtype]) ? $MatroskaBlockLacingType[$lacingtype] : $lacingtype);
1634 static $MatroskaCodecIDlist = array();
1635 if (empty($MatroskaCodecIDlist)) {
1636 $MatroskaCodecIDlist[
'A_AAC'] =
'aac';
1637 $MatroskaCodecIDlist[
'A_AAC/MPEG2/LC'] =
'aac';
1638 $MatroskaCodecIDlist[
'A_AC3'] =
'ac3';
1639 $MatroskaCodecIDlist[
'A_DTS'] =
'dts';
1640 $MatroskaCodecIDlist[
'A_FLAC'] =
'flac';
1641 $MatroskaCodecIDlist[
'A_MPEG/L1'] =
'mp1';
1642 $MatroskaCodecIDlist[
'A_MPEG/L2'] =
'mp2';
1643 $MatroskaCodecIDlist[
'A_MPEG/L3'] =
'mp3';
1644 $MatroskaCodecIDlist[
'A_PCM/INT/LIT'] =
'pcm';
1645 $MatroskaCodecIDlist[
'A_PCM/INT/BIG'] =
'pcm';
1646 $MatroskaCodecIDlist[
'A_QUICKTIME/QDMC'] =
'quicktime';
1647 $MatroskaCodecIDlist[
'A_QUICKTIME/QDM2'] =
'quicktime';
1648 $MatroskaCodecIDlist[
'A_VORBIS'] =
'vorbis';
1649 $MatroskaCodecIDlist[
'V_MPEG1'] =
'mpeg';
1650 $MatroskaCodecIDlist[
'V_THEORA'] =
'theora';
1651 $MatroskaCodecIDlist[
'V_REAL/RV40'] =
'real';
1652 $MatroskaCodecIDlist[
'V_REAL/RV10'] =
'real';
1653 $MatroskaCodecIDlist[
'V_REAL/RV20'] =
'real';
1654 $MatroskaCodecIDlist[
'V_REAL/RV30'] =
'real';
1655 $MatroskaCodecIDlist[
'V_QUICKTIME'] =
'quicktime';
1656 $MatroskaCodecIDlist[
'V_MPEG4/ISO/AP'] =
'mpeg4';
1657 $MatroskaCodecIDlist[
'V_MPEG4/ISO/ASP'] =
'mpeg4';
1658 $MatroskaCodecIDlist[
'V_MPEG4/ISO/AVC'] =
'h264';
1659 $MatroskaCodecIDlist[
'V_MPEG4/ISO/SP'] =
'mpeg4';
1660 $MatroskaCodecIDlist[
'V_VP8'] =
'vp8';
1661 $MatroskaCodecIDlist[
'V_MS/VFW/FOURCC'] =
'riff';
1662 $MatroskaCodecIDlist[
'A_MS/ACM'] =
'riff';
1665 return (isset($MatroskaCodecIDlist[$codecid]) ? $MatroskaCodecIDlist[$codecid] : $codecid);
1676 static $EBMLidList = array();
1677 if (empty($EBMLidList)) {
1869 return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value));
1874 foreach (array_reverse($streams) as $stream) {
1875 if ($stream[
'default']) {
1880 $unset = array(
'default',
'name');
1881 foreach ($unset as $u) {
1882 if (isset($stream[$u])) {
1888 $info[
'streams'] = $streams;
An exception for terminatinating execution or to throw for unit testing.
GetId3() by James Heinrich info@getid3.org //.
GetId3() by James Heinrich info@getid3.org //.
saveAttachment(&$ThisFileInfoIndex, $filename, $offset, $length)
fseek($bytes, $whence=SEEK_SET)
GetId3() by James Heinrich info@getid3.org //.
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
static intValueSupported($num)
@staticvar null $hasINT64
static trimNullByte($string)
static BigEndian2Float($byteword)
ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic.
GetId3() by James Heinrich info@getid3.org //.
const EBML_ID_PIXELHEIGHT
unhandledElement($type, $line, $element)
const EBML_ID_CHAPTERTRANSLATEID
const EBML_ID_EBMLMAXIDLENGTH
const EBML_ID_CHAPTERPHYSICALEQUIV
const EBML_ID_CLUSTERBLOCK
const EBML_ID_CHAPPROCESSCOMMAND
static EBMLdate2unix($EBMLdatestamp)
const EBML_ID_TRACKNUMBER
const EBML_ID_CLUSTERCODECSTATE
const EBML_ID_CHANNELPOSITIONS
const EBML_ID_CHAPTERTRACK
const EBML_ID_CHAPTERTRACKNUMBER
const EBML_ID_CLUSTERBLOCKVIRTUAL
const EBML_ID_CLUSTERREFERENCEVIRTUAL
const EBML_ID_CLUSTERBLOCKADDID
const EBML_ID_DISPLAYUNIT
const EBML_ID_CLUSTERPREVSIZE
const EBML_ID_CONTENTSIGHASHALGO
ExtractCommentsSimpleTag($SimpleTagArray)
const EBML_ID_CODECSETTINGS
const EBML_ID_CONTENTSIGNATURE
const EBML_ID_EDITIONENTRY
HandleEMBLClusterBlock($element, $block_type, &$info)
const EBML_ID_CLUSTERSILENTTRACKS
const EBML_ID_PIXELCROPBOTTOM
const EBML_ID_ATTACHEDFILE
const EBML_ID_PREVFILENAME
const EBML_ID_TRACKOFFSET
const EBML_ID_SEGMENTFAMILY
const EBML_ID_CUECLUSTERPOSITION
const EBML_ID_CLUSTERREFERENCEPRIORITY
const EBML_ID_CUEREFNUMBER
const EBML_ID_CHAPTERFLAGENABLED
const EBML_ID_NEXTFILENAME
const EBML_ID_FILEDESCRIPTION
const EBML_ID_TARGETTYPEVALUE
const EBML_ID_DOCTYPEREADVERSION
const EBML_ID_CHAPPROCESSCODECID
static MatroskaCodecIDtoCommonName($codecid)
@staticvar array $MatroskaCodecIDlist
const EBML_ID_CONTENTENCODINGSCOPE
const EBML_ID_CHAPTERSEGMENTUID
const EBML_ID_CUEREFCLUSTER
const EBML_ID_FILEMIMETYPE
const EBML_ID_CHAPPROCESSDATA
const EBML_ID_CHAPTERATOM
const EBML_ID_ASPECTRATIOTYPE
static EBMLidName($value)
@staticvar array $EBMLidList
const EBML_ID_TAGCHAPTERUID
const EBML_ID_PIXELCROPTOP
const EBML_ID_CHAPTERTIMEEND
const EBML_ID_CONTENTSIGALGO
const EBML_ID_CLUSTERLACENUMBER
const EBML_ID_EDITIONFLAGDEFAULT
const EBML_ID_CLUSTERTIMECODE
const EBML_ID_TRACKTRANSLATEEDITIONUID
const EBML_ID_EDITIONFLAGHIDDEN
const EBML_ID_DISPLAYHEIGHT
const EBML_ID_CONTENTCOMPALGO
const EBML_ID_CHAPTERFLAGHIDDEN
const EBML_ID_DOCTYPEVERSION
const EBML_ID_CLUSTERBLOCKGROUP
const EBML_ID_CLUSTERDELAY
const EBML_ID_ATTACHMENTLINK
const EBML_ID_TRACKTRANSLATECODEC
HandleEMBLSimpleTag($parent_end)
const EBML_ID_CLUSTERBLOCKADDITIONAL
static MatroskaBlockLacingType($lacingtype)
@staticvar array $MatroskaBlockLacingType
getEBMLelement(&$element, $parent_end, $get_data=false)
const EBML_ID_TAGLANGUAGE
const EBML_ID_PIXELCROPLEFT
readEBMLelementData($length)
const EBML_ID_CHAPPROCESS
const EBML_ID_TIMECODESCALE
const EBML_ID_CONTENTENCKEYID
const EBML_ID_CHAPTERTIMESTART
const EBML_ID_TRACKTIMECODESCALE
const EBML_ID_EBMLMAXSIZELENGTH
const EBML_ID_FLAGENABLED
const EBML_ID_CODECDOWNLOADURL
const EBML_ID_PIXELCROPRIGHT
const EBML_ID_CLUSTERTIMESLICE
const EBML_ID_CONTENTCOMPRESSION
const EBML_ID_SEGMENTFILENAME
const EBML_ID_CODECINFOURL
const EBML_ID_CHAPCOUNTRY
const EBML_ID_SAMPLINGFREQUENCY
const EBML_ID_CHAPTERTRANSLATE
const EBML_ID_DISPLAYWIDTH
const EBML_ID_TAGEDITIONUID
const EBML_ID_OUTPUTSAMPLINGFREQUENCY
const EBML_ID_CODECPRIVATE
const EBML_ID_CUECODECSTATE
const EBML_ID_COLOURSPACE
const EBML_ID_EBMLVERSION
const EBML_ID_FILEREFERRAL
static EBML2Int($EBMLstring)
const EBML_ID_CLUSTERREFERENCEBLOCK
const EBML_ID_CHAPTERSEGMENTEDITIONUID
const EBML_ID_FLAGDEFAULT
const EBML_ID_CLUSTERBLOCKADDITIONID
const EBML_ID_CLUSTERSIMPLEBLOCK
const EBML_ID_CHAPLANGUAGE
const EBML_ID_DEFAULTDURATION
const EBML_ID_CONTENTENCODINGTYPE
const EBML_ID_CLUSTERDURATION
const EBML_ID_CLUSTERSLICES
const EBML_ID_TRACKTRANSLATETRACKID
const EBML_ID_CLUSTERPOSITION
const EBML_ID_CHAPPROCESSPRIVATE
const EBML_ID_EDITIONFLAGORDERED
const EBML_ID_CONTENTSIGKEYID
const EBML_ID_SEEKPOSITION
const EBML_ID_TRACKTRANSLATE
const EBML_ID_CUEBLOCKNUMBER
const EBML_ID_MAXBLOCKADDITIONID
const EBML_ID_CHAPTERDISPLAY
const EBML_ID_CLUSTERFRAMENUMBER
EnsureBufferHasEnoughData($min_data=1024)
const EBML_ID_CONTENTENCODING
const EBML_ID_CLUSTERSILENTTRACKNUMBER
const EBML_ID_CUEREFCODECSTATE
const EBML_ID_CONTENTENCODINGS
const EBML_ID_CLUSTERBLOCKDURATION
const EBML_ID_CHAPTERTRANSLATECODEC
const EBML_ID_CHAPTERTRANSLATEEDITIONUID
const EBML_ID_FLAGINTERLACED
const EBML_ID_ATTACHMENTS
const EBML_ID_EBMLREADVERSION
const EBML_ID_CONTENTENCALGO
const EBML_ID_CHAPPROCESSTIME
const EBML_ID_CONTENTCOMPSETTINGS
const EBML_ID_CLUSTERENCRYPTEDBLOCK
static getDefaultStreamInfo($streams)
const EBML_ID_CONTENTENCODINGORDER
const EBML_ID_CUEREFERENCE
const EBML_ID_TRACKOVERLAY
const EBML_ID_CODECDECODEALL
const EBML_ID_TAGATTACHMENTUID
const EBML_ID_CONTENTENCRYPTION
const EBML_ID_CLUSTERBLOCKADDITIONS
const EBML_ID_CUETRACKPOSITIONS
const EBML_ID_CLUSTERBLOCKMORE
static MatroskaTargetTypeValue($target_type)
@staticvar array $MatroskaTargetTypeValue
const EBML_ID_TAGTRACKUID
static RIFFfourccLookup($fourcc)
static ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true)
static RIFFparseWAVEFORMATex($WaveFormatExData)
GetId3() by James Heinrich info@getid3.org //.