wp/wp-includes/ID3/module.audio-video.matroska.php
changeset 16 a86126ab1dd4
parent 7 cf61fcea0001
child 19 3d72ae0968f4
--- a/wp/wp-includes/ID3/module.audio-video.matroska.php	Tue Oct 22 16:11:46 2019 +0200
+++ b/wp/wp-includes/ID3/module.audio-video.matroska.php	Tue Dec 15 13:49:49 2020 +0100
@@ -1,11 +1,11 @@
 <?php
+
 /////////////////////////////////////////////////////////////////
 /// getID3() by James Heinrich <info@getid3.org>               //
-//  available at http://getid3.sourceforge.net                 //
-//            or http://www.getid3.org                         //
-//          also https://github.com/JamesHeinrich/getID3       //
-/////////////////////////////////////////////////////////////////
-// See readme.txt for more details                             //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
 /////////////////////////////////////////////////////////////////
 //                                                             //
 // module.audio-video.matriska.php                             //
@@ -14,6 +14,9 @@
 //                                                            ///
 /////////////////////////////////////////////////////////////////
 
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
 
 define('EBML_ID_CHAPTERS',                  0x0043A770); // [10][43][A7][70] -- A system to define basic menus and partition data. For more detailed information, look at the Chapters Explanation.
 define('EBML_ID_SEEKHEAD',                  0x014D9B74); // [11][4D][9B][74] -- Contains the position of other level 1 elements.
@@ -72,7 +75,7 @@
 define('EBML_ID_FILEDESCRIPTION',               0x067E); //         [46][7E] -- A human-friendly name for the attached file.
 define('EBML_ID_FILEUID',                       0x06AE); //         [46][AE] -- Unique ID representing the file, as random as possible.
 define('EBML_ID_CONTENTENCALGO',                0x07E1); //         [47][E1] -- The encryption algorithm used. The value '0' means that the contents have not been encrypted but only signed. Predefined values:
-define('EBML_ID_CONTENTENCKEYID',               0x07E2); //         [47][E2] -- For public key algorithms this is the ID of the public key the the data was encrypted with.
+define('EBML_ID_CONTENTENCKEYID',               0x07E2); //         [47][E2] -- For public key algorithms this is the ID of the public key the data was encrypted with.
 define('EBML_ID_CONTENTSIGNATURE',              0x07E3); //         [47][E3] -- A cryptographic signature of the contents.
 define('EBML_ID_CONTENTSIGKEYID',               0x07E4); //         [47][E4] -- This is the ID of the private key the data was signed with.
 define('EBML_ID_CONTENTSIGALGO',                0x07E5); //         [47][E5] -- The algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values:
@@ -215,17 +218,33 @@
 */
 class getid3_matroska extends getid3_handler
 {
-	// public options
-	public static $hide_clusters    = true;  // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful [default: TRUE]
-	public static $parse_whole_file = false; // true to parse the whole file, not only header [default: FALSE]
+	/**
+	 * If true, do not return information about CLUSTER chunks, since there's a lot of them
+	 * and they're not usually useful [default: TRUE].
+	 *
+	 * @var bool
+	 */
+	public static $hide_clusters    = true;
 
-	// private parser settings/placeholders
+	/**
+	 * True to parse the whole file, not only header [default: FALSE].
+	 *
+	 * @var bool
+	 */
+	public static $parse_whole_file = false;
+
+	/*
+	 * Private parser settings/placeholders.
+	 */
 	private $EBMLbuffer        = '';
 	private $EBMLbuffer_offset = 0;
 	private $EBMLbuffer_length = 0;
 	private $current_offset    = 0;
 	private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID);
 
+	/**
+	 * @return bool
+	 */
 	public function Analyze()
 	{
 		$info = &$this->getid3->info;
@@ -313,7 +332,7 @@
 								break;*/
 						}
 
-						$info['video']['streams'][] = $track_info;
+						$info['video']['streams'][$trackarray['TrackUID']] = $track_info;
 						break;
 
 					case 2: // Audio
