wp/wp-includes/ID3/module.audio-video.riff.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
   212 						$this->warning('Audio codec = '.$thisfile_audio['codec']);
   212 						$this->warning('Audio codec = '.$thisfile_audio['codec']);
   213 					}
   213 					}
   214 					$thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
   214 					$thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
   215 
   215 
   216 					if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV)
   216 					if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV)
   217 						$info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
   217 						$info['playtime_seconds'] =  (float)getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $thisfile_audio['bitrate']);
   218 					}
   218 					}
   219 
   219 
   220 					$thisfile_audio['lossless'] = false;
   220 					$thisfile_audio['lossless'] = false;
   221 					if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
   221 					if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
   222 						switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
   222 						switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
   438 					// requires functions simplexml_load_string and get_object_vars
   438 					// requires functions simplexml_load_string and get_object_vars
   439 					if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) {
   439 					if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) {
   440 						$thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML;
   440 						$thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML;
   441 						if (isset($parsedXML['SPEED']['MASTER_SPEED'])) {
   441 						if (isset($parsedXML['SPEED']['MASTER_SPEED'])) {
   442 							@list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']);
   442 							@list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']);
   443 							$thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000);
   443 							$thisfile_riff_WAVE['iXML'][0]['master_speed'] = (int) $numerator / ($denominator ? $denominator : 1000);
   444 						}
   444 						}
   445 						if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) {
   445 						if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) {
   446 							@list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']);
   446 							@list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']);
   447 							$thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000);
   447 							$thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = (int) $numerator / ($denominator ? $denominator : 1000);
   448 						}
   448 						}
   449 						if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
   449 						if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
   450 							$samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
   450 							$samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
   451 							$timestamp_sample_rate = (is_array($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) ? max($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) : $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']); // XML could possibly contain more than one TIMESTAMP_SAMPLE_RATE tag, returning as array instead of integer [why? does it make sense? perhaps doesn't matter but getID3 needs to deal with it] - see https://github.com/JamesHeinrich/getID3/issues/105
   451 							$timestamp_sample_rate = (is_array($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) ? max($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) : $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']); // XML could possibly contain more than one TIMESTAMP_SAMPLE_RATE tag, returning as array instead of integer [why? does it make sense? perhaps doesn't matter but getID3 needs to deal with it] - see https://github.com/JamesHeinrich/getID3/issues/105
   452 							$thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate;
   452 							$thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate;
   519 					}
   519 					}
   520 				}
   520 				}
   521 
   521 
   522 				if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
   522 				if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
   523 					$thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
   523 					$thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
   524 					$info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
   524 					$info['playtime_seconds'] = (float)getid3_lib::SafeDiv((($info['avdataend'] - $info['avdataoffset']) * 8), $thisfile_audio['bitrate']);
   525 				}
   525 				}
   526 
   526 
   527 				if (!empty($info['wavpack'])) {
   527 				if (!empty($info['wavpack'])) {
   528 					$thisfile_audio_dataformat = 'wavpack';
   528 					$thisfile_audio_dataformat = 'wavpack';
   529 					$thisfile_audio['bitrate_mode'] = 'vbr';
   529 					$thisfile_audio['bitrate_mode'] = 'vbr';
   530 					$thisfile_audio['encoder']      = 'WavPack v'.$info['wavpack']['version'];
   530 					$thisfile_audio['encoder']      = 'WavPack v'.$info['wavpack']['version'];
   531 
   531 
   532 					// Reset to the way it was - RIFF parsing will have messed this up
   532 					// Reset to the way it was - RIFF parsing will have messed this up
   533 					$info['avdataend']        = $Original['avdataend'];
   533 					$info['avdataend']        = $Original['avdataend'];
   534 					$thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
   534 					$thisfile_audio['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']);
   535 
   535 
   536 					$this->fseek($info['avdataoffset'] - 44);
   536 					$this->fseek($info['avdataoffset'] - 44);
   537 					$RIFFdata = $this->fread(44);
   537 					$RIFFdata = $this->fread(44);
   538 					$OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata,  4, 4)) +  8;
   538 					$OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata,  4, 4)) +  8;
   539 					$OrignalRIFFdataSize   = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
   539 					$OrignalRIFFdataSize   = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
   630 						default:
   630 						default:
   631 							break;
   631 							break;
   632 					}
   632 					}
   633 				}
   633 				}
   634 				if ($info['avdataend'] > $info['filesize']) {
   634 				if ($info['avdataend'] > $info['filesize']) {
   635 					switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') {
   635 					switch ($thisfile_audio_dataformat) {
   636 						case 'wavpack': // WavPack
   636 						case 'wavpack': // WavPack
   637 						case 'lpac':    // LPAC
   637 						case 'lpac':    // LPAC
   638 						case 'ofr':     // OptimFROG
   638 						case 'ofr':     // OptimFROG
   639 						case 'ofs':     // OptimFROG DualStream
   639 						case 'ofs':     // OptimFROG DualStream
   640 							// lossless compressed audio formats that keep original RIFF headers - skip warning
   640 							// lossless compressed audio formats that keep original RIFF headers - skip warning
   670 					if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
   670 					if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
   671 						$info['avdataend']--;
   671 						$info['avdataend']--;
   672 						$this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
   672 						$this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
   673 					}
   673 					}
   674 				}
   674 				}
   675 				if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) {
   675 				if ($thisfile_audio_dataformat == 'ac3') {
   676 					unset($thisfile_audio['bits_per_sample']);
   676 					unset($thisfile_audio['bits_per_sample']);
   677 					if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) {
   677 					if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) {
   678 						$thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
   678 						$thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
   679 					}
   679 					}
   680 				}
   680 				}
   779 					// shortcut
   779 					// shortcut
   780 					$thisfile_riff_video[$streamindex] = array();
   780 					$thisfile_riff_video[$streamindex] = array();
   781 					/** @var array $thisfile_riff_video_current */
   781 					/** @var array $thisfile_riff_video_current */
   782 					$thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
   782 					$thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
   783 
   783 
   784 					if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
   784 					if ($thisfile_riff_raw_avih['dwWidth'] > 0) { // @phpstan-ignore-line
   785 						$thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
   785 						$thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
   786 						$thisfile_video['resolution_x']             = $thisfile_riff_video_current['frame_width'];
   786 						$thisfile_video['resolution_x']             = $thisfile_riff_video_current['frame_width'];
   787 					}
   787 					}
   788 					if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
   788 					if ($thisfile_riff_raw_avih['dwHeight'] > 0) { // @phpstan-ignore-line
   789 						$thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
   789 						$thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
   790 						$thisfile_video['resolution_y']              = $thisfile_riff_video_current['frame_height'];
   790 						$thisfile_video['resolution_y']              = $thisfile_riff_video_current['frame_height'];
   791 					}
   791 					}
   792 					if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
   792 					if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { // @phpstan-ignore-line
   793 						$thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
   793 						$thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
   794 						$thisfile_video['total_frames']              = $thisfile_riff_video_current['total_frames'];
   794 						$thisfile_video['total_frames']              = $thisfile_riff_video_current['total_frames'];
   795 					}
   795 					}
   796 
   796 
   797 					$thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
   797 					$thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
   806 								$strhfccType = substr($strhData,  0, 4);
   806 								$strhfccType = substr($strhData,  0, 4);
   807 
   807 
   808 								if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
   808 								if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
   809 									$strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
   809 									$strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
   810 
   810 
       
   811 									if (!isset($thisfile_riff_raw['strf'][$strhfccType][$streamindex])) {
       
   812 										$thisfile_riff_raw['strf'][$strhfccType][$streamindex] = null;
       
   813 									}
   811 									// shortcut
   814 									// shortcut
   812 									$thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
   815 									$thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
   813 
   816 
   814 									switch ($strhfccType) {
   817 									switch ($strhfccType) {
   815 										case 'auds':
   818 										case 'auds':
  1351 		}
  1354 		}
  1352 
  1355 
  1353 		if (!isset($info['playtime_seconds'])) {
  1356 		if (!isset($info['playtime_seconds'])) {
  1354 			$info['playtime_seconds'] = 0;
  1357 			$info['playtime_seconds'] = 0;
  1355 		}
  1358 		}
  1356 		if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
  1359 		if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { // @phpstan-ignore-line
  1357 			// needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
  1360 			// needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
  1358 			$info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
  1361 			$info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
  1359 		} elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
  1362 		} elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { // @phpstan-ignore-line
  1360 			$info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
  1363 			$info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
  1361 		}
  1364 		}
  1362 
  1365 
  1363 		if ($info['playtime_seconds'] > 0) {
  1366 		if ($info['playtime_seconds'] > 0) {
  1364 			if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
  1367 			if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
  1577 	 * @throws getid3_exception
  1580 	 * @throws getid3_exception
  1578 	 */
  1581 	 */
  1579 	public function ParseRIFF($startoffset, $maxoffset) {
  1582 	public function ParseRIFF($startoffset, $maxoffset) {
  1580 		$info = &$this->getid3->info;
  1583 		$info = &$this->getid3->info;
  1581 
  1584 
  1582 		$RIFFchunk = false;
  1585 		$RIFFchunk = array();
  1583 		$FoundAllChunksWeNeed = false;
  1586 		$FoundAllChunksWeNeed = false;
  1584 		$LISTchunkParent = null;
  1587 		$LISTchunkParent = null;
  1585 		$LISTchunkMaxOffset = null;
  1588 		$LISTchunkMaxOffset = null;
  1586 		$AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77"
  1589 		$AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77"
  1587 
  1590 
  1908 									unset($RIFFchunk[$chunkname][$thisindex]['offset']);
  1911 									unset($RIFFchunk[$chunkname][$thisindex]['offset']);
  1909 									unset($RIFFchunk[$chunkname][$thisindex]['size']);
  1912 									unset($RIFFchunk[$chunkname][$thisindex]['size']);
  1910 									if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
  1913 									if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
  1911 										unset($RIFFchunk[$chunkname][$thisindex]);
  1914 										unset($RIFFchunk[$chunkname][$thisindex]);
  1912 									}
  1915 									}
  1913 									if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) {
  1916 									if (count($RIFFchunk[$chunkname]) === 0) {
  1914 										unset($RIFFchunk[$chunkname]);
  1917 										unset($RIFFchunk[$chunkname]);
  1915 									}
  1918 									}
  1916 									$RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize);
  1919 									$RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize);
  1917 								} elseif ($chunksize < 2048) {
  1920 								} elseif ($chunksize < 2048) {
  1918 									// only read data in if smaller than 2kB
  1921 									// only read data in if smaller than 2kB
  1932 			} else {
  1935 			} else {
  1933 				throw $e;
  1936 				throw $e;
  1934 			}
  1937 			}
  1935 		}
  1938 		}
  1936 
  1939 
  1937 		return $RIFFchunk;
  1940 		return !empty($RIFFchunk) ? $RIFFchunk : false;
  1938 	}
  1941 	}
  1939 
  1942 
  1940 	/**
  1943 	/**
  1941 	 * @param string $RIFFdata
  1944 	 * @param string $RIFFdata
  1942 	 *
  1945 	 *
  2029 			'____'=>'comment',
  2032 			'____'=>'comment',
  2030 		);
  2033 		);
  2031 		foreach ($RIFFinfoKeyLookup as $key => $value) {
  2034 		foreach ($RIFFinfoKeyLookup as $key => $value) {
  2032 			if (isset($RIFFinfoArray[$key])) {
  2035 			if (isset($RIFFinfoArray[$key])) {
  2033 				foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) {
  2036 				foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) {
  2034 					if (trim($commentdata['data']) != '') {
  2037 					if (!empty($commentdata['data']) && trim($commentdata['data']) != '') {
  2035 						if (isset($CommentsTargetArray[$value])) {
  2038 						if (isset($CommentsTargetArray[$value])) {
  2036 							$CommentsTargetArray[$value][] =     trim($commentdata['data']);
  2039 							$CommentsTargetArray[$value][] =     trim($commentdata['data']);
  2037 						} else {
  2040 						} else {
  2038 							$CommentsTargetArray[$value] = array(trim($commentdata['data']));
  2041 							$CommentsTargetArray[$value] = array(trim($commentdata['data']));
  2039 						}
  2042 						}