@@ -326,7 +345,7 @@
 						switch ($trackarray['CodecID']) {
 							case 'A_PCM/INT/LIT':
 							case 'A_PCM/INT/BIG':
-								$track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
+								$track_info['bitrate'] = $track_info['sample_rate'] * $track_info['channels'] * $trackarray['BitDepth'];
 								break;
 
 							case 'A_AC3':
@@ -346,7 +365,7 @@
 								// create temp instance
 								$getid3_temp = new getID3();
 								if ($track_info['dataformat'] != 'flac') {
-									$getid3_temp->openfile($this->getid3->filename);
+									$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
 								}
 								$getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
 								if ($track_info['dataformat'][0] == 'm' || $track_info['dataformat'] == 'flac') {
@@ -366,8 +385,8 @@
 								if (!empty($getid3_temp->info[$header_data_key])) {
 									$info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
 									if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
-										foreach ($getid3_temp->info['audio'] as $key => $value) {
-											$track_info[$key] = $value;
+										foreach ($getid3_temp->info['audio'] as $sub_key => $value) {
+											$track_info[$sub_key] = $value;
 										}
 									}
 								}
@@ -421,8 +440,8 @@
 								if (!empty($getid3_temp->info['ogg'])) {
 									$info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
 									if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
-										foreach ($getid3_temp->info['audio'] as $key => $value) {
-											$track_info[$key] = $value;
+										foreach ($getid3_temp->info['audio'] as $sub_key => $value) {
+											$track_info[$sub_key] = $value;
 										}
 									}
 								}
@@ -449,9 +468,9 @@
 								getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
 
 								$parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']);
-								foreach ($parsed as $key => $value) {
-									if ($key != 'raw') {
-										$track_info[$key] = $value;
+								foreach ($parsed as $sub_key => $value) {
+									if ($sub_key != 'raw') {
+										$track_info[$sub_key] = $value;
 									}
 								}
 								$info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
@@ -462,7 +481,7 @@
 								break;
 						}
 
-						$info['audio']['streams'][] = $track_info;
+						$info['audio']['streams'][$trackarray['TrackUID']] = $track_info;
 						break;
 				}
 			}
@@ -493,9 +512,36 @@
 			unset($info['mime_type']);
 		}
 
+		// use _STATISTICS_TAGS if available to set audio/video bitrates
+		if (!empty($info['matroska']['tags'])) {
+			$_STATISTICS_byTrackUID = array();
+			foreach ($info['matroska']['tags'] as $key1 => $value1) {
+				if (!empty($value1['Targets']['TagTrackUID'][0]) && !empty($value1['SimpleTag'])) {
+					foreach ($value1['SimpleTag'] as $key2 => $value2) {
+						if (!empty($value2['TagName']) && isset($value2['TagString'])) {
+							$_STATISTICS_byTrackUID[$value1['Targets']['TagTrackUID'][0]][$value2['TagName']] = $value2['TagString'];
+						}
+					}
+				}
+			}
+			foreach (array('audio','video') as $avtype) {
+				if (!empty($info[$avtype]['streams'])) {
+					foreach ($info[$avtype]['streams'] as $trackUID => $trackdata) {
+						if (!isset($trackdata['bitrate']) && !empty($_STATISTICS_byTrackUID[$trackUID]['BPS'])) {
+							$info[$avtype]['streams'][$trackUID]['bitrate'] = (int) $_STATISTICS_byTrackUID[$trackUID]['BPS'];
+							@$info[$avtype]['bitrate'] += $info[$avtype]['streams'][$trackUID]['bitrate'];
+						}
+					}
+				}
+			}
+		}
+
 		return true;
 	}
 
+	/**
+	 * @param array $info
+	 */
 	private function parseEBML(&$info) {
 		// http://www.matroska.org/technical/specs/index.html#EBMLBasics
 		$this->current_offset = $info['avdataoffset'];
@@ -595,8 +641,10 @@
 											while ($this->getEBMLelement($subelement, $track_entry['end'], array(EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS, EBML_ID_CODECPRIVATE))) {
 												switch ($subelement['id']) {
 
+													case EBML_ID_TRACKUID:
+														$track_entry[$subelement['id_name']] = getid3_lib::PrintHexBytes($subelement['data'], true, false);
+														break;
 													case EBML_ID_TRACKNUMBER:
-													case EBML_ID_TRACKUID:
 													case EBML_ID_TRACKTYPE:
 													case EBML_ID_MINCACHE:
 													case EBML_ID_MAXCACHE:
@@ -944,7 +992,7 @@
 																case EBML_ID_TAGEDITIONUID:
 																case EBML_ID_TAGCHAPTERUID:
 																case EBML_ID_TAGATTACHMENTUID:
-																	$targets_entry[$sub_sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+																	$targets_entry[$sub_sub_subelement['id_name']][] = getid3_lib::PrintHexBytes($sub_sub_subelement['data'], true, false);
 																	break;
 
 																default:
@@ -1228,6 +1276,11 @@
 		}
 	}
 
+	/**
+	 * @param int $min_data
+	 *
+	 * @return bool
+	 */
 	private function EnsureBufferHasEnoughData($min_data=1024) {
 		if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) {
 			$read_bytes = max($min_data, $this->getid3->fread_buffer_size());
@@ -1249,6 +1302,9 @@
 		return true;
 	}
 
+	/**
+	 * @return int|float|false
+	 */
 	private function readEBMLint() {
 		$actual_offset = $this->current_offset - $this->EBMLbuffer_offset;
 
@@ -1281,6 +1337,12 @@
 		return $int_value;
 	}
 
+	/**
+	 * @param int  $length
+	 * @param bool $check_buffer
+	 *
+	 * @return string|false
+	 */
 	private function readEBMLelementData($length, $check_buffer=false) {
 		if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) {
 			return false;
@@ -1290,6 +1352,13 @@
 		return $data;
 	}
 
+	/**
+	 * @param array      $element
+	 * @param int        $parent_end
+	 * @param array|bool $get_data
+	 *
+	 * @return bool
+	 */
 	private function getEBMLelement(&$element, $parent_end, $get_data=false) {
 		if ($this->current_offset >= $parent_end) {
 			return false;
@@ -1326,6 +1395,11 @@
 		return true;
 	}
 
+	/**
+	 * @param string $type
+	 * @param int    $line
+	 * @param array  $element
+	 */
 	private function unhandledElement($type, $line, $element) {
 		// warn only about unknown and missed elements, not about unuseful
 		if (!in_array($element['id'], $this->unuseful_elements)) {
@@ -1338,6 +1412,11 @@
 		}
 	}
 
+	/**
+	 * @param array $SimpleTagArray
+	 *
+	 * @return bool
+	 */
 	private function ExtractCommentsSimpleTag($SimpleTagArray) {
 		if (!empty($SimpleTagArray['SimpleTag'])) {
 			foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) {
@@ -1353,6 +1432,11 @@
 		return true;
 	}
 
+	/**
+	 * @param int $parent_end
+	 *
+	 * @return array
+	 */
 	private function HandleEMBLSimpleTag($parent_end) {
 		$simpletag_entry = array();
 
@@ -1383,6 +1467,13 @@
 		return $simpletag_entry;
 	}
 
+	/**
+	 * @param array $element
+	 * @param int   $block_type
+	 * @param array $info
+	 *
+	 * @return array
+	 */
 	private function HandleEMBLClusterBlock($element, $block_type, &$info) {
 		// http://www.matroska.org/technical/specs/index.html#block_structure
 		// http://www.matroska.org/technical/specs/index.html#simpleblock_structure
@@ -1446,6 +1537,11 @@
 		return $block_data;
 	}
 
+	/**
+	 * @param string $EBMLstring
+	 *
+	 * @return int|float|false
+	 */
 	private static function EBML2Int($EBMLstring) {
 		// http://matroska.org/specs/
 
@@ -1488,12 +1584,22 @@
 		return getid3_lib::BigEndian2Int($EBMLstring);
 	}
 
+	/**
+	 * @param int $EBMLdatestamp
+	 *
+	 * @return float
+	 */
 	private static function EBMLdate2unix($EBMLdatestamp) {
 		// Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC)
 		// 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC
 		return round(($EBMLdatestamp / 1000000000) + 978307200);
 	}
 
+	/**
+	 * @param int $target_type
+	 *
+	 * @return string|int
+	 */
 	public static function TargetTypeValue($target_type) {
 		// http://www.matroska.org/technical/specs/tagging/index.html
 		static $TargetTypeValue = array();
@@ -1509,6 +1615,11 @@
 		return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type);
 	}
 
+	/**
+	 * @param int $lacingtype
+	 *
+	 * @return string|int
+	 */
 	public static function BlockLacingType($lacingtype) {
 		// http://matroska.org/technical/specs/index.html#block_structure
 		static $BlockLacingType = array();
@@ -1521,6 +1632,11 @@
 		return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype);
 	}
 
+	/**
+	 * @param string $codecid
+	 *
+	 * @return string
+	 */
 	public static function CodecIDtoCommonName($codecid) {
 		// http://www.matroska.org/technical/specs/codecid/index.html
 		static $CodecIDlist = array();
@@ -1557,6 +1673,11 @@
 		return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid);
 	}
 
+	/**
+	 * @param int $value
+	 *
+	 * @return string
+	 */
 	private static function EBMLidName($value) {
 		static $EBMLidList = array();
 		if (empty($EBMLidList)) {
@@ -1755,6 +1876,11 @@
 		return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value));
 	}
 
+	/**
+	 * @param int $value
+	 *
+	 * @return string
+	 */
 	public static function displayUnit($value) {
 		// http://www.matroska.org/technical/specs/index.html#DisplayUnit
 		static $units = array(
@@ -1766,8 +1892,14 @@
 		return (isset($units[$value]) ? $units[$value] : 'unknown');
 	}
 
+	/**
+	 * @param array $streams
+	 *
+	 * @return array
+	 */
 	private static function getDefaultStreamInfo($streams)
 	{
+		$stream = array();
 		foreach (array_reverse($streams) as $stream) {
 			if ($stream['default']) {
 				break;